refactor (backend): port password hashing/verification to backend-rs

Co-authored-by: naskya <m@naskya.net>
This commit is contained in:
sup39 2024-04-14 14:41:01 +09:00 committed by naskya
parent baa57d7c17
commit 70aa3704ef
No known key found for this signature in database
GPG key ID: 712D413B3A9FED5C
25 changed files with 214 additions and 118 deletions

92
Cargo.lock generated
View file

@ -132,6 +132,18 @@ version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
[[package]]
name = "argon2"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072"
dependencies = [
"base64ct",
"blake2",
"cpufeatures",
"password-hash",
]
[[package]]
name = "arrayvec"
version = "0.7.4"
@ -190,8 +202,10 @@ checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
name = "backend-rs"
version = "0.0.0"
dependencies = [
"argon2",
"async-trait",
"basen",
"bcrypt",
"cfg-if",
"chrono",
"cuid2",
@ -238,6 +252,12 @@ version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "base64"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51"
[[package]]
name = "base64ct"
version = "1.6.0"
@ -250,6 +270,19 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dbe4bb73fd931c4d1aaf53b35d1286c8a948ad00ec92c8e3c856f15fd027f43"
[[package]]
name = "bcrypt"
version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e65938ed058ef47d92cf8b346cc76ef48984572ade631927e9937b5ffc7662c7"
dependencies = [
"base64 0.22.0",
"blowfish",
"getrandom",
"subtle",
"zeroize",
]
[[package]]
name = "bigdecimal"
version = "0.3.1"
@ -303,6 +336,15 @@ dependencies = [
"wyz",
]
[[package]]
name = "blake2"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
dependencies = [
"digest",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
@ -312,6 +354,16 @@ dependencies = [
"generic-array",
]
[[package]]
name = "blowfish"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7"
dependencies = [
"byteorder",
"cipher",
]
[[package]]
name = "borsh"
version = "1.4.0"
@ -415,6 +467,16 @@ dependencies = [
"windows-targets 0.52.4",
]
[[package]]
name = "cipher"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
dependencies = [
"crypto-common",
"inout",
]
[[package]]
name = "clap"
version = "4.5.4"
@ -1075,6 +1137,15 @@ dependencies = [
"syn 2.0.58",
]
[[package]]
name = "inout"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
dependencies = [
"generic-array",
]
[[package]]
name = "ipnet"
version = "2.9.0"
@ -1122,7 +1193,7 @@ checksum = "2a071f4f7efc9a9118dfb627a0a94ef247986e1ab8606a4c806ae2b3aa3b6978"
dependencies = [
"ahash 0.8.11",
"anyhow",
"base64",
"base64 0.21.7",
"bytecount",
"clap",
"fancy-regex",
@ -1559,6 +1630,17 @@ dependencies = [
"syn 2.0.58",
]
[[package]]
name = "password-hash"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
dependencies = [
"base64ct",
"rand_core",
"subtle",
]
[[package]]
name = "paste"
version = "1.0.14"
@ -1801,7 +1883,7 @@ version = "0.11.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
dependencies = [
"base64",
"base64 0.21.7",
"bytes",
"encoding_rs",
"futures-core",
@ -1947,7 +2029,7 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
dependencies = [
"base64",
"base64 0.21.7",
]
[[package]]
@ -2398,7 +2480,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418"
dependencies = [
"atoi",
"base64",
"base64 0.21.7",
"bigdecimal",
"bitflags 2.5.0",
"byteorder",
@ -2445,7 +2527,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e"
dependencies = [
"atoi",
"base64",
"base64 0.21.7",
"bigdecimal",
"bitflags 2.5.0",
"byteorder",

View file

@ -9,8 +9,10 @@ napi = { version = "2.16.2", default-features = false }
napi-derive = "2.16.2"
napi-build = "2.1.2"
argon2 = "0.5.3"
async-trait = "0.1.80"
basen = "0.1.0"
bcrypt = "0.15.1"
cfg-if = "1.0.0"
chrono = "0.4.37"
convert_case = "0.6.0"

View file

@ -17,8 +17,10 @@ macro_rs = { workspace = true }
napi = { workspace = true, optional = true, default-features = false, features = ["napi9", "tokio_rt", "chrono_date", "serde-json"] }
napi-derive = { workspace = true, optional = true }
argon2 = { workspace = true, features = ["std"] }
async-trait = { workspace = true }
basen = { workspace = true }
bcrypt = { workspace = true }
cfg-if = { workspace = true }
chrono = { workspace = true }
cuid2 = { workspace = true }

View file

@ -135,6 +135,9 @@ export function toPuny(host: string): string
export function toMastodonId(firefishId: string): string | null
export function fromMastodonId(mastodonId: string): string | null
export function nyaify(text: string, lang?: string | undefined | null): string
export function hashPassword(password: string): string
export function verifyPassword(password: string, hash: string): boolean
export function isOldPasswordAlgorithm(hash: string): boolean
export interface AbuseUserReport {
id: string
createdAt: Date

View file

@ -310,7 +310,7 @@ if (!nativeBinding) {
throw new Error(`Failed to load native binding`)
}
const { readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, toMastodonId, fromMastodonId, nyaify, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding
const { readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, toMastodonId, fromMastodonId, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding
module.exports.readServerConfig = readServerConfig
module.exports.stringToAcct = stringToAcct
@ -324,6 +324,9 @@ module.exports.toPuny = toPuny
module.exports.toMastodonId = toMastodonId
module.exports.fromMastodonId = fromMastodonId
module.exports.nyaify = nyaify
module.exports.hashPassword = hashPassword
module.exports.verifyPassword = verifyPassword
module.exports.isOldPasswordAlgorithm = isOldPasswordAlgorithm
module.exports.AntennaSrcEnum = AntennaSrcEnum
module.exports.MutedNoteReasonEnum = MutedNoteReasonEnum
module.exports.NoteVisibilityEnum = NoteVisibilityEnum

View file

@ -3,3 +3,4 @@ pub mod check_word_mute;
pub mod convert_host;
pub mod mastodon_id;
pub mod nyaify;
pub mod password;

View file

@ -0,0 +1,69 @@
use argon2::{
password_hash,
password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
Argon2,
};
#[crate::export]
pub fn hash_password(password: &str) -> Result<String, password_hash::errors::Error> {
let salt = SaltString::generate(&mut OsRng);
Ok(Argon2::default()
.hash_password(password.as_bytes(), &salt)?
.to_string())
}
#[derive(thiserror::Error, Debug)]
pub enum VerifyError {
#[error("An error occured while bcrypt verification: {0}")]
BcryptError(#[from] bcrypt::BcryptError),
#[error("Invalid argon2 password hash: {0}")]
InvalidArgon2Hash(#[from] password_hash::Error),
#[error("An error occured while argon2 verification: {0}")]
Argon2Error(#[from] argon2::Error),
}
#[crate::export]
pub fn verify_password(password: &str, hash: &str) -> Result<bool, VerifyError> {
if is_old_password_algorithm(hash) {
Ok(bcrypt::verify(password, hash)?)
} else {
let parsed_hash = PasswordHash::new(hash)?;
Ok(Argon2::default()
.verify_password(password.as_bytes(), &parsed_hash)
.is_ok())
}
}
#[inline]
#[crate::export]
pub fn is_old_password_algorithm(hash: &str) -> bool {
// bcrypt hashes start with $2[ab]$
hash.starts_with("$2")
}
#[cfg(test)]
mod unit_test {
use super::{hash_password, is_old_password_algorithm, verify_password};
#[test]
fn verify_password_test() {
let password = "omWc*%sD^fn7o2cXmc9e2QasBdrbRuhNB*gx!J5";
let hash = hash_password(password).unwrap();
assert!(verify_password(password, hash.as_str()).unwrap());
let argon2_hash = "$argon2id$v=19$m=19456,t=2,p=1$jty3puDFd4ENv/lgHn3ROQ$kRHDdEoVv2rruvnF731E74NxnYlvj5FMgePdGIIq3Jk";
let argon2_invalid_hash = "$argon2id$v=19$m=19456,t=2,p=1$jty3puDFd4ENv/lgHn3ROQ$kRHDdEoVv2rruvnF731E74NxnYlvj4FMgePdGIIq3Jk";
let bcrypt_hash = "$2a$12$WzUc.20jgbHmQjUMqTr8vOhKqYbS1BUvubapv/GLjCK1IN.h4e4la";
let bcrypt_invalid_hash = "$2a$12$WzUc.20jgbHmQjUMqTr7vOhKqYbS1BUvubapv/GLjCK1IN.h4e4la";
assert!(!is_old_password_algorithm(argon2_hash));
assert!(is_old_password_algorithm(bcrypt_hash));
assert!(verify_password(password, argon2_hash).unwrap());
assert!(verify_password(password, bcrypt_hash).unwrap());
assert!(!verify_password(password, argon2_invalid_hash).unwrap());
assert!(!verify_password(password, bcrypt_invalid_hash).unwrap());
}
}

View file

@ -37,11 +37,9 @@
"adm-zip": "0.5.10",
"ajv": "8.12.0",
"archiver": "7.0.1",
"argon2": "^0.40.1",
"aws-sdk": "2.1597.0",
"axios": "^1.6.8",
"backend-rs": "workspace:*",
"bcryptjs": "2.4.3",
"blurhash": "2.0.5",
"bull": "4.12.2",
"cacheable-lookup": "TheEssem/cacheable-lookup",
@ -130,7 +128,6 @@
"@swc/cli": "0.3.12",
"@swc/core": "1.4.13",
"@types/adm-zip": "^0.5.5",
"@types/bcryptjs": "2.4.6",
"@types/color-convert": "^2.0.3",
"@types/content-disposition": "^0.5.8",
"@types/escape-regexp": "0.0.3",

View file

@ -1,20 +0,0 @@
import bcrypt from "bcryptjs";
import * as argon2 from "argon2";
export async function hashPassword(password: string): Promise<string> {
return argon2.hash(password);
}
export async function comparePassword(
password: string,
hash: string,
): Promise<boolean> {
if (isOldAlgorithm(hash)) return bcrypt.compare(password, hash);
return argon2.verify(hash, password);
}
export function isOldAlgorithm(hash: string): boolean {
// bcrypt hashes start with $2[ab]$
return hash.startsWith("$2");
}

View file

@ -4,12 +4,11 @@ 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, toPuny } from "backend-rs";
import { genId, hashPassword, toPuny } from "backend-rs";
import { UserKeypair } from "@/models/entities/user-keypair.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";
export async function signup(opts: {
username: User["username"];
@ -40,7 +39,7 @@ export async function signup(opts: {
}
// Generate hash of password
hash = await hashPassword(password);
hash = hashPassword(password);
}
// Generate secret

View file

@ -1,8 +1,7 @@
import define from "@/server/api/define.js";
// import bcrypt from "bcryptjs";
import rndstr from "rndstr";
import { Users, UserProfiles } from "@/models/index.js";
import { hashPassword } from "@/misc/password.js";
import { hashPassword } from "backend-rs";
export const meta = {
tags: ["admin"],
@ -48,8 +47,7 @@ export default define(meta, paramDef, async (ps) => {
const passwd = rndstr("a-zA-Z0-9", 8);
// Generate hash of password
// const hash = bcrypt.hashSync(passwd);
const hash = await hashPassword(passwd);
const hash = hashPassword(passwd);
await UserProfiles.update(
{

View file

@ -9,7 +9,7 @@ import {
import config from "@/config/index.js";
import { procedures, hash } from "@/server/api/2fa.js";
import { publishMainStream } from "@/services/stream.js";
import { comparePassword } from "@/misc/password.js";
import { verifyPassword } from "backend-rs";
const rpIdHashReal = hash(Buffer.from(config.hostname, "utf-8"));
@ -40,8 +40,8 @@ export const paramDef = {
export default define(meta, paramDef, async (ps, user) => {
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
// Compare password
const same = await comparePassword(ps.password, profile.password!);
// Compare passwords
const same = verifyPassword(ps.password, profile.password!);
if (!same) {
throw new Error("incorrect password");

View file

@ -2,9 +2,8 @@ import define from "@/server/api/define.js";
import { UserProfiles, AttestationChallenges } from "@/models/index.js";
import { promisify } from "node:util";
import * as crypto from "node:crypto";
import { genId } from "backend-rs";
import { genId, verifyPassword } from "backend-rs";
import { hash } from "@/server/api/2fa.js";
import { comparePassword } from "@/misc/password.js";
const randomBytes = promisify(crypto.randomBytes);
@ -25,8 +24,8 @@ export const paramDef = {
export default define(meta, paramDef, async (ps, user) => {
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
// Compare password
const same = await comparePassword(ps.password, profile.password!);
// Compare passwords
const same = verifyPassword(ps.password, profile.password!);
if (!same) {
throw new Error("incorrect password");

View file

@ -3,7 +3,7 @@ import * as QRCode from "qrcode";
import config from "@/config/index.js";
import { UserProfiles } from "@/models/index.js";
import define from "@/server/api/define.js";
import { comparePassword } from "@/misc/password.js";
import { verifyPassword } from "backend-rs";
export const meta = {
requireCredential: true,
@ -22,8 +22,8 @@ export const paramDef = {
export default define(meta, paramDef, async (ps, user) => {
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
// Compare password
const same = await comparePassword(ps.password, profile.password!);
// Compare passwords
const same = verifyPassword(ps.password, profile.password!);
if (!same) {
throw new Error("incorrect password");

View file

@ -1,4 +1,4 @@
import { comparePassword } from "@/misc/password.js";
import { verifyPassword } from "backend-rs";
import define from "@/server/api/define.js";
import { UserProfiles, UserSecurityKeys, Users } from "@/models/index.js";
import { publishMainStream } from "@/services/stream.js";
@ -21,8 +21,8 @@ export const paramDef = {
export default define(meta, paramDef, async (ps, user) => {
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
// Compare password
const same = await comparePassword(ps.password, profile.password!);
// Compare passwords
const same = verifyPassword(ps.password, profile.password!);
if (!same) {
throw new Error("incorrect password");

View file

@ -1,7 +1,7 @@
import { publishMainStream } from "@/services/stream.js";
import define from "@/server/api/define.js";
import { Users, UserProfiles } from "@/models/index.js";
import { comparePassword } from "@/misc/password.js";
import { verifyPassword } from "backend-rs";
export const meta = {
requireCredential: true,
@ -20,8 +20,8 @@ export const paramDef = {
export default define(meta, paramDef, async (ps, user) => {
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
// Compare password
const same = await comparePassword(ps.password, profile.password!);
// Compare passwords
const same = verifyPassword(ps.password, profile.password!);
if (!same) {
throw new Error("incorrect password");

View file

@ -1,6 +1,6 @@
import define from "@/server/api/define.js";
import { UserProfiles } from "@/models/index.js";
import { hashPassword, comparePassword } from "@/misc/password.js";
import { hashPassword, verifyPassword } from "backend-rs";
export const meta = {
requireCredential: true,
@ -20,8 +20,8 @@ export const paramDef = {
export default define(meta, paramDef, async (ps, user) => {
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
// Compare password
const same = await comparePassword(ps.currentPassword, profile.password!);
// Compare passwords
const same = verifyPassword(ps.currentPassword, profile.password!);
if (!same) {
throw new Error("incorrect password");

View file

@ -1,7 +1,7 @@
import { UserProfiles, Users } from "@/models/index.js";
import { deleteAccount } from "@/services/delete-account.js";
import define from "@/server/api/define.js";
import { comparePassword } from "@/misc/password.js";
import { verifyPassword } from "backend-rs";
export const meta = {
requireCredential: true,
@ -24,8 +24,8 @@ export default define(meta, paramDef, async (ps, user) => {
return;
}
// Compare password
const same = await comparePassword(ps.password, profile.password!);
// Compare passwords
const same = verifyPassword(ps.password, profile.password!);
if (!same) {
throw new Error("incorrect password");

View file

@ -6,7 +6,7 @@ import {
import generateUserToken from "@/server/api/common/generate-native-user-token.js";
import define from "@/server/api/define.js";
import { Users, UserProfiles } from "@/models/index.js";
import { comparePassword } from "@/misc/password.js";
import { verifyPassword } from "backend-rs";
export const meta = {
requireCredential: true,
@ -28,8 +28,8 @@ export default define(meta, paramDef, async (ps, user) => {
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
// Compare password
const same = await comparePassword(ps.password, profile.password!);
// Compare passwords
const same = verifyPassword(ps.password, profile.password!);
if (!same) {
throw new Error("incorrect password");

View file

@ -7,7 +7,7 @@ import { sendEmail } from "@/services/send-email.js";
import { ApiError } from "@/server/api/error.js";
import { validateEmailForAccount } from "@/services/validate-email-for-account.js";
import { HOUR } from "@/const.js";
import { comparePassword } from "@/misc/password.js";
import { verifyPassword } from "backend-rs";
export const meta = {
requireCredential: true,
@ -46,8 +46,8 @@ export const paramDef = {
export default define(meta, paramDef, async (ps, user) => {
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
// Compare password
const same = await comparePassword(ps.password, profile.password!);
// Compare passwords
const same = verifyPassword(ps.password, profile.password!);
if (!same) {
throw new ApiError(meta.errors.incorrectPassword);

View file

@ -1,6 +1,6 @@
import { UserProfiles, PasswordResetRequests } from "@/models/index.js";
import define from "@/server/api/define.js";
import { hashPassword } from "@/misc/password.js";
import { hashPassword } from "backend-rs";
export const meta = {
tags: ["reset password"],
@ -32,7 +32,7 @@ export default define(meta, paramDef, async (ps, user) => {
}
// Generate hash of password
const hash = await hashPassword(ps.password);
const hash = hashPassword(ps.password);
await UserProfiles.update(req.userId, {
password: hash,

View file

@ -10,12 +10,12 @@ import {
AttestationChallenges,
} from "@/models/index.js";
import type { ILocalUser } from "@/models/entities/user.js";
import { genId } from "backend-rs";
import {
comparePassword,
genId,
hashPassword,
isOldAlgorithm,
} from "@/misc/password.js";
isOldPasswordAlgorithm,
verifyPassword,
} from "backend-rs";
import { verifyLogin, hash } from "@/server/api/2fa.js";
import { randomBytes } from "node:crypto";
import { IsNull } from "typeorm";
@ -91,11 +91,11 @@ export default async (ctx: Koa.Context) => {
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
// Compare password
const same = await comparePassword(password, profile.password!);
// Compare passwords
const same = verifyPassword(password, profile.password!);
if (same && isOldAlgorithm(profile.password!)) {
profile.password = await hashPassword(password);
if (same && isOldPasswordAlgorithm(profile.password!)) {
profile.password = hashPassword(password);
await UserProfiles.save(profile);
}

View file

@ -6,10 +6,8 @@ import { Users, RegistrationTickets, UserPendings } from "@/models/index.js";
import { signup } from "@/server/api/common/signup.js";
import config from "@/config/index.js";
import { sendEmail } from "@/services/send-email.js";
import { genId } from "backend-rs";
import { genId, hashPassword } from "backend-rs";
import { validateEmailForAccount } from "@/services/validate-email-for-account.js";
import { hashPassword } from "@/misc/password.js";
import { inspect } from "node:util";
export default async (ctx: Koa.Context) => {
const body = ctx.request.body;
@ -85,7 +83,7 @@ export default async (ctx: Koa.Context) => {
const code = rndstr("a-z0-9", 16);
// Generate hash of password
const hash = await hashPassword(password);
const hash = hashPassword(password);
await UserPendings.insert({
id: genId(),

View file

@ -4,17 +4,16 @@ import { genRsaKeyPair } from "@/misc/gen-key-pair.js";
import { User } from "@/models/entities/user.js";
import { UserProfile } from "@/models/entities/user-profile.js";
import { IsNull } from "typeorm";
import { genId } from "backend-rs";
import { genId, hashPassword } from "backend-rs";
import { UserKeypair } from "@/models/entities/user-keypair.js";
import { UsedUsername } from "@/models/entities/used-username.js";
import { db } from "@/db/postgre.js";
import { hashPassword } from "@/misc/password.js";
export async function createSystemUser(username: string) {
const password = uuid();
// Generate hash of password
const hash = await hashPassword(password);
const hash = hashPassword(password);
// Generate secret
const secret = generateNativeUserToken();

View file

@ -99,9 +99,6 @@ importers:
archiver:
specifier: 7.0.1
version: 7.0.1
argon2:
specifier: ^0.40.1
version: 0.40.1
aws-sdk:
specifier: 2.1597.0
version: 2.1597.0
@ -111,9 +108,6 @@ importers:
backend-rs:
specifier: workspace:*
version: link:../backend-rs
bcryptjs:
specifier: 2.4.3
version: 2.4.3
blurhash:
specifier: 2.0.5
version: 2.0.5
@ -377,9 +371,6 @@ importers:
'@types/adm-zip':
specifier: ^0.5.5
version: 0.5.5
'@types/bcryptjs':
specifier: 2.4.6
version: 2.4.6
'@types/color-convert':
specifier: ^2.0.3
version: 2.0.3
@ -3294,11 +3285,6 @@ packages:
sshpk: 1.17.0
dev: false
/@phc/format@1.0.0:
resolution: {integrity: sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==}
engines: {node: '>=10'}
dev: false
/@phosphor-icons/web@2.1.1:
resolution: {integrity: sha512-QjrfbItu5Rb2i37GzsKxmrRHfZPTVk3oXSPBnQ2+oACDbQRWGAeB0AsvZw263n1nFouQuff+khOCtRbrc6+k+A==}
dev: true
@ -3831,10 +3817,6 @@ packages:
'@babel/types': 7.23.0
dev: true
/@types/bcryptjs@2.4.6:
resolution: {integrity: sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==}
dev: true
/@types/body-parser@1.19.2:
resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==}
dependencies:
@ -5358,16 +5340,6 @@ packages:
/arg@4.1.3:
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
/argon2@0.40.1:
resolution: {integrity: sha512-DjtHDwd7pm12qeWyfihHoM8Bn5vGcgH6sKwgPqwNYroRmxlrzadHEvMyuvQxN/V8YSyRRKD5x6ito09q1e9OyA==}
engines: {node: '>=16.17.0'}
requiresBuild: true
dependencies:
'@phc/format': 1.0.0
node-addon-api: 7.1.0
node-gyp-build: 4.8.0
dev: false
/argparse@1.0.10:
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
dependencies:
@ -5893,10 +5865,6 @@ packages:
tweetnacl: 0.14.5
dev: false
/bcryptjs@2.4.3:
resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==}
dev: false
/bin-check@4.1.0:
resolution: {integrity: sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==}
engines: {node: '>=4'}
@ -13029,11 +12997,6 @@ packages:
dev: true
optional: true
/node-addon-api@7.1.0:
resolution: {integrity: sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==}
engines: {node: ^16 || ^18 || >= 20}
dev: false
/node-domexception@1.0.0:
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
engines: {node: '>=10.5.0'}
@ -13083,6 +13046,7 @@ packages:
/node-gyp-build@4.8.0:
resolution: {integrity: sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==}
hasBin: true
dev: true
/node-int64@0.4.0:
resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}