UNPKG

@openinc/parse-server-opendash

Version:
102 lines (101 loc) 4.66 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.init = init; const crypto_1 = require("crypto"); const jsonwebtoken_1 = __importDefault(require("jsonwebtoken")); const jwks_rsa_1 = __importDefault(require("jwks-rsa")); const config_1 = require("../features/config"); const types_1 = require("../types"); const tenantId = config_1.ConfigInstance.getInstance().get("MICROSOFT_TENANT_ID") || process.env.MICROSOFT_TENANT_ID || process.env.OI_MICROSOFT_TENANT_ID; const appId = config_1.ConfigInstance.getInstance().get("MICROSOFT_APP_ID") || process.env.MICROSOFT_APP_ID || process.env.OI_MICROSOFT_APP_ID; // Simple, standard Microsoft v2.0 endpoint with app-specific parameter const client = (0, jwks_rsa_1.default)({ jwksUri: `https://login.microsoftonline.com/${tenantId}/discovery/keys?appid=${appId}`, cache: true, cacheMaxAge: 12 * 60 * 60 * 1000, // 12 hours timeout: 30000, }); function getKey(header, callback) { if (!header.kid) { return callback(new Error("No kid found in token header")); } client.getSigningKey(header.kid, (err, key) => { if (err) return callback(err); if (!key) return callback(new Error("Key not found")); callback(null, key.getPublicKey()); }); } async function init(name) { Parse.Cloud.define(name, async (request) => { const token = request.params.token; const account = request.params.account; console.log(JSON.stringify(request.params)); console.log("Account: ", JSON.stringify(account)); if (!token) { throw new Parse.Error(Parse.Error.INVALID_JSON, "Token missing"); } if (!tenantId || !appId) { throw new Parse.Error(Parse.Error.INVALID_JSON, "Microsoft authentication not properly configured"); } const verifiedPayload = await new Promise((resolve, reject) => { jsonwebtoken_1.default.verify(token, getKey, { audience: appId, issuer: `https://login.microsoftonline.com/${tenantId}/v2.0`, algorithms: ["RS256"], }, (err, decoded) => { if (err) { console.error("JWT verification failed:", err.message); return reject(err); } resolve(decoded); }); }); console.log("Payload: ", JSON.stringify(verifiedPayload)); const defaultTenant = await new Parse.Query(types_1.Tenant) .ascending("createdAt") .first({ useMasterKey: true }); let user = (await new Parse.Query(Parse.User) .equalTo("microsoftId", verifiedPayload.oid) .first({ useMasterKey: true })); // Legacy fallback: some older accounts might have been created using the oid as username. let oldUser = (await new Parse.Query(Parse.User) .equalTo("username", verifiedPayload.oid) .first({ useMasterKey: true })); if (!user && !oldUser) { user = new Parse.User(); user.set("password", (0, crypto_1.randomBytes)(16).toString("hex")); user.set("microsoftId", verifiedPayload.oid); user.set("name", verifiedPayload.name || verifiedPayload.preferred_username); user.set("tenant", defaultTenant); user = await user.signUp(null, { useMasterKey: true }); return user.getSessionToken(); } else if (!user && oldUser) { // Migrate legacy account that used the oid as username to a modern record keyed by microsoftId. user = oldUser; user.set("microsoftId", verifiedPayload.oid); user = await user.save(null, { useMasterKey: true }); } // Update user info on each login user.set("username", verifiedPayload.name ?? verifiedPayload.preferred_username ?? account.username); user.set("email", verifiedPayload.email ?? verifiedPayload.preferred_username); const sessionToken = "r:" + (0, crypto_1.randomBytes)(16).toString("hex"); const session = new Parse.Object("_Session"); session.set("user", user); session.set("sessionToken", sessionToken); session.set("expiresAt", new Date(Date.now() + 24 * 60 * 60 * 1000 * 7)); const savedSession = await session.save(null, { useMasterKey: true }); return savedSession.get("sessionToken"); }); }