106 lines
3.3 KiB
JavaScript
106 lines
3.3 KiB
JavaScript
/// 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() });
|
|
});
|