refactor(api): 🎨 Move createLocalUser to a static method of User

This commit is contained in:
Jesse Wierzbinski 2024-04-24 17:48:39 -10:00
parent 9d70778abd
commit 9e9998ea82
No known key found for this signature in database
7 changed files with 79 additions and 99 deletions

3
cli.ts
View file

@ -13,7 +13,6 @@ import extract from "extract-zip";
import { MediaBackend } from "media-manager";
import { lookup } from "mime-types";
import { getUrl } from "~database/entities/Attachment";
import { type UserType, createNewLocalUser } from "~database/entities/User";
import { client, db } from "~drizzle/db";
import { Emojis, Notes, OpenIdAccounts, Users } from "~drizzle/schema";
import { Note } from "~packages/database-interface/note";
@ -129,7 +128,7 @@ const cliBuilder = new CliBuilder([
}
// Create user
const newUser = await createNewLocalUser({
const newUser = await User.fromDataLocal({
email: email,
password: password,
username: username,

View file

@ -379,69 +379,6 @@ export const resolveWebFinger = async (
return User.resolve(relevantLink.href);
};
/**
* Fetches the list of followers associated with the actor and updates the user's followers
*/
export const fetchFollowers = () => {
//
};
/**
* Creates a new LOCAL user.
* @param data The data for the new user.
* @returns The newly created user.
*/
export const createNewLocalUser = async (data: {
username: string;
display_name?: string;
password: string;
email: string;
bio?: string;
avatar?: string;
header?: string;
admin?: boolean;
skipPasswordHash?: boolean;
}): Promise<User | null> => {
const keys = await generateUserKeys();
const newUser = (
await db
.insert(Users)
.values({
username: data.username,
displayName: data.display_name ?? data.username,
password: data.skipPasswordHash
? data.password
: await Bun.password.hash(data.password),
email: data.email,
note: data.bio ?? "",
avatar: data.avatar ?? config.defaults.avatar,
header: data.header ?? config.defaults.avatar,
isAdmin: data.admin ?? false,
publicKey: keys.public_key,
privateKey: keys.private_key,
updatedAt: new Date().toISOString(),
source: {
language: null,
note: "",
privacy: "public",
sensitive: false,
fields: [],
},
})
.returning()
)[0];
const finalUser = await User.fromId(newUser.id);
if (!finalUser) return null;
// Add to Meilisearch
await addUserToMeilisearch(finalUser);
return finalUser;
};
/**
* Parses mentions from a list of URIs
*/
@ -537,31 +474,6 @@ export const getRelationshipToOtherUser = async (
return foundRelationship;
};
/**
* Generates keys for the user.
*/
export const generateUserKeys = async () => {
const keys = await crypto.subtle.generateKey("Ed25519", true, [
"sign",
"verify",
]);
const privateKey = Buffer.from(
await crypto.subtle.exportKey("pkcs8", keys.privateKey),
).toString("base64");
const publicKey = Buffer.from(
await crypto.subtle.exportKey("spki", keys.publicKey),
).toString("base64");
// Add header, footer and newlines later on
// These keys are base64 encrypted
return {
private_key: privateKey,
public_key: publicKey,
};
};
export const followRequestToLysand = (
follower: User,
followee: User,

View file

@ -262,6 +262,79 @@ export class User {
return this.user.avatar;
}
static async generateKeys() {
const keys = await crypto.subtle.generateKey("Ed25519", true, [
"sign",
"verify",
]);
const privateKey = Buffer.from(
await crypto.subtle.exportKey("pkcs8", keys.privateKey),
).toString("base64");
const publicKey = Buffer.from(
await crypto.subtle.exportKey("spki", keys.publicKey),
).toString("base64");
// Add header, footer and newlines later on
// These keys are base64 encrypted
return {
private_key: privateKey,
public_key: publicKey,
};
}
static async fromDataLocal(data: {
username: string;
display_name?: string;
password: string;
email: string;
bio?: string;
avatar?: string;
header?: string;
admin?: boolean;
skipPasswordHash?: boolean;
}): Promise<User | null> {
const keys = await User.generateKeys();
const newUser = (
await db
.insert(Users)
.values({
username: data.username,
displayName: data.display_name ?? data.username,
password: data.skipPasswordHash
? data.password
: await Bun.password.hash(data.password),
email: data.email,
note: data.bio ?? "",
avatar: data.avatar ?? config.defaults.avatar,
header: data.header ?? config.defaults.avatar,
isAdmin: data.admin ?? false,
publicKey: keys.public_key,
privateKey: keys.private_key,
updatedAt: new Date().toISOString(),
source: {
language: null,
note: "",
privacy: "public",
sensitive: false,
fields: [],
},
})
.returning()
)[0];
const finalUser = await User.fromId(newUser.id);
if (!finalUser) return null;
// Add to Meilisearch
await addUserToMeilisearch(finalUser);
return finalUser;
}
/**
* Get the user's header in raw URL format
* @param config The config to use

View file

@ -15,7 +15,7 @@ export const meta = applyConfig({
route: "/api/v1/accounts/:id/followers",
auth: {
required: false,
oauthPermissions: [],
oauthPermissions: ["read:accounts"],
},
});
@ -36,7 +36,6 @@ export default apiRoute<typeof meta, typeof schema>(
return errorResponse("Invalid ID, must be of type UUIDv7", 404);
}
// TODO: Add pinned
const { max_id, min_id, since_id, limit } = extraData.parsedRequest;
const otherUser = await User.fromId(id);

View file

@ -15,7 +15,7 @@ export const meta = applyConfig({
route: "/api/v1/accounts/:id/following",
auth: {
required: false,
oauthPermissions: [],
oauthPermissions: ["read:accounts"],
},
});
@ -36,7 +36,6 @@ export default apiRoute<typeof meta, typeof schema>(
return errorResponse("Invalid ID, must be of type UUIDv7", 404);
}
// TODO: Add pinned
const { max_id, min_id, since_id, limit } = extraData.parsedRequest;
const otherUser = await User.fromId(id);

View file

@ -4,7 +4,6 @@ import { tempmailDomains } from "@tempmail";
import { eq } from "drizzle-orm";
import ISO6391 from "iso-639-1";
import { z } from "zod";
import { createNewLocalUser } from "~database/entities/User";
import { Users } from "~drizzle/schema";
import { User } from "~packages/database-interface/user";
@ -207,7 +206,7 @@ export default apiRoute<typeof meta, typeof schema>(
);
}
await createNewLocalUser({
await User.fromDataLocal({
username: body.username ?? "",
password: body.password ?? "",
email: body.email ?? "",

View file

@ -1,12 +1,11 @@
import { randomBytes } from "node:crypto";
import { asc, inArray, like } from "drizzle-orm";
import type { Status } from "~database/entities/Status";
import { createNewLocalUser } from "~database/entities/User";
import { db } from "~drizzle/db";
import { Notes, Tokens, Users } from "~drizzle/schema";
import { server } from "~index";
import { Note } from "~packages/database-interface/note";
import type { User } from "~packages/database-interface/user";
import { User } from "~packages/database-interface/user";
/**
* This allows us to send a test request to the server even when it isnt running
* CURRENTLY NOT WORKING, NEEDS TO BE FIXED
@ -33,7 +32,7 @@ export const getTestUsers = async (count: number) => {
for (let i = 0; i < count; i++) {
const password = randomBytes(32).toString("hex");
const user = await createNewLocalUser({
const user = await User.fromDataLocal({
username: `test-${randomBytes(32).toString("hex")}`,
email: `${randomBytes(32).toString("hex")}@test.com`,
password,