@openinc/parse-server-opendash
Version:
Parse Server Cloud Code for open.INC Stack.
101 lines (100 loc) • 4.57 kB
JavaScript
;
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;
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");
}
// DEBUGGING: Decode token without verification to see what we're dealing with
console.log("=== DEBUGGING TOKEN ===");
try {
const tokenParts = token.split(".");
const payload = JSON.parse(Buffer.from(tokenParts[1], "base64").toString());
console.log("Token audience (aud):", payload.aud);
console.log("Token issuer (iss):", payload.iss);
console.log("Expected audience:", appId);
console.log("Expected issuer:", `https://login.microsoftonline.com/${tenantId}/v2.0`);
console.log("Audience match:", payload.aud === appId);
console.log("Issuer match:", payload.iss === `https://login.microsoftonline.com/${tenantId}/v2.0`);
}
catch (e) {
console.error("Failed to decode token:", e);
}
console.log("=== END DEBUGGING ===");
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);
});
});
const defaultTenant = await new Parse.Query(types_1.Tenant)
.ascending("createdAt")
.first({ useMasterKey: true });
let user = await new Parse.Query(Parse.User)
.equalTo("username", verifiedPayload.oid)
.first({ useMasterKey: true });
if (!user) {
user = new Parse.User();
user.set("username", verifiedPayload.oid);
user.set("email", account.username);
user.set("password", (0, crypto_1.randomBytes)(16).toString("hex"));
user.set("name", verifiedPayload.name || verifiedPayload.preferred_username);
user.set("tenant", defaultTenant);
user = await user.signUp(null, { useMasterKey: true });
return user.getSessionToken();
}
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");
});
}