173 lines
5.1 KiB
JavaScript
173 lines
5.1 KiB
JavaScript
import { getPool } from "../../../db/index.js";
|
|
import { createHash } from "crypto";
|
|
import { getConfig } from "../../../common/config.js";
|
|
import axios from "axios";
|
|
import sodium from "sodium-native";
|
|
|
|
async function getEntity(client, userId, shortName) {
|
|
const sql = `
|
|
SELECT
|
|
JSON_BUILD_OBJECT(
|
|
'fedidUrl', e.fedid_url,
|
|
'shortName', e.short_name,
|
|
'didId', e.did_id,
|
|
'controlPrivateKeyB64U', e.control_private_key_b64u,
|
|
'recoveryPrivateKeyB64U', e.recovery_private_key_b64u,
|
|
'didDoc', e.did_doc
|
|
) AS record
|
|
FROM entity e
|
|
WHERE LOWER(e.short_name) = LOWER($1)
|
|
AND e.user_id = $2;
|
|
`
|
|
const res = await client.query(sql, [
|
|
shortName,
|
|
userId,
|
|
]);
|
|
if (res.rows.length > 0 && res.rows[0].record) {
|
|
return res.rows[0].record;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
async function get(input, userId) {
|
|
let response = {
|
|
success: false,
|
|
error: 'Unknown error',
|
|
};
|
|
const client = await getPool();
|
|
try {
|
|
const existingEntity = await getEntity(client, userId, input.shortName)
|
|
if (!existingEntity) {
|
|
response.error = 'entity not found'
|
|
} else {
|
|
const data = {
|
|
didDoc: existingEntity.didDoc,
|
|
}
|
|
response = {
|
|
message: `retrieved: ${input.shortName}`,
|
|
data,
|
|
}
|
|
}
|
|
} catch(e) {
|
|
console.error(e)
|
|
} finally {
|
|
await client.release();
|
|
}
|
|
return response;
|
|
}
|
|
|
|
async function getDomains(input, userId) {
|
|
let response = {
|
|
success: false,
|
|
error: 'Unknown error',
|
|
};
|
|
try {
|
|
const config = getConfig();
|
|
const fedidUrl = input.fedidUrl ?? config.defaultFedidUrl;
|
|
const data = (await axios.get(
|
|
`${fedidUrl}/api/v2/domains`,
|
|
)).data.data.domains;
|
|
response = {
|
|
message: `retrieved domains`,
|
|
data,
|
|
}
|
|
} catch(e) {
|
|
console.error(e)
|
|
}
|
|
return response;
|
|
}
|
|
|
|
async function save(client, userId, entity) {
|
|
const res = await client.query(`
|
|
INSERT INTO entity (
|
|
user_id,
|
|
fedid_url,
|
|
short_name,
|
|
did_id,
|
|
control_private_key_b64u,
|
|
recovery_private_key_b64u,
|
|
did_doc
|
|
) VALUES (
|
|
$1,
|
|
$2,
|
|
$3,
|
|
$4,
|
|
$5,
|
|
$6,
|
|
$7
|
|
) RETURNING id;
|
|
`, [
|
|
userId,
|
|
entity.fedidUrl,
|
|
entity.shortName,
|
|
entity.didDoc.id,
|
|
entity.controlPrivateKeyB64U,
|
|
entity.recoveryPrivateKeyB64U,
|
|
entity.didDoc,
|
|
]);
|
|
}
|
|
|
|
async function create(input, userId) {
|
|
let response = {
|
|
success: false,
|
|
error: 'Unknown error',
|
|
};
|
|
const client = await getPool();
|
|
try {
|
|
const config = getConfig();
|
|
const fedidUrl = input.fedidUrl ?? config.defaultFedidUrl;
|
|
const domains = (await axios.get(
|
|
`${fedidUrl}/api/v2/domains`,
|
|
)).data.data.domains;
|
|
const shortName = input.shortName.split('@')
|
|
const domain = shortName[1]
|
|
if (!domains.includes(domain)) {
|
|
throw new Error('domain is not available');
|
|
}
|
|
const entity = {
|
|
shortName: input.shortName,
|
|
fedidUrl,
|
|
}
|
|
// Generate a control key
|
|
entity.controlPublicKey = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES);
|
|
entity.controlPrivateKey = Buffer.alloc(sodium.crypto_sign_SECRETKEYBYTES);
|
|
sodium.crypto_sign_keypair(entity.controlPublicKey, entity.controlPrivateKey);
|
|
entity.controlPublicKeyB64U = entity.controlPublicKey.toString("base64url");
|
|
entity.controlPrivateKeyB64U = entity.controlPrivateKey.toString("base64url");
|
|
// Generate a recovery key
|
|
entity.recoveryPublicKey = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES);
|
|
entity.recoveryPrivateKey = Buffer.alloc(sodium.crypto_sign_SECRETKEYBYTES);
|
|
entity.recoveryPrivateKeyB64U = entity.recoveryPrivateKey.toString("base64url");
|
|
sodium.crypto_sign_keypair(entity.recoveryPublicKey, entity.recoveryPrivateKey);
|
|
entity.recoveryHash = createHash("sha256").update(entity.recoveryPublicKey).digest("hex").slice(0, 48);
|
|
entity.didDoc = (await axios.post(
|
|
`${fedidUrl}/api/v2/did/create`,
|
|
{
|
|
shortName: entity.shortName,
|
|
control: entity.controlPublicKeyB64U,
|
|
recoveryHash: entity.recoveryHash,
|
|
},
|
|
)).data.data.didDoc;
|
|
await save(client, userId, entity);
|
|
response = {
|
|
message: `created and saved: ${entity.didDoc.id}`,
|
|
data: {
|
|
didDoc: entity.didDoc,
|
|
},
|
|
}
|
|
} catch(e) {
|
|
console.error(e);
|
|
response.error = e.message;
|
|
} finally {
|
|
await client.release();
|
|
}
|
|
return response;
|
|
}
|
|
|
|
export const entity = {
|
|
getEntity,
|
|
getDomains,
|
|
get,
|
|
create,
|
|
}
|