mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 08:28:19 +01:00
refactor(api): 🎨 Move createLocalUser to a static method of User
This commit is contained in:
parent
9d70778abd
commit
9e9998ea82
3
cli.ts
3
cli.ts
|
|
@ -13,7 +13,6 @@ import extract from "extract-zip";
|
||||||
import { MediaBackend } from "media-manager";
|
import { MediaBackend } from "media-manager";
|
||||||
import { lookup } from "mime-types";
|
import { lookup } from "mime-types";
|
||||||
import { getUrl } from "~database/entities/Attachment";
|
import { getUrl } from "~database/entities/Attachment";
|
||||||
import { type UserType, createNewLocalUser } from "~database/entities/User";
|
|
||||||
import { client, db } from "~drizzle/db";
|
import { client, db } from "~drizzle/db";
|
||||||
import { Emojis, Notes, OpenIdAccounts, Users } from "~drizzle/schema";
|
import { Emojis, Notes, OpenIdAccounts, Users } from "~drizzle/schema";
|
||||||
import { Note } from "~packages/database-interface/note";
|
import { Note } from "~packages/database-interface/note";
|
||||||
|
|
@ -129,7 +128,7 @@ const cliBuilder = new CliBuilder([
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create user
|
// Create user
|
||||||
const newUser = await createNewLocalUser({
|
const newUser = await User.fromDataLocal({
|
||||||
email: email,
|
email: email,
|
||||||
password: password,
|
password: password,
|
||||||
username: username,
|
username: username,
|
||||||
|
|
|
||||||
|
|
@ -379,69 +379,6 @@ export const resolveWebFinger = async (
|
||||||
return User.resolve(relevantLink.href);
|
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
|
* Parses mentions from a list of URIs
|
||||||
*/
|
*/
|
||||||
|
|
@ -537,31 +474,6 @@ export const getRelationshipToOtherUser = async (
|
||||||
return foundRelationship;
|
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 = (
|
export const followRequestToLysand = (
|
||||||
follower: User,
|
follower: User,
|
||||||
followee: User,
|
followee: User,
|
||||||
|
|
|
||||||
|
|
@ -262,6 +262,79 @@ export class User {
|
||||||
return this.user.avatar;
|
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
|
* Get the user's header in raw URL format
|
||||||
* @param config The config to use
|
* @param config The config to use
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ export const meta = applyConfig({
|
||||||
route: "/api/v1/accounts/:id/followers",
|
route: "/api/v1/accounts/:id/followers",
|
||||||
auth: {
|
auth: {
|
||||||
required: false,
|
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);
|
return errorResponse("Invalid ID, must be of type UUIDv7", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add pinned
|
|
||||||
const { max_id, min_id, since_id, limit } = extraData.parsedRequest;
|
const { max_id, min_id, since_id, limit } = extraData.parsedRequest;
|
||||||
|
|
||||||
const otherUser = await User.fromId(id);
|
const otherUser = await User.fromId(id);
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ export const meta = applyConfig({
|
||||||
route: "/api/v1/accounts/:id/following",
|
route: "/api/v1/accounts/:id/following",
|
||||||
auth: {
|
auth: {
|
||||||
required: false,
|
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);
|
return errorResponse("Invalid ID, must be of type UUIDv7", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add pinned
|
|
||||||
const { max_id, min_id, since_id, limit } = extraData.parsedRequest;
|
const { max_id, min_id, since_id, limit } = extraData.parsedRequest;
|
||||||
|
|
||||||
const otherUser = await User.fromId(id);
|
const otherUser = await User.fromId(id);
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import { tempmailDomains } from "@tempmail";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import ISO6391 from "iso-639-1";
|
import ISO6391 from "iso-639-1";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { createNewLocalUser } from "~database/entities/User";
|
|
||||||
import { Users } from "~drizzle/schema";
|
import { Users } from "~drizzle/schema";
|
||||||
import { User } from "~packages/database-interface/user";
|
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 ?? "",
|
username: body.username ?? "",
|
||||||
password: body.password ?? "",
|
password: body.password ?? "",
|
||||||
email: body.email ?? "",
|
email: body.email ?? "",
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
import { randomBytes } from "node:crypto";
|
import { randomBytes } from "node:crypto";
|
||||||
import { asc, inArray, like } from "drizzle-orm";
|
import { asc, inArray, like } from "drizzle-orm";
|
||||||
import type { Status } from "~database/entities/Status";
|
import type { Status } from "~database/entities/Status";
|
||||||
import { createNewLocalUser } from "~database/entities/User";
|
|
||||||
import { db } from "~drizzle/db";
|
import { db } from "~drizzle/db";
|
||||||
import { Notes, Tokens, Users } from "~drizzle/schema";
|
import { Notes, Tokens, Users } from "~drizzle/schema";
|
||||||
import { server } from "~index";
|
import { server } from "~index";
|
||||||
import { Note } from "~packages/database-interface/note";
|
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
|
* This allows us to send a test request to the server even when it isnt running
|
||||||
* CURRENTLY NOT WORKING, NEEDS TO BE FIXED
|
* CURRENTLY NOT WORKING, NEEDS TO BE FIXED
|
||||||
|
|
@ -33,7 +32,7 @@ export const getTestUsers = async (count: number) => {
|
||||||
for (let i = 0; i < count; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
const password = randomBytes(32).toString("hex");
|
const password = randomBytes(32).toString("hex");
|
||||||
|
|
||||||
const user = await createNewLocalUser({
|
const user = await User.fromDataLocal({
|
||||||
username: `test-${randomBytes(32).toString("hex")}`,
|
username: `test-${randomBytes(32).toString("hex")}`,
|
||||||
email: `${randomBytes(32).toString("hex")}@test.com`,
|
email: `${randomBytes(32).toString("hex")}@test.com`,
|
||||||
password,
|
password,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue