(Feat) Add google
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
/// Connexion native Google (Credential Manager) pour l'app cliente.
|
||||
///
|
||||
/// L'app obtient un « ID token » Google via le sélecteur de compte natif, puis
|
||||
/// l'envoie ici. On le vérifie auprès de Google, on retrouve (ou on crée) le
|
||||
/// compte `users`, on s'assure qu'une fiche fidélité `clients` existe (créée
|
||||
/// automatiquement à partir du nom/prénom Google), et on renvoie une session.
|
||||
///
|
||||
/// Endpoint : POST /api/google-native-auth body: { "idToken": "..." }
|
||||
/// Réponse : { "token": "<jwt pocketbase>", "record": { ...compte... } }
|
||||
routerAdd("POST", "/api/google-native-auth", (e) => {
|
||||
// ID client OAuth « Web » (celui passé comme serverClientId côté app).
|
||||
const WEB_CLIENT_ID =
|
||||
"831733439319-45cergb7cf8r728fja4m0kcvu2r7fbj9.apps.googleusercontent.com";
|
||||
|
||||
const body = new DynamicModel({ idToken: "" });
|
||||
e.bindBody(body);
|
||||
const idToken = (body.idToken || "").trim();
|
||||
if (!idToken) {
|
||||
throw new BadRequestError("idToken manquant");
|
||||
}
|
||||
|
||||
// Vérification de l'ID token auprès de Google (signature + expiration).
|
||||
const res = $http.send({
|
||||
url:
|
||||
"https://oauth2.googleapis.com/tokeninfo?id_token=" +
|
||||
encodeURIComponent(idToken),
|
||||
method: "GET",
|
||||
timeout: 15,
|
||||
});
|
||||
if (res.statusCode !== 200) {
|
||||
throw new BadRequestError("ID token Google invalide");
|
||||
}
|
||||
const p = res.json;
|
||||
|
||||
if (p.aud !== WEB_CLIENT_ID) {
|
||||
throw new BadRequestError("audience inattendue");
|
||||
}
|
||||
if (
|
||||
p.iss !== "accounts.google.com" &&
|
||||
p.iss !== "https://accounts.google.com"
|
||||
) {
|
||||
throw new BadRequestError("issuer inattendu");
|
||||
}
|
||||
const email = (p.email || "").toLowerCase();
|
||||
if (!email) {
|
||||
throw new BadRequestError("email absent du token");
|
||||
}
|
||||
if (String(p.email_verified) !== "true") {
|
||||
throw new BadRequestError("email Google non verifie");
|
||||
}
|
||||
|
||||
// Compte existant ?
|
||||
let user = null;
|
||||
try {
|
||||
user = $app.findFirstRecordByFilter("users", "email = {:email}", {
|
||||
email: email,
|
||||
});
|
||||
} catch (_) {
|
||||
user = null;
|
||||
}
|
||||
|
||||
// Sinon création d'un compte client (is_staff = false).
|
||||
if (!user) {
|
||||
const collection = $app.findCollectionByNameOrId("users");
|
||||
user = new Record(collection);
|
||||
user.set("email", email);
|
||||
user.set("emailVisibility", false);
|
||||
user.set("verified", true);
|
||||
user.set("name", p.name || "");
|
||||
user.set("is_staff", false);
|
||||
user.setPassword($security.randomString(30));
|
||||
$app.save(user);
|
||||
}
|
||||
|
||||
// Fiche fidélité déjà présente ? Sinon on la crée à partir du nom/prénom
|
||||
// Google → l'app cliente arrive directement sur sa carte (pas de saisie).
|
||||
let hasProfile = false;
|
||||
try {
|
||||
$app.findFirstRecordByFilter("clients", "user = {:uid}", { uid: user.id });
|
||||
hasProfile = true;
|
||||
} catch (_) {
|
||||
hasProfile = false;
|
||||
}
|
||||
if (!hasProfile) {
|
||||
const prenom = p.given_name || "";
|
||||
let nom = p.family_name || "";
|
||||
if (!nom) {
|
||||
nom = p.name || prenom || email.split("@")[0];
|
||||
}
|
||||
const code =
|
||||
"FID-" +
|
||||
$security.randomStringWithAlphabet(6, "ABCDEFGHJKLMNPQRSTUVWXYZ23456789");
|
||||
|
||||
const clientsCol = $app.findCollectionByNameOrId("clients");
|
||||
const client = new Record(clientsCol);
|
||||
client.set("user", user.id);
|
||||
client.set("nom", nom);
|
||||
client.set("prenom", prenom);
|
||||
client.set("code", code);
|
||||
$app.save(client);
|
||||
}
|
||||
|
||||
const token = user.newAuthToken();
|
||||
return e.json(200, { token: token, record: user.publicExport() });
|
||||
});
|
||||
Reference in New Issue
Block a user