Fixed 267U.pre2
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
import { generateKeyPair } from "node:crypto";
|
||||
import generateUserToken from "./generate-native-user-token.js";
|
||||
import { User } from "../../../models/entities/user.js";
|
||||
import { Users, UsedUsernames } from "../../../models/index.js";
|
||||
import { UserProfile } from "../../../models/entities/user-profile.js";
|
||||
import { IsNull } from "typeorm";
|
||||
import { genId } from "../../../misc/gen-id.js";
|
||||
import { toPunyNullable } from "../../../misc/convert-host.js";
|
||||
import { UserKeypair } from "../../../models/entities/user-keypair.js";
|
||||
import { usersChart } from "../../../services/chart/index.js";
|
||||
import { UsedUsername } from "../../../models/entities/used-username.js";
|
||||
import { db } from "../../../db/postgre.js";
|
||||
import config from "../../../config/index.js";
|
||||
import { hashPassword } from "../../../misc/password.js";
|
||||
import { fetchMeta } from "../../../misc/fetch-meta.js";
|
||||
import follow from "../../../services/following/create.js";
|
||||
export async function signup(opts) {
|
||||
const { username, password, passwordHash, host } = opts;
|
||||
let hash = passwordHash;
|
||||
const userCount = await Users.countBy({
|
||||
host: IsNull()
|
||||
});
|
||||
if (config.maxUserSignups != null && userCount > config.maxUserSignups) {
|
||||
throw new Error("MAX_USERS_REACHED");
|
||||
}
|
||||
// Validate username
|
||||
if (!Users.validateLocalUsername(username)) {
|
||||
throw new Error("INVALID_USERNAME");
|
||||
}
|
||||
if (password != null && passwordHash == null) {
|
||||
// Validate password
|
||||
if (!Users.validatePassword(password)) {
|
||||
throw new Error("INVALID_PASSWORD");
|
||||
}
|
||||
// Generate hash of password
|
||||
hash = await hashPassword(password);
|
||||
}
|
||||
// Generate secret
|
||||
const secret = generateUserToken();
|
||||
// Check username duplication
|
||||
if (await Users.findOneBy({
|
||||
usernameLower: username.toLowerCase(),
|
||||
host: IsNull()
|
||||
})) {
|
||||
throw new Error("DUPLICATED_USERNAME");
|
||||
}
|
||||
// Check deleted username duplication
|
||||
if (await UsedUsernames.findOneBy({
|
||||
username: username.toLowerCase()
|
||||
})) {
|
||||
throw new Error("USED_USERNAME");
|
||||
}
|
||||
const keyPair = await new Promise((res, rej)=>generateKeyPair("rsa", {
|
||||
modulusLength: 4096,
|
||||
publicKeyEncoding: {
|
||||
type: "spki",
|
||||
format: "pem"
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
type: "pkcs8",
|
||||
format: "pem",
|
||||
cipher: undefined,
|
||||
passphrase: undefined
|
||||
}
|
||||
}, (err, publicKey, privateKey)=>err ? rej(err) : res([
|
||||
publicKey,
|
||||
privateKey
|
||||
])));
|
||||
const exist = await Users.findOneBy({
|
||||
usernameLower: username.toLowerCase(),
|
||||
host: IsNull()
|
||||
});
|
||||
if (exist) throw new Error("The username is already in use");
|
||||
// Prepare objects
|
||||
const user = new User({
|
||||
id: genId(),
|
||||
createdAt: new Date(),
|
||||
username: username,
|
||||
usernameLower: username.toLowerCase(),
|
||||
host: toPunyNullable(host),
|
||||
token: secret,
|
||||
isAdmin: await Users.countBy({
|
||||
host: IsNull(),
|
||||
isAdmin: true
|
||||
}) === 0
|
||||
});
|
||||
const userKeypair = new UserKeypair({
|
||||
publicKey: keyPair[0],
|
||||
privateKey: keyPair[1],
|
||||
userId: user.id
|
||||
});
|
||||
const userProfile = new UserProfile({
|
||||
userId: user.id,
|
||||
autoAcceptFollowed: true,
|
||||
allowCalls: false,
|
||||
password: hash
|
||||
});
|
||||
const usedUsername = new UsedUsername({
|
||||
createdAt: new Date(),
|
||||
username: username.toLowerCase()
|
||||
});
|
||||
// Save the objects atomically using a db transaction, note that we should never run any code in a transaction block directly
|
||||
await db.transaction(async (transactionalEntityManager)=>{
|
||||
await transactionalEntityManager.save(user);
|
||||
await transactionalEntityManager.save(userKeypair);
|
||||
await transactionalEntityManager.save(userProfile);
|
||||
await transactionalEntityManager.save(usedUsername);
|
||||
});
|
||||
const account = await Users.findOneByOrFail({
|
||||
id: user.id
|
||||
});
|
||||
const meta = await fetchMeta();
|
||||
// If an autofollow account exists, follow it
|
||||
if (meta.autofollowedAccount) {
|
||||
const autofollowedAccount = await Users.findOneByOrFail({
|
||||
usernameLower: meta.autofollowedAccount.toLowerCase(),
|
||||
host: IsNull()
|
||||
});
|
||||
if (autofollowedAccount) {
|
||||
await follow(account, autofollowedAccount);
|
||||
}
|
||||
}
|
||||
usersChart.update(account, true);
|
||||
return {
|
||||
account,
|
||||
secret
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user