import {
ALG,
base64decode,
getHeaders,
getSchema,
setRefresh,
setTokenSigningKey,
tryCompress
} from '/assets/{{ version }}/js/core.js';
async function hash(
domain,
account,
password,
mfa_code,
) {
const encoder = new TextEncoder();
const encoded_domain = encoder.encode(domain);
const encoded_account = encoder.encode(account);
const encoded_password = encoder.encode(password);
const all = new Uint8Array([...encoded_domain, ...encoded_account, ...encoded_password]);
const schema = await getSchema();
const alg = ALG[schema.auth.client_hash]
const password_hash = await crypto.subtle.digest(alg, all);
if (mfa_code) {
const encoded_mfa_code = encoder.encode(mfa_code);
const mfa_all = new Uint8Array([...encoded_domain, ...encoded_account, ...encoded_mfa_code]);
const mfa_hash = await crypto.subtle.digest(alg, mfa_all);
return [new Uint8Array(password_hash), new Uint8Array(mfa_hash)];
} else {
return new Uint8Array(password_hash);
}
}
export async function register(
account,
password,
domain,
invite_token = null,
) {
const schema = await getSchema();
if (schema.auth.invite && !invite_token) throw new Error('invite token must be included');
await __wbg_init();
const password_hash = await hash(domain, account, password);
const start_req = registration_start_req(
account,
password_hash,
);
const start_res = await fetch('/accounts/registration/start', {
method: 'POST',
body: start_req.request,
headers: {
...await getHeaders({cookies: false}),
...(invite_token ? {'authorization': invite_token} : {}),
},
});
const server_message = await start_res.bytes();
const finish_req = registration_finish_req(
account, password_hash, start_req.client_state, server_message
);
const finish_res = await fetch('/accounts/registration/finish', {
method: 'POST',
body: finish_req.request,
headers: await getHeaders({cookies: false}),
});
const encrypted_totp_mfa = await finish_res.bytes();
const decrypted = decrypt_totp_mfa(encrypted_totp_mfa, finish_req.private_key, domain, account);
const [recovery_codes_str, mfa_svg] = decrypted.split('__');
const recovery_codes = recovery_codes_str.match(/.{1,11}/g);
return [mfa_svg, recovery_codes];
}
export async function login(
account,
password,
mfa_code,
domain,
) {
await __wbg_init();
const [password_hash, mfa_hash] = await hash(domain, account, password, mfa_code);
const start_req = login_start_req(account, password_hash);
const start_res = await fetch('/accounts/login/start', {
method: 'POST',
body: start_req.request,
headers: await getHeaders({cookies: false}),
});
const server_message = await start_res.bytes();
const keypair = await crypto.subtle.generateKey({name: "Ed25519"}, true, ["sign", "verify"]);
const pubKeyBytes = new Uint8Array(
await crypto.subtle.exportKey("raw", keypair.publicKey),
);
const privKeyBytes = new Uint8Array(
await crypto.subtle.exportKey("pkcs8", keypair.privateKey),
);
setTokenSigningKey(privKeyBytes);
const finish_req = login_finish_req(
account, password_hash, mfa_hash, start_req.client_state, server_message, pubKeyBytes
);
const finish_res = await fetch('/accounts/login/finish', {
method: 'POST',
body: finish_req.request,
credentials: 'omit',
headers: await getHeaders({cookies: false}),
});
const encrypted_token = await finish_res.bytes();
const refresh_token = decrypt_token(encrypted_token, finish_req.session_key);
setRefresh(refresh_token);
}
export async function invoke(actionId, payload) {
await __wbg_init();
const schema = await getSchema();
for (let i = 0; i < schema.actions.length; i += 1) {
const action = schema.actions[i];
if ((action.name === actionId || action.idx === actionId) && action.triggered_by.includes("Ordinary")) {
const req = invoke_req(
JSON.stringify(payload),
JSON.stringify(action.accepts),
);
const send = await tryCompress(req, 'application/octet-stream');
const res = await fetch(`/action/invoke/${action.idx}`, {
method: 'POST',
body: send.body,
headers: {
...(await getHeaders({cookies: false, authorization: action.protected})),
...send.headers,
},
});
const res_bytes = await res.bytes();
const res_json = invoke_res(JSON.stringify(action.returns), res_bytes);
return JSON.parse(res_json);
}
}
}