Initial import of zappier-edge from zapier monorepo
This commit is contained in:
commit
7ca269eb99
130 changed files with 20843 additions and 0 deletions
89
src/verae-bind.ts
Normal file
89
src/verae-bind.ts
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/**
|
||||
* Bind a portal customer to a Verae central user id.
|
||||
* The public credential stays the zappier API key. The Verae JWT never leaves the server.
|
||||
*/
|
||||
import { createHash, randomBytes } from 'crypto';
|
||||
|
||||
export function normalizeVeraeUsername(username: string): string {
|
||||
return username.trim().toLowerCase();
|
||||
}
|
||||
|
||||
export function stableVeraeUserId(username: string): string {
|
||||
const n = normalizeVeraeUsername(username);
|
||||
return `vu_${createHash('sha256').update(n).digest('hex').slice(0, 16)}`;
|
||||
}
|
||||
|
||||
export type VeraeBind = {
|
||||
veraeUserId: string;
|
||||
veraeUsername: string;
|
||||
bound: boolean;
|
||||
};
|
||||
|
||||
function mockBind(email: string): VeraeBind {
|
||||
const veraeUsername = normalizeVeraeUsername(email);
|
||||
return { veraeUserId: stableVeraeUserId(veraeUsername), veraeUsername, bound: true };
|
||||
}
|
||||
|
||||
/**
|
||||
* Register or look up the customer on api.veraetime.net.
|
||||
* MOCK_VERAE (default) or missing VERAE_API_BASE_URL → stable id, no network.
|
||||
*/
|
||||
export async function bindVeraeUser(email: string, customerId?: string): Promise<VeraeBind> {
|
||||
const identity = (process.env.IDENTITY_URL || '').replace(/\/$/, '');
|
||||
if (identity) {
|
||||
try {
|
||||
const r = await fetch(`${identity}/bind`, {
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body: JSON.stringify({ email, customerId }),
|
||||
});
|
||||
if (r.ok) return (await r.json()) as VeraeBind;
|
||||
} catch {
|
||||
/* fall through */
|
||||
}
|
||||
}
|
||||
const mock = process.env.MOCK_VERAE !== 'false';
|
||||
const base = (process.env.VERAE_API_BASE_URL || '').replace(/\/$/, '');
|
||||
if (mock || !base) return mockBind(email);
|
||||
|
||||
const veraeUsername = normalizeVeraeUsername(email);
|
||||
const adminUser = process.env.VERAE_ADMIN_USER;
|
||||
const adminPass = process.env.VERAE_ADMIN_PASSWORD;
|
||||
const password = `vt_${randomBytes(18).toString('base64url')}`;
|
||||
|
||||
const login = async (username: string, pass: string) => {
|
||||
const r = await fetch(`${base}/auth/login`, {
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body: JSON.stringify({ username, password: pass }),
|
||||
});
|
||||
if (!r.ok) throw new Error(`verae login ${r.status}`);
|
||||
return r.json() as Promise<{ token: string; user?: { id?: string; username?: string } }>;
|
||||
};
|
||||
|
||||
if (!adminUser || !adminPass) return mockBind(email);
|
||||
|
||||
try {
|
||||
const admin = await login(adminUser, adminPass);
|
||||
const created = await fetch(`${base}/auth/users`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
authorization: `Bearer ${admin.token}`,
|
||||
},
|
||||
body: JSON.stringify({ username: veraeUsername, password, role: 'user' }),
|
||||
});
|
||||
if (!created.ok && created.status !== 409) {
|
||||
return mockBind(email);
|
||||
}
|
||||
const user = (await created.json().catch(() => ({}))) as { id?: string; username?: string };
|
||||
const id = user.id || (await login(veraeUsername, password)).user?.id;
|
||||
return {
|
||||
veraeUserId: id || stableVeraeUserId(veraeUsername),
|
||||
veraeUsername,
|
||||
bound: true,
|
||||
};
|
||||
} catch {
|
||||
return mockBind(email);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue