import { action } from "../_generated/server"; import { v } from "convex/values"; import { internal } from "../_generated/api"; import { getAuthUserId } from "@convex-dev/auth/server"; import { activateSession, getSecondaryToken, getSessions, oauthToken, validateSession, } from "./client"; function randomUuid(): string { return crypto.randomUUID(); } export const start = action({ args: { zugangsnummer: v.string(), pin: v.string(), }, returns: v.object({ challengeType: v.string(), photoTanPngBase64: v.optional(v.string()), }), handler: async (ctx, args) => { const userId = await getAuthUserId(ctx); if (!userId) throw new Error("Nicht angemeldet"); const clientId = process.env.COMDIRECT_CLIENT_ID; const clientSecret = process.env.COMDIRECT_CLIENT_SECRET; if (!clientId || !clientSecret) { throw new Error("comdirect API-Zugangsdaten nicht konfiguriert"); } const sessionUuid = randomUuid(); const tokenResponse = await oauthToken( { grant_type: "password", username: args.zugangsnummer, password: args.pin, }, clientId, clientSecret, ); const sessions = await getSessions(tokenResponse.access_token, sessionUuid); const session = sessions[0]; if (!session) throw new Error("Keine comdirect-Session gefunden"); const challenge = await validateSession( tokenResponse.access_token, sessionUuid, session.identifier, ); await ctx.runMutation(internal.comdirect.internal.upsertSession, { userId, sessionUuid, identifier: session.identifier, accessToken: tokenResponse.access_token, refreshToken: tokenResponse.refresh_token, secondaryActive: false, challengeId: challenge.challengeId, challengeType: challenge.challengeType, status: "challenged", expiresAt: Date.now() + tokenResponse.expires_in * 1000, }); return { challengeType: challenge.challengeType, photoTanPngBase64: challenge.challengeType === "P_TAN" ? challenge.challenge : undefined, }; }, }); export const confirm = action({ args: { tan: v.optional(v.string()) }, returns: v.object({ success: v.boolean() }), handler: async (ctx, args) => { const userId = await getAuthUserId(ctx); if (!userId) throw new Error("Nicht angemeldet"); const clientId = process.env.COMDIRECT_CLIENT_ID; const clientSecret = process.env.COMDIRECT_CLIENT_SECRET; if (!clientId || !clientSecret) { throw new Error("comdirect API-Zugangsdaten nicht konfiguriert"); } const session = await ctx.runQuery(internal.comdirect.internal.getSession, { userId }); if (!session?.accessToken || !session.identifier || !session.challengeId) { throw new Error("Keine aktive comdirect-Session"); } await activateSession( session.accessToken, session.sessionUuid, session.identifier, session.challengeId, args.tan, ); const secondary = await getSecondaryToken(session.accessToken, clientId, clientSecret); await ctx.runMutation(internal.comdirect.internal.upsertSession, { userId, sessionUuid: session.sessionUuid, identifier: session.identifier, accessToken: secondary.access_token, refreshToken: secondary.refresh_token, secondaryActive: true, challengeId: session.challengeId, challengeType: session.challengeType, status: "active", }); return { success: true }; }, });