@actual-app/sync-server 26.7.0-nightly.20260621 → 26.7.0-nightly.20260623

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/app.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { t as run } from "./chunks/migrations-Cneard4X.js";
2
2
  //#region app.ts
3
3
  run().then(() => {
4
- import("./chunks/app-B9HVY4ZU.js").then((app) => app.run());
4
+ import("./chunks/app-BByUQmkt.js").then((app) => app.run());
5
5
  }).catch((err) => {
6
6
  console.log("Error starting app:", err);
7
7
  process.exit(1);
@@ -41,7 +41,7 @@ if (values.help) {
41
41
  process.exit();
42
42
  }
43
43
  if (values.version) {
44
- console.log("v26.7.0-nightly.20260621");
44
+ console.log("v26.7.0-nightly.20260623");
45
45
  process.exit();
46
46
  }
47
47
  var setupDataDir = (dataDir) => {
@@ -1 +1 @@
1
- {"version":3,"file":"account-db-HkRNud0e.js","names":["uuidv4","config","config"],"sources":["../../src/services/user-service.ts","../../src/util/validate-user.ts","../../src/accounts/password.js","../../src/accounts/openid.ts","../../src/db.js","../../src/account-db.js"],"sourcesContent":["// @ts-strict-ignore\nimport { getAccountDb } from '#account-db';\n\nexport function getUserByUsername(userName) {\n if (!userName || typeof userName !== 'string') {\n return null;\n }\n const { id } =\n getAccountDb().first('SELECT id FROM users WHERE user_name = ?', [\n userName,\n ]) || {};\n return id || null;\n}\n\nexport function getUserById(userId) {\n if (!userId) {\n return null;\n }\n const { id } =\n getAccountDb().first('SELECT * FROM users WHERE id = ?', [userId]) || {};\n return id || null;\n}\n\nexport function getFileById(fileId) {\n if (!fileId) {\n return null;\n }\n const { id } =\n getAccountDb().first('SELECT * FROM files WHERE files.id = ?', [fileId]) ||\n {};\n return id || null;\n}\n\nexport function validateRole(roleId) {\n const possibleRoles = ['BASIC', 'ADMIN'];\n return possibleRoles.some(a => a === roleId);\n}\n\nexport function getOwnerCount(): number {\n const { ownerCount } = getAccountDb().first(\n `SELECT count(*) as ownerCount FROM users WHERE users.user_name <> '' and users.owner = 1`,\n ) || { ownerCount: 0 };\n return ownerCount;\n}\n\nexport function getOwnerId() {\n const { id } =\n getAccountDb().first(\n `SELECT users.id FROM users WHERE users.user_name <> '' and users.owner = 1`,\n ) || {};\n return id;\n}\n\nexport function getFileOwnerId(fileId) {\n const { owner } =\n getAccountDb().first(`SELECT files.owner FROM files WHERE files.id = ?`, [\n fileId,\n ]) || {};\n return owner;\n}\n\nexport function getAllUsers() {\n return getAccountDb().all(\n `SELECT users.id, user_name as userName, display_name as displayName, enabled, ifnull(owner,0) as owner, role\n FROM users\n WHERE users.user_name <> ''`,\n );\n}\n\nexport function insertUser(userId, userName, displayName, enabled, role) {\n getAccountDb().mutate(\n 'INSERT INTO users (id, user_name, display_name, enabled, owner, role) VALUES (?, ?, ?, ?, 0, ?)',\n [userId, userName, displayName, enabled, role],\n );\n}\n\nexport function updateUser(userId, userName, displayName, enabled) {\n if (!userId || !userName) {\n throw new Error('Invalid user parameters');\n }\n try {\n getAccountDb().mutate(\n 'UPDATE users SET user_name = ?, display_name = ?, enabled = ? WHERE id = ?',\n [userName, displayName, enabled, userId],\n );\n } catch (error) {\n throw new Error(`Failed to update user: ${error.message}`);\n }\n}\n\nexport function updateUserWithRole(\n userId,\n userName,\n displayName,\n enabled,\n roleId,\n) {\n getAccountDb().transaction(() => {\n getAccountDb().mutate(\n 'UPDATE users SET user_name = ?, display_name = ?, enabled = ?, role = ? WHERE id = ?',\n [userName, displayName, enabled, roleId, userId],\n );\n if (!enabled) {\n getAccountDb().mutate('DELETE FROM sessions WHERE user_id = ?', [userId]);\n }\n });\n}\n\nexport function deleteUser(userId) {\n return getAccountDb().transaction(() => {\n const { changes } = getAccountDb().mutate(\n 'DELETE FROM users WHERE id = ? and owner = 0',\n [userId],\n );\n if (changes > 0) {\n getAccountDb().mutate('DELETE FROM sessions WHERE user_id = ?', [userId]);\n }\n return changes;\n });\n}\nexport function deleteUserAccess(userId) {\n try {\n return getAccountDb().mutate('DELETE FROM user_access WHERE user_id = ?', [\n userId,\n ]).changes;\n } catch (error) {\n throw new Error(`Failed to delete user access: ${error.message}`);\n }\n}\n\nexport function transferAllFilesFromUser(ownerId, oldUserId) {\n if (!ownerId || !oldUserId) {\n throw new Error('Invalid user IDs');\n }\n try {\n getAccountDb().transaction(() => {\n const ownerExists = getUserById(ownerId);\n if (!ownerExists) {\n throw new Error('New owner not found');\n }\n getAccountDb().mutate('UPDATE files set owner = ? WHERE owner = ?', [\n ownerId,\n oldUserId,\n ]);\n });\n } catch (error) {\n throw new Error(`Failed to transfer files: ${error.message}`);\n }\n}\n\nexport function updateFileOwner(ownerId, fileId) {\n if (!ownerId || !fileId) {\n throw new Error('Invalid parameters');\n }\n try {\n const result = getAccountDb().mutate(\n 'UPDATE files set owner = ? WHERE id = ?',\n [ownerId, fileId],\n );\n if (result.changes === 0) {\n throw new Error('File not found');\n }\n } catch (error) {\n throw new Error(`Failed to update file owner: ${error.message}`);\n }\n}\n\nexport function getUserAccess(fileId, userId, isAdmin) {\n return getAccountDb().all(\n `SELECT users.id as userId, user_name as userName, files.owner, display_name as displayName\n FROM users\n JOIN user_access ON user_access.user_id = users.id\n JOIN files ON files.id = user_access.file_id\n WHERE files.id = ? and (files.owner = ? OR 1 = ?)`,\n [fileId, userId, isAdmin ? 1 : 0],\n );\n}\n\nexport function countUserAccess(fileId, userId) {\n const { accessCount } =\n getAccountDb().first(\n `SELECT COUNT(*) as accessCount\n FROM files\n WHERE files.id = ? AND (files.owner = ? OR EXISTS (\n SELECT 1 FROM user_access\n WHERE user_access.user_id = ? AND user_access.file_id = ?)\n )`,\n [fileId, userId, userId, fileId],\n ) || {};\n\n return accessCount || 0;\n}\n\nexport function checkFilePermission(fileId, userId) {\n return (\n getAccountDb().first(\n `SELECT 1 as granted\n FROM files\n WHERE files.id = ? and (files.owner = ?)`,\n [fileId, userId],\n ) || { granted: 0 }\n );\n}\n\nexport function addUserAccess(userId, fileId) {\n if (!userId || !fileId) {\n throw new Error('Invalid parameters');\n }\n try {\n const userExists = getUserById(userId);\n const fileExists = getFileById(fileId);\n if (!userExists || !fileExists) {\n throw new Error('User or file not found');\n }\n getAccountDb().mutate(\n 'INSERT INTO user_access (user_id, file_id) VALUES (?, ?)',\n [userId, fileId],\n );\n } catch (error) {\n if (error.message.includes('UNIQUE constraint')) {\n throw new Error('Access already exists');\n }\n throw new Error(`Failed to add user access: ${error.message}`);\n }\n}\n\nexport function deleteUserAccessByFileId(userIds, fileId) {\n if (!Array.isArray(userIds) || userIds.length === 0) {\n throw new Error('The provided userIds must be a non-empty array.');\n }\n\n const CHUNK_SIZE = 999;\n let totalChanges = 0;\n\n try {\n getAccountDb().transaction(() => {\n for (let i = 0; i < userIds.length; i += CHUNK_SIZE) {\n const chunk = userIds.slice(i, i + CHUNK_SIZE);\n const placeholders = chunk.map(() => '?').join(',');\n\n const sql = `DELETE FROM user_access WHERE user_id IN (${placeholders}) AND file_id = ?`;\n\n const result = getAccountDb().mutate(sql, [...chunk, fileId]);\n totalChanges += result.changes;\n }\n });\n } catch (error) {\n throw new Error(`Failed to delete user access: ${error.message}`);\n }\n\n return totalChanges;\n}\n\nexport function getAllUserAccess(fileId) {\n //This can't be used here until we can create user invite links:\n //const isLoginMode = config.get('userCreationMode') === 'login';\n const isLoginMode = false;\n const joinType = isLoginMode ? 'JOIN' : 'LEFT JOIN';\n\n return getAccountDb().all(\n `\n SELECT\n users.id as userId,\n user_name as userName,\n display_name as displayName,\n CASE WHEN user_access.file_id IS NULL THEN 0 ELSE 1 END as haveAccess,\n CASE WHEN files.id IS NULL THEN 0 ELSE 1 END as owner\n FROM users\n ${joinType} user_access ON user_access.file_id = ? AND user_access.user_id = users.id\n ${joinType} files ON files.id = ? AND files.owner = users.id\n WHERE users.enabled = 1\n AND users.user_name <> ''\n `,\n [fileId, fileId],\n );\n}\n\nexport function getOpenIDConfig() {\n return (\n getAccountDb().first(`SELECT * FROM auth WHERE method = ?`, ['openid']) ||\n null\n );\n}\n","import type { Request, Response } from 'express';\nimport ipaddr from 'ipaddr.js';\n\nimport { getSession } from '#account-db';\nimport { config } from '#load-config';\n\nexport const TOKEN_EXPIRATION_NEVER = -1;\nconst MS_PER_SECOND = 1000;\n\nexport function validateSession(req: Request, res: Response) {\n let { token } = req.body || {};\n\n if (!token) {\n token = req.headers['x-actual-token'];\n }\n\n const session = getSession(token);\n\n if (!session) {\n res.status(401);\n res.send({\n status: 'error',\n reason: 'unauthorized',\n details: 'token-not-found',\n });\n return null;\n }\n\n if (\n session.expires_at !== TOKEN_EXPIRATION_NEVER &&\n session.expires_at * MS_PER_SECOND <= Date.now()\n ) {\n res.status(401);\n res.send({\n status: 'error',\n reason: 'token-expired',\n });\n return null;\n }\n\n return session;\n}\n\nexport function validateAuthHeader(req: Request) {\n // fallback to trustedProxies when trustedAuthProxies not set\n const trustedAuthProxies: string[] =\n config.get('trustedAuthProxies') ?? config.get('trustedProxies');\n // ensure the first hop from our server is trusted\n const peer = req.socket.remoteAddress;\n if (peer === undefined) {\n console.error(`Header Auth Login attempted but there was no defined peer.`);\n return false;\n }\n const peerIp = ipaddr.process(peer);\n const rangeList = {\n allowed_ips: trustedAuthProxies.map(q => ipaddr.parseCIDR(q)),\n };\n\n const matched = ipaddr.subnetMatch(peerIp, rangeList, 'fail');\n\n if (matched === 'allowed_ips') {\n console.info(`Header Auth Login permitted from ${peer}`);\n return true;\n } else {\n console.warn(`Header Auth Login attempted from ${peer}`);\n return false;\n }\n}\n","import * as bcrypt from 'bcrypt';\nimport { v4 as uuidv4 } from 'uuid';\n\nimport { clearExpiredSessions, getAccountDb } from '#account-db';\nimport { config } from '#load-config';\nimport { TOKEN_EXPIRATION_NEVER } from '#util/validate-user';\n\nfunction isValidPassword(password) {\n return password != null && password !== '';\n}\n\nfunction hashPassword(password) {\n return bcrypt.hashSync(password, 12);\n}\n\nexport function bootstrapPassword(password) {\n if (!isValidPassword(password)) {\n return { error: 'invalid-password' };\n }\n\n const hashed = hashPassword(password);\n const accountDb = getAccountDb();\n accountDb.transaction(() => {\n accountDb.mutate('DELETE FROM auth WHERE method = ?', ['password']);\n accountDb.mutate('UPDATE auth SET active = 0');\n accountDb.mutate(\n \"INSERT INTO auth (method, display_name, extra_data, active) VALUES ('password', 'Password', ?, 1)\",\n [hashed],\n );\n });\n\n return {};\n}\n\nexport function loginWithPassword(password) {\n if (!isValidPassword(password)) {\n return { error: 'invalid-password' };\n }\n\n const accountDb = getAccountDb();\n const { extra_data: passwordHash } =\n accountDb.first('SELECT extra_data FROM auth WHERE method = ?', [\n 'password',\n ]) || {};\n\n if (!passwordHash) {\n return { error: 'invalid-password' };\n }\n\n const confirmed = bcrypt.compareSync(password, passwordHash);\n\n if (!confirmed) {\n return { error: 'invalid-password' };\n }\n\n const sessionRow = accountDb.first(\n 'SELECT * FROM sessions WHERE auth_method = ?',\n ['password'],\n );\n\n const token = sessionRow ? sessionRow.token : uuidv4();\n\n const { totalOfUsers } = accountDb.first(\n 'SELECT count(*) as totalOfUsers FROM users',\n );\n let userId = null;\n if (totalOfUsers === 0) {\n userId = uuidv4();\n accountDb.mutate(\n 'INSERT INTO users (id, user_name, display_name, enabled, owner, role) VALUES (?, ?, ?, 1, 1, ?)',\n [userId, '', '', 'ADMIN'],\n );\n } else {\n const { id: userIdFromDb } = accountDb.first(\n 'SELECT id FROM users WHERE user_name = ?',\n [''],\n );\n\n userId = userIdFromDb;\n\n if (!userId) {\n return { error: 'user-not-found' };\n }\n }\n\n let expiration = TOKEN_EXPIRATION_NEVER;\n if (\n config.get('token_expiration') !== 'never' &&\n config.get('token_expiration') !== 'openid-provider' &&\n typeof config.get('token_expiration') === 'number'\n ) {\n expiration =\n Math.floor(Date.now() / 1000) + config.get('token_expiration') * 60;\n }\n\n if (!sessionRow) {\n accountDb.mutate(\n 'INSERT INTO sessions (token, expires_at, user_id, auth_method) VALUES (?, ?, ?, ?)',\n [token, expiration, userId, 'password'],\n );\n } else {\n accountDb.mutate(\n 'UPDATE sessions SET user_id = ?, expires_at = ? WHERE token = ?',\n [userId, expiration, token],\n );\n }\n\n clearExpiredSessions();\n\n return { token };\n}\n\nexport function changePassword(newPassword) {\n const accountDb = getAccountDb();\n\n if (!isValidPassword(newPassword)) {\n return { error: 'invalid-password' };\n }\n\n const hashed = hashPassword(newPassword);\n accountDb.mutate(\"UPDATE auth SET extra_data = ? WHERE method = 'password'\", [\n hashed,\n ]);\n return {};\n}\n\nexport function checkPassword(password) {\n if (!isValidPassword(password)) {\n return false;\n }\n\n const accountDb = getAccountDb();\n const { extra_data: passwordHash } =\n accountDb.first('SELECT extra_data FROM auth WHERE method = ?', [\n 'password',\n ]) || {};\n\n if (!passwordHash) {\n return false;\n }\n\n const confirmed = bcrypt.compareSync(password, passwordHash);\n\n if (!confirmed) {\n return false;\n }\n\n return true;\n}\n","// @ts-strict-ignore\nimport { custom, generators, Issuer } from 'openid-client';\nimport { v4 as uuidv4 } from 'uuid';\n\nimport {\n clearExpiredSessions,\n getAccountDb,\n listLoginMethods,\n} from '#account-db';\nimport { config } from '#load-config';\nimport {\n getUserByUsername,\n transferAllFilesFromUser,\n} from '#services/user-service';\nimport { TOKEN_EXPIRATION_NEVER } from '#util/validate-user';\n\nimport { checkPassword } from './password';\n\nexport type ConfigParameter = {\n issuer?: string;\n discoveryURL?: string;\n client_id?: string;\n client_secret?: string;\n server_hostname?: string;\n};\n\nexport async function bootstrapOpenId(configParameter: ConfigParameter) {\n if (!('issuer' in configParameter) && !('discoveryURL' in configParameter)) {\n return { error: 'missing-issuer-or-discoveryURL' };\n }\n if (!('client_id' in configParameter)) {\n return { error: 'missing-client-id' };\n }\n if (!('client_secret' in configParameter)) {\n return { error: 'missing-client-secret' };\n }\n if (!('server_hostname' in configParameter)) {\n return { error: 'missing-server-hostname' };\n }\n\n custom.setHttpOptionsDefaults({\n timeout: 20 * 1000, // 20 seconds\n });\n\n try {\n //FOR BACKWARD COMPATIBLITY:\n //If we don't put discoverURL into the issuer, it will break already enabled openid instances\n if (configParameter.discoveryURL) {\n configParameter.issuer = configParameter.discoveryURL;\n delete configParameter.discoveryURL;\n }\n\n await setupOpenIdClient(configParameter);\n } catch (err) {\n console.error('Error setting up OpenID client:', err);\n return { error: 'configuration-error' };\n }\n\n const accountDb = getAccountDb();\n try {\n accountDb.transaction(() => {\n accountDb.mutate('DELETE FROM auth WHERE method = ?', ['openid']);\n accountDb.mutate('UPDATE auth SET active = 0');\n accountDb.mutate(\n \"INSERT INTO auth (method, display_name, extra_data, active) VALUES ('openid', 'OpenID', ?, 1)\",\n [JSON.stringify(configParameter)],\n );\n });\n } catch (err) {\n console.error('Error updating auth table:', err);\n return { error: 'database-error' };\n }\n\n return {};\n}\n\nasync function setupOpenIdClient(configParameter) {\n const issuer =\n typeof configParameter.issuer === 'string'\n ? await Issuer.discover(configParameter.issuer)\n : new Issuer({\n issuer: configParameter.issuer.name,\n authorization_endpoint: configParameter.issuer.authorization_endpoint,\n token_endpoint: configParameter.issuer.token_endpoint,\n userinfo_endpoint: configParameter.issuer.userinfo_endpoint,\n });\n\n const client = new issuer.Client({\n client_id: configParameter.client_id,\n client_secret: configParameter.client_secret,\n redirect_uri: new URL(\n '/openid/callback',\n configParameter.server_hostname,\n ).toString(),\n validate_id_token: true,\n });\n\n return client;\n}\n\nexport async function loginWithOpenIdSetup(\n returnUrl,\n firstTimeLoginPassword = '',\n) {\n if (!returnUrl) {\n return { error: 'return-url-missing' };\n }\n if (!isValidRedirectUrl(returnUrl)) {\n return { error: 'invalid-return-url' };\n }\n\n const accountDb = getAccountDb();\n\n const { countUsersWithUserName } = accountDb.first(\n 'SELECT count(*) as countUsersWithUserName FROM users WHERE user_name <> ?',\n [''],\n );\n if (countUsersWithUserName === 0) {\n const methods = listLoginMethods();\n if (methods.some(authMethod => authMethod.method === 'password')) {\n const valid = checkPassword(firstTimeLoginPassword);\n\n if (!valid) {\n return { error: 'invalid-password' };\n }\n }\n }\n\n let config = accountDb.first('SELECT extra_data FROM auth WHERE method = ?', [\n 'openid',\n ]);\n if (!config) {\n return { error: 'openid-not-configured' };\n }\n\n try {\n config = JSON.parse(config['extra_data']);\n } catch (err) {\n console.error('Error parsing OpenID configuration:', err);\n return { error: 'openid-setup-failed' };\n }\n\n let client;\n try {\n client = await setupOpenIdClient(config);\n } catch (err) {\n console.error('Error setting up OpenID client:', err);\n return { error: 'openid-setup-failed' };\n }\n\n const state = generators.state();\n const code_verifier = generators.codeVerifier();\n const code_challenge = generators.codeChallenge(code_verifier);\n\n const now_time = Date.now();\n const expiry_time = now_time + 300 * 1000;\n\n accountDb.mutate(\n 'DELETE FROM pending_openid_requests WHERE expiry_time < ?',\n [now_time],\n );\n accountDb.mutate(\n 'INSERT INTO pending_openid_requests (state, code_verifier, return_url, expiry_time) VALUES (?, ?, ?, ?)',\n [state, code_verifier, returnUrl, expiry_time],\n );\n\n const url = client.authorizationUrl({\n response_type: 'code',\n scope: 'openid email profile',\n state,\n code_challenge,\n code_challenge_method: 'S256',\n });\n\n return { url };\n}\n\nexport async function loginWithOpenIdFinalize(body) {\n if (!body.code) {\n return { error: 'missing-authorization-code' };\n }\n if (!body.state) {\n return { error: 'missing-state' };\n }\n\n const accountDb = getAccountDb();\n let configFromDb = accountDb.first(\n \"SELECT extra_data FROM auth WHERE method = 'openid' AND active = 1\",\n );\n if (!configFromDb) {\n return { error: 'openid-not-configured' };\n }\n try {\n configFromDb = JSON.parse(configFromDb['extra_data']);\n } catch (err) {\n console.error('Error parsing OpenID configuration:', err);\n return { error: 'openid-setup-failed' };\n }\n let client;\n try {\n client = await setupOpenIdClient(configFromDb);\n } catch (err) {\n console.error('Error setting up OpenID client:', err);\n return { error: 'openid-setup-failed' };\n }\n\n const pendingRequest = accountDb.first(\n 'SELECT code_verifier, return_url FROM pending_openid_requests WHERE state = ? AND expiry_time > ?',\n [body.state, Date.now()],\n );\n\n if (!pendingRequest) {\n return { error: 'invalid-or-expired-state' };\n }\n\n const { code_verifier, return_url } = pendingRequest;\n\n try {\n let tokenSet = null;\n\n if (!configFromDb.authMethod || configFromDb.authMethod === 'openid') {\n const params = { code: body.code, state: body.state, iss: body.iss };\n tokenSet = await client.callback(client.redirect_uris[0], params, {\n code_verifier,\n state: body.state,\n });\n } else {\n tokenSet = await client.grant({\n grant_type: 'authorization_code',\n code: body.code,\n redirect_uri: client.redirect_uris[0],\n code_verifier,\n });\n }\n const userInfo = await client.userinfo(tokenSet.access_token);\n const identity =\n userInfo.preferred_username ??\n userInfo.login ??\n userInfo.email ??\n userInfo.id ??\n userInfo.sub;\n\n if (identity == null) {\n return { error: 'openid-grant-failed: no identification was found' };\n }\n\n let userId = null;\n try {\n accountDb.transaction(() => {\n const { countUsersWithUserName } = accountDb.first(\n 'SELECT count(*) as countUsersWithUserName FROM users WHERE user_name <> ?',\n [''],\n );\n\n // Check if user was created by another transaction\n const existingUser = accountDb.first(\n 'SELECT id FROM users WHERE user_name = ?',\n [identity],\n );\n\n if (\n !existingUser &&\n (countUsersWithUserName === 0 ||\n config.get('userCreationMode') === 'login')\n ) {\n userId = uuidv4();\n accountDb.mutate(\n 'INSERT INTO users (id, user_name, display_name, enabled, owner, role) VALUES (?, ?, ?, 1, ?, ?)',\n [\n userId,\n identity,\n userInfo.name ?? userInfo.email ?? identity,\n countUsersWithUserName === 0 ? '1' : '0',\n countUsersWithUserName === 0 ? 'ADMIN' : 'BASIC',\n ],\n );\n\n if (countUsersWithUserName === 0) {\n const userFromPasswordMethod = getUserByUsername('');\n if (userFromPasswordMethod) {\n transferAllFilesFromUser(userId, userFromPasswordMethod.user_id);\n }\n }\n } else {\n const { id: userIdFromDb, display_name: displayName } =\n accountDb.first(\n 'SELECT id, display_name FROM users WHERE user_name = ? and enabled = 1',\n [identity],\n ) || {};\n\n if (userIdFromDb == null) {\n throw new Error('openid-grant-failed');\n }\n\n if (!displayName && userInfo.name) {\n accountDb.mutate('UPDATE users set display_name = ? WHERE id = ?', [\n userInfo.name,\n userIdFromDb,\n ]);\n }\n\n userId = userIdFromDb;\n }\n });\n } catch (error) {\n if (error.message === 'user-already-exists') {\n return { error: 'user-already-exists' };\n } else if (error.message === 'openid-grant-failed') {\n return { error: 'openid-grant-failed' };\n } else {\n throw error; // Re-throw other unexpected errors\n }\n }\n\n const token = uuidv4();\n\n let expiration;\n if (config.get('token_expiration') === 'openid-provider') {\n expiration = tokenSet.expires_at ?? TOKEN_EXPIRATION_NEVER;\n } else if (config.get('token_expiration') === 'never') {\n expiration = TOKEN_EXPIRATION_NEVER;\n } else if (typeof config.get('token_expiration') === 'number') {\n expiration =\n Math.floor(Date.now() / 1000) + config.get('token_expiration');\n } else {\n expiration = Math.floor(Date.now() / 1000) + 10 * 60; // Default to 10 minutes\n }\n\n accountDb.mutate(\n 'INSERT INTO sessions (token, expires_at, user_id, auth_method) VALUES (?, ?, ?, ?)',\n [token, expiration, userId, 'openid'],\n );\n\n clearExpiredSessions();\n\n return { url: `${return_url}/openid-cb?token=${token}` };\n } catch (err) {\n console.error('OpenID grant failed:', err);\n return { error: 'openid-grant-failed' };\n }\n}\n\nexport function getServerHostname() {\n const auth = getAccountDb().first(\n 'select * from auth WHERE method = ? and active = 1',\n ['openid'],\n );\n if (auth && auth.extra_data) {\n try {\n const openIdConfig = JSON.parse(auth.extra_data);\n return openIdConfig.server_hostname;\n } catch (error) {\n console.error('Error parsing OpenID configuration:', error);\n }\n }\n return null;\n}\n\nexport function isValidRedirectUrl(url: string | undefined): url is string {\n const serverHostname = getServerHostname();\n\n if (!serverHostname) {\n return false;\n }\n\n try {\n const redirectUrl = new URL(url);\n const serverUrl = new URL(serverHostname);\n\n if (\n redirectUrl.hostname === serverUrl.hostname ||\n redirectUrl.hostname === 'localhost'\n ) {\n return true;\n } else {\n return false;\n }\n } catch {\n return false;\n }\n}\n","import Database from 'better-sqlite3';\n\nexport class WrappedDatabase {\n constructor(db) {\n this.db = db;\n }\n\n /**\n * @param {string} sql\n * @param {(string | number)[]} params\n */\n all(sql, params = []) {\n const stmt = this.db.prepare(sql);\n return stmt.all(...params);\n }\n\n /**\n * @param {string} sql\n * @param {string[]} params\n */\n first(sql, params = []) {\n const rows = this.all(sql, params);\n return rows.length === 0 ? null : rows[0];\n }\n\n /**\n * @param {string} sql\n */\n exec(sql) {\n return this.db.exec(sql);\n }\n\n /**\n * @param {string} sql\n * @param {(string | number | null | undefined)[]} params\n */\n mutate(sql, params = []) {\n const stmt = this.db.prepare(sql);\n const info = stmt.run(...params);\n return { changes: info.changes, insertId: info.lastInsertRowid };\n }\n\n /**\n * @param {() => void} fn\n */\n transaction(fn) {\n return this.db.transaction(fn)();\n }\n\n close() {\n this.db.close();\n }\n}\n\n/** @param {string} filename */\nexport function openDatabase(filename) {\n return new WrappedDatabase(new Database(filename));\n}\n","import { join, resolve } from 'node:path';\n\nimport * as bcrypt from 'bcrypt';\n\nimport { bootstrapOpenId } from './accounts/openid';\nimport { bootstrapPassword, loginWithPassword } from './accounts/password';\nimport { openDatabase } from './db';\nimport { config } from './load-config';\n\nlet _accountDb;\n\nexport function getAccountDb() {\n if (_accountDb === undefined) {\n const dbPath = join(resolve(config.get('serverFiles')), 'account.sqlite');\n _accountDb = openDatabase(dbPath);\n }\n\n return _accountDb;\n}\n\nexport function needsBootstrap() {\n const accountDb = getAccountDb();\n const rows = accountDb.all('SELECT * FROM auth');\n return rows.length === 0;\n}\n\nexport function listLoginMethods() {\n const accountDb = getAccountDb();\n const rows = accountDb.all('SELECT method, display_name, active FROM auth');\n return rows\n .filter(f =>\n rows.length > 1 && config.get('enforceOpenId')\n ? f.method === 'openid'\n : true,\n )\n .map(r => ({\n method: r.method,\n active: r.active,\n displayName: r.display_name,\n }));\n}\n\nexport function getActiveLoginMethod() {\n const accountDb = getAccountDb();\n const { method } =\n accountDb.first('SELECT method FROM auth WHERE active = 1') || {};\n return method;\n}\n\n/*\n * Get the Login Method in the following order\n * req (the frontend can say which method in the case it wants to resort to forcing password auth)\n * config options\n * fall back to using password\n */\nexport function getLoginMethod(req) {\n if (\n typeof req !== 'undefined' &&\n (req.body || { loginMethod: null }).loginMethod &&\n config.get('allowedLoginMethods').includes(req.body.loginMethod)\n ) {\n const accountDb = getAccountDb();\n const row = accountDb.first('SELECT method FROM auth WHERE method = ?', [\n req.body.loginMethod,\n ]);\n if (row) return req.body.loginMethod;\n }\n\n //BY-PASS ANY OTHER CONFIGURATION TO ENSURE HEADER AUTH\n if (\n config.get('loginMethod') === 'header' &&\n config.get('allowedLoginMethods').includes('header')\n ) {\n return config.get('loginMethod');\n }\n\n const activeMethod = getActiveLoginMethod();\n return activeMethod || config.get('loginMethod');\n}\n\nexport async function bootstrap(loginSettings, forced = false) {\n if (!loginSettings) {\n return { error: 'invalid-login-settings' };\n }\n const passEnabled = 'password' in loginSettings;\n const openIdEnabled = 'openId' in loginSettings;\n\n const accountDb = getAccountDb();\n accountDb.mutate('BEGIN TRANSACTION');\n try {\n const { countOfOwner } =\n accountDb.first(\n `SELECT count(*) as countOfOwner\n FROM users\n WHERE users.user_name <> '' and users.owner = 1`,\n ) || {};\n\n if (!forced && (!openIdEnabled || countOfOwner > 0)) {\n if (!needsBootstrap()) {\n accountDb.mutate('ROLLBACK');\n return { error: 'already-bootstrapped' };\n }\n }\n\n if (!passEnabled && !openIdEnabled) {\n accountDb.mutate('ROLLBACK');\n return { error: 'no-auth-method-selected' };\n }\n\n if (passEnabled && openIdEnabled && !forced) {\n accountDb.mutate('ROLLBACK');\n return { error: 'max-one-method-allowed' };\n }\n\n if (passEnabled) {\n const { error } = bootstrapPassword(loginSettings.password);\n if (error) {\n accountDb.mutate('ROLLBACK');\n return { error };\n }\n }\n\n if (openIdEnabled && forced) {\n const { error } = await bootstrapOpenId(loginSettings.openId);\n if (error) {\n accountDb.mutate('ROLLBACK');\n return { error };\n }\n }\n\n accountDb.mutate('COMMIT');\n return passEnabled ? loginWithPassword(loginSettings.password) : {};\n } catch (error) {\n accountDb.mutate('ROLLBACK');\n throw error;\n }\n}\n\nexport function isAdmin(userId) {\n return hasPermission(userId, 'ADMIN');\n}\n\nexport function hasPermission(userId, permission) {\n return getUserPermission(userId) === permission;\n}\n\nexport async function enableOpenID(loginSettings) {\n if (!loginSettings || !loginSettings.openId) {\n return { error: 'invalid-login-settings' };\n }\n\n const { error } = (await bootstrapOpenId(loginSettings.openId)) || {};\n if (error) {\n return { error };\n }\n\n getAccountDb().mutate('DELETE FROM sessions');\n}\n\nexport async function disableOpenID(loginSettings) {\n if (!loginSettings || !loginSettings.password) {\n return { error: 'invalid-login-settings' };\n }\n\n const accountDb = getAccountDb();\n const { extra_data: passwordHash } =\n accountDb.first('SELECT extra_data FROM auth WHERE method = ?', [\n 'password',\n ]) || {};\n\n if (!passwordHash) {\n return { error: 'invalid-password' };\n }\n\n if (!loginSettings?.password) {\n return { error: 'invalid-password' };\n }\n\n const confirmed = bcrypt.compareSync(loginSettings.password, passwordHash);\n\n if (!confirmed) {\n return { error: 'invalid-password' };\n }\n\n const { error } = bootstrapPassword(loginSettings.password);\n if (error) {\n return { error };\n }\n\n try {\n accountDb.transaction(() => {\n accountDb.mutate('DELETE FROM sessions');\n accountDb.mutate(\n `DELETE FROM user_access\n WHERE user_access.user_id IN (\n SELECT users.id\n FROM users\n WHERE users.user_name <> ?\n );`,\n [''],\n );\n accountDb.mutate('DELETE FROM users WHERE user_name <> ?', ['']);\n accountDb.mutate('DELETE FROM auth WHERE method = ?', ['openid']);\n });\n } catch (err) {\n console.error('Error cleaning up openid information:', err);\n return { error: 'database-error' };\n }\n}\n\nexport function getSession(token) {\n const accountDb = getAccountDb();\n return accountDb.first(\n `SELECT sessions.*\n FROM sessions\n JOIN users ON users.id = sessions.user_id\n WHERE sessions.token = ? AND users.enabled = 1`,\n [token],\n );\n}\n\nexport function getUserInfo(userId) {\n const accountDb = getAccountDb();\n return accountDb.first('SELECT * FROM users WHERE id = ?', [userId]);\n}\n\nexport function getUserPermission(userId) {\n const accountDb = getAccountDb();\n const { role } = accountDb.first(\n `SELECT role FROM users\n WHERE users.id = ?`,\n [userId],\n ) || { role: '' };\n\n return role;\n}\n\nexport function getServerPrefs() {\n const accountDb = getAccountDb();\n const rows = accountDb.all('SELECT key, value FROM server_prefs') || [];\n\n return rows.reduce((prefs, row) => {\n prefs[row.key] = row.value;\n return prefs;\n }, {});\n}\n\nexport function setServerPrefs(prefs) {\n const accountDb = getAccountDb();\n\n if (!prefs) {\n return;\n }\n\n accountDb.transaction(() => {\n Object.entries(prefs).forEach(([key, value]) => {\n accountDb.mutate(\n 'INSERT INTO server_prefs (key, value) VALUES (?, ?) ON CONFLICT (key) DO UPDATE SET value = excluded.value',\n [key, value],\n );\n });\n });\n}\n\nexport function clearExpiredSessions() {\n const clearThreshold = Math.floor(Date.now() / 1000) - 3600;\n\n const deletedSessions = getAccountDb().mutate(\n 'DELETE FROM sessions WHERE expires_at <> -1 and expires_at < ?',\n [clearThreshold],\n ).changes;\n\n console.log(`Deleted ${deletedSessions} old sessions`);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"account-db-HkRNud0e.js","names":["uuidv4","config","config"],"sources":["../../src/services/user-service.ts","../../src/util/validate-user.ts","../../src/accounts/password.js","../../src/accounts/openid.ts","../../src/db.js","../../src/account-db.js"],"sourcesContent":["// @ts-strict-ignore\nimport { getAccountDb } from '#account-db';\n\nexport function getUserByUsername(userName) {\n if (!userName || typeof userName !== 'string') {\n return null;\n }\n const { id } =\n getAccountDb().first('SELECT id FROM users WHERE user_name = ?', [\n userName,\n ]) || {};\n return id || null;\n}\n\nexport function getUserById(userId) {\n if (!userId) {\n return null;\n }\n const { id } =\n getAccountDb().first('SELECT * FROM users WHERE id = ?', [userId]) || {};\n return id || null;\n}\n\nexport function getFileById(fileId) {\n if (!fileId) {\n return null;\n }\n const { id } =\n getAccountDb().first('SELECT * FROM files WHERE files.id = ?', [fileId]) ||\n {};\n return id || null;\n}\n\nexport function validateRole(roleId) {\n const possibleRoles = ['BASIC', 'ADMIN'];\n return possibleRoles.some(a => a === roleId);\n}\n\nexport function getOwnerCount(): number {\n const { ownerCount } = getAccountDb().first(\n `SELECT count(*) as ownerCount FROM users WHERE users.user_name <> '' and users.owner = 1`,\n ) || { ownerCount: 0 };\n return ownerCount;\n}\n\nexport function getOwnerId() {\n const { id } =\n getAccountDb().first(\n `SELECT users.id FROM users WHERE users.user_name <> '' and users.owner = 1`,\n ) || {};\n return id;\n}\n\nexport function getAllUsers() {\n return getAccountDb().all(\n `SELECT users.id, user_name as userName, display_name as displayName, enabled, ifnull(owner,0) as owner, role\n FROM users\n WHERE users.user_name <> ''`,\n );\n}\n\nexport function insertUser(userId, userName, displayName, enabled, role) {\n getAccountDb().mutate(\n 'INSERT INTO users (id, user_name, display_name, enabled, owner, role) VALUES (?, ?, ?, ?, 0, ?)',\n [userId, userName, displayName, enabled, role],\n );\n}\n\nexport function updateUserWithRole(\n userId,\n userName,\n displayName,\n enabled,\n roleId,\n) {\n getAccountDb().transaction(() => {\n getAccountDb().mutate(\n 'UPDATE users SET user_name = ?, display_name = ?, enabled = ?, role = ? WHERE id = ?',\n [userName, displayName, enabled, roleId, userId],\n );\n if (!enabled) {\n getAccountDb().mutate('DELETE FROM sessions WHERE user_id = ?', [userId]);\n }\n });\n}\n\nexport function deleteUser(userId) {\n return getAccountDb().transaction(() => {\n const { changes } = getAccountDb().mutate(\n 'DELETE FROM users WHERE id = ? and owner = 0',\n [userId],\n );\n if (changes > 0) {\n getAccountDb().mutate('DELETE FROM sessions WHERE user_id = ?', [userId]);\n }\n return changes;\n });\n}\nexport function deleteUserAccess(userId) {\n try {\n return getAccountDb().mutate('DELETE FROM user_access WHERE user_id = ?', [\n userId,\n ]).changes;\n } catch (error) {\n throw new Error(`Failed to delete user access: ${error.message}`);\n }\n}\n\nexport function transferAllFilesFromUser(ownerId, oldUserId) {\n if (!ownerId || !oldUserId) {\n throw new Error('Invalid user IDs');\n }\n try {\n getAccountDb().transaction(() => {\n const ownerExists = getUserById(ownerId);\n if (!ownerExists) {\n throw new Error('New owner not found');\n }\n getAccountDb().mutate('UPDATE files set owner = ? WHERE owner = ?', [\n ownerId,\n oldUserId,\n ]);\n });\n } catch (error) {\n throw new Error(`Failed to transfer files: ${error.message}`);\n }\n}\n\nexport function updateFileOwner(ownerId, fileId) {\n if (!ownerId || !fileId) {\n throw new Error('Invalid parameters');\n }\n try {\n const result = getAccountDb().mutate(\n 'UPDATE files set owner = ? WHERE id = ?',\n [ownerId, fileId],\n );\n if (result.changes === 0) {\n throw new Error('File not found');\n }\n } catch (error) {\n throw new Error(`Failed to update file owner: ${error.message}`);\n }\n}\n\nexport function getUserAccess(fileId, userId, isAdmin) {\n return getAccountDb().all(\n `SELECT users.id as userId, user_name as userName, files.owner, display_name as displayName\n FROM users\n JOIN user_access ON user_access.user_id = users.id\n JOIN files ON files.id = user_access.file_id\n WHERE files.id = ? and (files.owner = ? OR 1 = ?)`,\n [fileId, userId, isAdmin ? 1 : 0],\n );\n}\n\nexport function countUserAccess(fileId, userId) {\n const { accessCount } =\n getAccountDb().first(\n `SELECT COUNT(*) as accessCount\n FROM files\n WHERE files.id = ? AND (files.owner = ? OR EXISTS (\n SELECT 1 FROM user_access\n WHERE user_access.user_id = ? AND user_access.file_id = ?)\n )`,\n [fileId, userId, userId, fileId],\n ) || {};\n\n return accessCount || 0;\n}\n\nexport function checkFilePermission(fileId, userId) {\n return (\n getAccountDb().first(\n `SELECT 1 as granted\n FROM files\n WHERE files.id = ? and (files.owner = ?)`,\n [fileId, userId],\n ) || { granted: 0 }\n );\n}\n\nexport function addUserAccess(userId, fileId) {\n if (!userId || !fileId) {\n throw new Error('Invalid parameters');\n }\n try {\n const userExists = getUserById(userId);\n const fileExists = getFileById(fileId);\n if (!userExists || !fileExists) {\n throw new Error('User or file not found');\n }\n getAccountDb().mutate(\n 'INSERT INTO user_access (user_id, file_id) VALUES (?, ?)',\n [userId, fileId],\n );\n } catch (error) {\n if (error.message.includes('UNIQUE constraint')) {\n throw new Error('Access already exists');\n }\n throw new Error(`Failed to add user access: ${error.message}`);\n }\n}\n\nexport function deleteUserAccessByFileId(userIds, fileId) {\n if (!Array.isArray(userIds) || userIds.length === 0) {\n throw new Error('The provided userIds must be a non-empty array.');\n }\n\n const CHUNK_SIZE = 999;\n let totalChanges = 0;\n\n try {\n getAccountDb().transaction(() => {\n for (let i = 0; i < userIds.length; i += CHUNK_SIZE) {\n const chunk = userIds.slice(i, i + CHUNK_SIZE);\n const placeholders = chunk.map(() => '?').join(',');\n\n const sql = `DELETE FROM user_access WHERE user_id IN (${placeholders}) AND file_id = ?`;\n\n const result = getAccountDb().mutate(sql, [...chunk, fileId]);\n totalChanges += result.changes;\n }\n });\n } catch (error) {\n throw new Error(`Failed to delete user access: ${error.message}`);\n }\n\n return totalChanges;\n}\n\nexport function getAllUserAccess(fileId) {\n //This can't be used here until we can create user invite links:\n //const isLoginMode = config.get('userCreationMode') === 'login';\n const isLoginMode = false;\n const joinType = isLoginMode ? 'JOIN' : 'LEFT JOIN';\n\n return getAccountDb().all(\n `\n SELECT\n users.id as userId,\n user_name as userName,\n display_name as displayName,\n CASE WHEN user_access.file_id IS NULL THEN 0 ELSE 1 END as haveAccess,\n CASE WHEN files.id IS NULL THEN 0 ELSE 1 END as owner\n FROM users\n ${joinType} user_access ON user_access.file_id = ? AND user_access.user_id = users.id\n ${joinType} files ON files.id = ? AND files.owner = users.id\n WHERE users.enabled = 1\n AND users.user_name <> ''\n `,\n [fileId, fileId],\n );\n}\n\nexport function getOpenIDConfig() {\n return (\n getAccountDb().first(`SELECT * FROM auth WHERE method = ?`, ['openid']) ||\n null\n );\n}\n","import type { Request, Response } from 'express';\nimport ipaddr from 'ipaddr.js';\n\nimport { getSession } from '#account-db';\nimport { config } from '#load-config';\n\nexport const TOKEN_EXPIRATION_NEVER = -1;\nconst MS_PER_SECOND = 1000;\n\nexport function validateSession(req: Request, res: Response) {\n let { token } = req.body || {};\n\n if (!token) {\n token = req.headers['x-actual-token'];\n }\n\n const session = getSession(token);\n\n if (!session) {\n res.status(401);\n res.send({\n status: 'error',\n reason: 'unauthorized',\n details: 'token-not-found',\n });\n return null;\n }\n\n if (\n session.expires_at !== TOKEN_EXPIRATION_NEVER &&\n session.expires_at * MS_PER_SECOND <= Date.now()\n ) {\n res.status(401);\n res.send({\n status: 'error',\n reason: 'token-expired',\n });\n return null;\n }\n\n return session;\n}\n\nexport function validateAuthHeader(req: Request) {\n // fallback to trustedProxies when trustedAuthProxies not set\n const trustedAuthProxies: string[] =\n config.get('trustedAuthProxies') ?? config.get('trustedProxies');\n // ensure the first hop from our server is trusted\n const peer = req.socket.remoteAddress;\n if (peer === undefined) {\n console.error(`Header Auth Login attempted but there was no defined peer.`);\n return false;\n }\n const peerIp = ipaddr.process(peer);\n const rangeList = {\n allowed_ips: trustedAuthProxies.map(q => ipaddr.parseCIDR(q)),\n };\n\n const matched = ipaddr.subnetMatch(peerIp, rangeList, 'fail');\n\n if (matched === 'allowed_ips') {\n console.info(`Header Auth Login permitted from ${peer}`);\n return true;\n } else {\n console.warn(`Header Auth Login attempted from ${peer}`);\n return false;\n }\n}\n","import * as bcrypt from 'bcrypt';\nimport { v4 as uuidv4 } from 'uuid';\n\nimport { clearExpiredSessions, getAccountDb } from '#account-db';\nimport { config } from '#load-config';\nimport { TOKEN_EXPIRATION_NEVER } from '#util/validate-user';\n\nfunction isValidPassword(password) {\n return password != null && password !== '';\n}\n\nfunction hashPassword(password) {\n return bcrypt.hashSync(password, 12);\n}\n\nexport function bootstrapPassword(password) {\n if (!isValidPassword(password)) {\n return { error: 'invalid-password' };\n }\n\n const hashed = hashPassword(password);\n const accountDb = getAccountDb();\n accountDb.transaction(() => {\n accountDb.mutate('DELETE FROM auth WHERE method = ?', ['password']);\n accountDb.mutate('UPDATE auth SET active = 0');\n accountDb.mutate(\n \"INSERT INTO auth (method, display_name, extra_data, active) VALUES ('password', 'Password', ?, 1)\",\n [hashed],\n );\n });\n\n return {};\n}\n\nexport function loginWithPassword(password) {\n if (!isValidPassword(password)) {\n return { error: 'invalid-password' };\n }\n\n const accountDb = getAccountDb();\n const { extra_data: passwordHash } =\n accountDb.first('SELECT extra_data FROM auth WHERE method = ?', [\n 'password',\n ]) || {};\n\n if (!passwordHash) {\n return { error: 'invalid-password' };\n }\n\n const confirmed = bcrypt.compareSync(password, passwordHash);\n\n if (!confirmed) {\n return { error: 'invalid-password' };\n }\n\n const sessionRow = accountDb.first(\n 'SELECT * FROM sessions WHERE auth_method = ?',\n ['password'],\n );\n\n const token = sessionRow ? sessionRow.token : uuidv4();\n\n const { totalOfUsers } = accountDb.first(\n 'SELECT count(*) as totalOfUsers FROM users',\n );\n let userId = null;\n if (totalOfUsers === 0) {\n userId = uuidv4();\n accountDb.mutate(\n 'INSERT INTO users (id, user_name, display_name, enabled, owner, role) VALUES (?, ?, ?, 1, 1, ?)',\n [userId, '', '', 'ADMIN'],\n );\n } else {\n const { id: userIdFromDb } = accountDb.first(\n 'SELECT id FROM users WHERE user_name = ?',\n [''],\n );\n\n userId = userIdFromDb;\n\n if (!userId) {\n return { error: 'user-not-found' };\n }\n }\n\n let expiration = TOKEN_EXPIRATION_NEVER;\n if (\n config.get('token_expiration') !== 'never' &&\n config.get('token_expiration') !== 'openid-provider' &&\n typeof config.get('token_expiration') === 'number'\n ) {\n expiration =\n Math.floor(Date.now() / 1000) + config.get('token_expiration') * 60;\n }\n\n if (!sessionRow) {\n accountDb.mutate(\n 'INSERT INTO sessions (token, expires_at, user_id, auth_method) VALUES (?, ?, ?, ?)',\n [token, expiration, userId, 'password'],\n );\n } else {\n accountDb.mutate(\n 'UPDATE sessions SET user_id = ?, expires_at = ? WHERE token = ?',\n [userId, expiration, token],\n );\n }\n\n clearExpiredSessions();\n\n return { token };\n}\n\nexport function changePassword(newPassword) {\n const accountDb = getAccountDb();\n\n if (!isValidPassword(newPassword)) {\n return { error: 'invalid-password' };\n }\n\n const hashed = hashPassword(newPassword);\n accountDb.mutate(\"UPDATE auth SET extra_data = ? WHERE method = 'password'\", [\n hashed,\n ]);\n return {};\n}\n\nexport function checkPassword(password) {\n if (!isValidPassword(password)) {\n return false;\n }\n\n const accountDb = getAccountDb();\n const { extra_data: passwordHash } =\n accountDb.first('SELECT extra_data FROM auth WHERE method = ?', [\n 'password',\n ]) || {};\n\n if (!passwordHash) {\n return false;\n }\n\n const confirmed = bcrypt.compareSync(password, passwordHash);\n\n if (!confirmed) {\n return false;\n }\n\n return true;\n}\n","// @ts-strict-ignore\nimport { custom, generators, Issuer } from 'openid-client';\nimport { v4 as uuidv4 } from 'uuid';\n\nimport {\n clearExpiredSessions,\n getAccountDb,\n listLoginMethods,\n} from '#account-db';\nimport { config } from '#load-config';\nimport {\n getUserByUsername,\n transferAllFilesFromUser,\n} from '#services/user-service';\nimport { TOKEN_EXPIRATION_NEVER } from '#util/validate-user';\n\nimport { checkPassword } from './password';\n\nexport type ConfigParameter = {\n issuer?: string;\n discoveryURL?: string;\n client_id?: string;\n client_secret?: string;\n server_hostname?: string;\n};\n\nexport async function bootstrapOpenId(configParameter: ConfigParameter) {\n if (!('issuer' in configParameter) && !('discoveryURL' in configParameter)) {\n return { error: 'missing-issuer-or-discoveryURL' };\n }\n if (!('client_id' in configParameter)) {\n return { error: 'missing-client-id' };\n }\n if (!('client_secret' in configParameter)) {\n return { error: 'missing-client-secret' };\n }\n if (!('server_hostname' in configParameter)) {\n return { error: 'missing-server-hostname' };\n }\n\n custom.setHttpOptionsDefaults({\n timeout: 20 * 1000, // 20 seconds\n });\n\n try {\n //FOR BACKWARD COMPATIBLITY:\n //If we don't put discoverURL into the issuer, it will break already enabled openid instances\n if (configParameter.discoveryURL) {\n configParameter.issuer = configParameter.discoveryURL;\n delete configParameter.discoveryURL;\n }\n\n await setupOpenIdClient(configParameter);\n } catch (err) {\n console.error('Error setting up OpenID client:', err);\n return { error: 'configuration-error' };\n }\n\n const accountDb = getAccountDb();\n try {\n accountDb.transaction(() => {\n accountDb.mutate('DELETE FROM auth WHERE method = ?', ['openid']);\n accountDb.mutate('UPDATE auth SET active = 0');\n accountDb.mutate(\n \"INSERT INTO auth (method, display_name, extra_data, active) VALUES ('openid', 'OpenID', ?, 1)\",\n [JSON.stringify(configParameter)],\n );\n });\n } catch (err) {\n console.error('Error updating auth table:', err);\n return { error: 'database-error' };\n }\n\n return {};\n}\n\nasync function setupOpenIdClient(configParameter) {\n const issuer =\n typeof configParameter.issuer === 'string'\n ? await Issuer.discover(configParameter.issuer)\n : new Issuer({\n issuer: configParameter.issuer.name,\n authorization_endpoint: configParameter.issuer.authorization_endpoint,\n token_endpoint: configParameter.issuer.token_endpoint,\n userinfo_endpoint: configParameter.issuer.userinfo_endpoint,\n });\n\n const client = new issuer.Client({\n client_id: configParameter.client_id,\n client_secret: configParameter.client_secret,\n redirect_uri: new URL(\n '/openid/callback',\n configParameter.server_hostname,\n ).toString(),\n validate_id_token: true,\n });\n\n return client;\n}\n\nexport async function loginWithOpenIdSetup(\n returnUrl,\n firstTimeLoginPassword = '',\n) {\n if (!returnUrl) {\n return { error: 'return-url-missing' };\n }\n if (!isValidRedirectUrl(returnUrl)) {\n return { error: 'invalid-return-url' };\n }\n\n const accountDb = getAccountDb();\n\n const { countUsersWithUserName } = accountDb.first(\n 'SELECT count(*) as countUsersWithUserName FROM users WHERE user_name <> ?',\n [''],\n );\n if (countUsersWithUserName === 0) {\n const methods = listLoginMethods();\n if (methods.some(authMethod => authMethod.method === 'password')) {\n const valid = checkPassword(firstTimeLoginPassword);\n\n if (!valid) {\n return { error: 'invalid-password' };\n }\n }\n }\n\n let config = accountDb.first('SELECT extra_data FROM auth WHERE method = ?', [\n 'openid',\n ]);\n if (!config) {\n return { error: 'openid-not-configured' };\n }\n\n try {\n config = JSON.parse(config['extra_data']);\n } catch (err) {\n console.error('Error parsing OpenID configuration:', err);\n return { error: 'openid-setup-failed' };\n }\n\n let client;\n try {\n client = await setupOpenIdClient(config);\n } catch (err) {\n console.error('Error setting up OpenID client:', err);\n return { error: 'openid-setup-failed' };\n }\n\n const state = generators.state();\n const code_verifier = generators.codeVerifier();\n const code_challenge = generators.codeChallenge(code_verifier);\n\n const now_time = Date.now();\n const expiry_time = now_time + 300 * 1000;\n\n accountDb.mutate(\n 'DELETE FROM pending_openid_requests WHERE expiry_time < ?',\n [now_time],\n );\n accountDb.mutate(\n 'INSERT INTO pending_openid_requests (state, code_verifier, return_url, expiry_time) VALUES (?, ?, ?, ?)',\n [state, code_verifier, returnUrl, expiry_time],\n );\n\n const url = client.authorizationUrl({\n response_type: 'code',\n scope: 'openid email profile',\n state,\n code_challenge,\n code_challenge_method: 'S256',\n });\n\n return { url };\n}\n\nexport async function loginWithOpenIdFinalize(body) {\n if (!body.code) {\n return { error: 'missing-authorization-code' };\n }\n if (!body.state) {\n return { error: 'missing-state' };\n }\n\n const accountDb = getAccountDb();\n let configFromDb = accountDb.first(\n \"SELECT extra_data FROM auth WHERE method = 'openid' AND active = 1\",\n );\n if (!configFromDb) {\n return { error: 'openid-not-configured' };\n }\n try {\n configFromDb = JSON.parse(configFromDb['extra_data']);\n } catch (err) {\n console.error('Error parsing OpenID configuration:', err);\n return { error: 'openid-setup-failed' };\n }\n let client;\n try {\n client = await setupOpenIdClient(configFromDb);\n } catch (err) {\n console.error('Error setting up OpenID client:', err);\n return { error: 'openid-setup-failed' };\n }\n\n const pendingRequest = accountDb.first(\n 'SELECT code_verifier, return_url FROM pending_openid_requests WHERE state = ? AND expiry_time > ?',\n [body.state, Date.now()],\n );\n\n if (!pendingRequest) {\n return { error: 'invalid-or-expired-state' };\n }\n\n const { code_verifier, return_url } = pendingRequest;\n\n try {\n let tokenSet = null;\n\n if (!configFromDb.authMethod || configFromDb.authMethod === 'openid') {\n const params = { code: body.code, state: body.state, iss: body.iss };\n tokenSet = await client.callback(client.redirect_uris[0], params, {\n code_verifier,\n state: body.state,\n });\n } else {\n tokenSet = await client.grant({\n grant_type: 'authorization_code',\n code: body.code,\n redirect_uri: client.redirect_uris[0],\n code_verifier,\n });\n }\n const userInfo = await client.userinfo(tokenSet.access_token);\n const identity =\n userInfo.preferred_username ??\n userInfo.login ??\n userInfo.email ??\n userInfo.id ??\n userInfo.sub;\n\n if (identity == null) {\n return { error: 'openid-grant-failed: no identification was found' };\n }\n\n let userId = null;\n try {\n accountDb.transaction(() => {\n const { countUsersWithUserName } = accountDb.first(\n 'SELECT count(*) as countUsersWithUserName FROM users WHERE user_name <> ?',\n [''],\n );\n\n // Check if user was created by another transaction\n const existingUser = accountDb.first(\n 'SELECT id FROM users WHERE user_name = ?',\n [identity],\n );\n\n if (\n !existingUser &&\n (countUsersWithUserName === 0 ||\n config.get('userCreationMode') === 'login')\n ) {\n userId = uuidv4();\n accountDb.mutate(\n 'INSERT INTO users (id, user_name, display_name, enabled, owner, role) VALUES (?, ?, ?, 1, ?, ?)',\n [\n userId,\n identity,\n userInfo.name ?? userInfo.email ?? identity,\n countUsersWithUserName === 0 ? '1' : '0',\n countUsersWithUserName === 0 ? 'ADMIN' : 'BASIC',\n ],\n );\n\n if (countUsersWithUserName === 0) {\n const userFromPasswordMethod = getUserByUsername('');\n if (userFromPasswordMethod) {\n transferAllFilesFromUser(userId, userFromPasswordMethod.user_id);\n }\n }\n } else {\n const { id: userIdFromDb, display_name: displayName } =\n accountDb.first(\n 'SELECT id, display_name FROM users WHERE user_name = ? and enabled = 1',\n [identity],\n ) || {};\n\n if (userIdFromDb == null) {\n throw new Error('openid-grant-failed');\n }\n\n if (!displayName && userInfo.name) {\n accountDb.mutate('UPDATE users set display_name = ? WHERE id = ?', [\n userInfo.name,\n userIdFromDb,\n ]);\n }\n\n userId = userIdFromDb;\n }\n });\n } catch (error) {\n if (error.message === 'user-already-exists') {\n return { error: 'user-already-exists' };\n } else if (error.message === 'openid-grant-failed') {\n return { error: 'openid-grant-failed' };\n } else {\n throw error; // Re-throw other unexpected errors\n }\n }\n\n const token = uuidv4();\n\n let expiration;\n if (config.get('token_expiration') === 'openid-provider') {\n expiration = tokenSet.expires_at ?? TOKEN_EXPIRATION_NEVER;\n } else if (config.get('token_expiration') === 'never') {\n expiration = TOKEN_EXPIRATION_NEVER;\n } else if (typeof config.get('token_expiration') === 'number') {\n expiration =\n Math.floor(Date.now() / 1000) + config.get('token_expiration');\n } else {\n expiration = Math.floor(Date.now() / 1000) + 10 * 60; // Default to 10 minutes\n }\n\n accountDb.mutate(\n 'INSERT INTO sessions (token, expires_at, user_id, auth_method) VALUES (?, ?, ?, ?)',\n [token, expiration, userId, 'openid'],\n );\n\n clearExpiredSessions();\n\n return { url: `${return_url}/openid-cb?token=${token}` };\n } catch (err) {\n console.error('OpenID grant failed:', err);\n return { error: 'openid-grant-failed' };\n }\n}\n\nexport function getServerHostname() {\n const auth = getAccountDb().first(\n 'select * from auth WHERE method = ? and active = 1',\n ['openid'],\n );\n if (auth && auth.extra_data) {\n try {\n const openIdConfig = JSON.parse(auth.extra_data);\n return openIdConfig.server_hostname;\n } catch (error) {\n console.error('Error parsing OpenID configuration:', error);\n }\n }\n return null;\n}\n\nexport function isValidRedirectUrl(url: string | undefined): url is string {\n const serverHostname = getServerHostname();\n\n if (!serverHostname) {\n return false;\n }\n\n try {\n const redirectUrl = new URL(url);\n const serverUrl = new URL(serverHostname);\n\n if (\n redirectUrl.hostname === serverUrl.hostname ||\n redirectUrl.hostname === 'localhost'\n ) {\n return true;\n } else {\n return false;\n }\n } catch {\n return false;\n }\n}\n","import Database from 'better-sqlite3';\n\nexport class WrappedDatabase {\n constructor(db) {\n this.db = db;\n }\n\n /**\n * @param {string} sql\n * @param {(string | number)[]} params\n */\n all(sql, params = []) {\n const stmt = this.db.prepare(sql);\n return stmt.all(...params);\n }\n\n /**\n * @param {string} sql\n * @param {string[]} params\n */\n first(sql, params = []) {\n const rows = this.all(sql, params);\n return rows.length === 0 ? null : rows[0];\n }\n\n /**\n * @param {string} sql\n */\n exec(sql) {\n return this.db.exec(sql);\n }\n\n /**\n * @param {string} sql\n * @param {(string | number | null | undefined)[]} params\n */\n mutate(sql, params = []) {\n const stmt = this.db.prepare(sql);\n const info = stmt.run(...params);\n return { changes: info.changes, insertId: info.lastInsertRowid };\n }\n\n /**\n * @param {() => void} fn\n */\n transaction(fn) {\n return this.db.transaction(fn)();\n }\n\n close() {\n this.db.close();\n }\n}\n\n/** @param {string} filename */\nexport function openDatabase(filename) {\n return new WrappedDatabase(new Database(filename));\n}\n","import { join, resolve } from 'node:path';\n\nimport * as bcrypt from 'bcrypt';\n\nimport { bootstrapOpenId } from './accounts/openid';\nimport { bootstrapPassword, loginWithPassword } from './accounts/password';\nimport { openDatabase } from './db';\nimport { config } from './load-config';\n\nlet _accountDb;\n\nexport function getAccountDb() {\n if (_accountDb === undefined) {\n const dbPath = join(resolve(config.get('serverFiles')), 'account.sqlite');\n _accountDb = openDatabase(dbPath);\n }\n\n return _accountDb;\n}\n\nexport function needsBootstrap() {\n const accountDb = getAccountDb();\n const rows = accountDb.all('SELECT * FROM auth');\n return rows.length === 0;\n}\n\nexport function listLoginMethods() {\n const accountDb = getAccountDb();\n const rows = accountDb.all('SELECT method, display_name, active FROM auth');\n return rows\n .filter(f =>\n rows.length > 1 && config.get('enforceOpenId')\n ? f.method === 'openid'\n : true,\n )\n .map(r => ({\n method: r.method,\n active: r.active,\n displayName: r.display_name,\n }));\n}\n\nexport function getActiveLoginMethod() {\n const accountDb = getAccountDb();\n const { method } =\n accountDb.first('SELECT method FROM auth WHERE active = 1') || {};\n return method;\n}\n\n/*\n * Get the Login Method in the following order\n * req (the frontend can say which method in the case it wants to resort to forcing password auth)\n * config options\n * fall back to using password\n */\nexport function getLoginMethod(req) {\n if (\n typeof req !== 'undefined' &&\n (req.body || { loginMethod: null }).loginMethod &&\n config.get('allowedLoginMethods').includes(req.body.loginMethod)\n ) {\n const accountDb = getAccountDb();\n const row = accountDb.first('SELECT method FROM auth WHERE method = ?', [\n req.body.loginMethod,\n ]);\n if (row) return req.body.loginMethod;\n }\n\n //BY-PASS ANY OTHER CONFIGURATION TO ENSURE HEADER AUTH\n if (\n config.get('loginMethod') === 'header' &&\n config.get('allowedLoginMethods').includes('header')\n ) {\n return config.get('loginMethod');\n }\n\n const activeMethod = getActiveLoginMethod();\n return activeMethod || config.get('loginMethod');\n}\n\nexport async function bootstrap(loginSettings, forced = false) {\n if (!loginSettings) {\n return { error: 'invalid-login-settings' };\n }\n const passEnabled = 'password' in loginSettings;\n const openIdEnabled = 'openId' in loginSettings;\n\n const accountDb = getAccountDb();\n accountDb.mutate('BEGIN TRANSACTION');\n try {\n const { countOfOwner } =\n accountDb.first(\n `SELECT count(*) as countOfOwner\n FROM users\n WHERE users.user_name <> '' and users.owner = 1`,\n ) || {};\n\n if (!forced && (!openIdEnabled || countOfOwner > 0)) {\n if (!needsBootstrap()) {\n accountDb.mutate('ROLLBACK');\n return { error: 'already-bootstrapped' };\n }\n }\n\n if (!passEnabled && !openIdEnabled) {\n accountDb.mutate('ROLLBACK');\n return { error: 'no-auth-method-selected' };\n }\n\n if (passEnabled && openIdEnabled && !forced) {\n accountDb.mutate('ROLLBACK');\n return { error: 'max-one-method-allowed' };\n }\n\n if (passEnabled) {\n const { error } = bootstrapPassword(loginSettings.password);\n if (error) {\n accountDb.mutate('ROLLBACK');\n return { error };\n }\n }\n\n if (openIdEnabled && forced) {\n const { error } = await bootstrapOpenId(loginSettings.openId);\n if (error) {\n accountDb.mutate('ROLLBACK');\n return { error };\n }\n }\n\n accountDb.mutate('COMMIT');\n return passEnabled ? loginWithPassword(loginSettings.password) : {};\n } catch (error) {\n accountDb.mutate('ROLLBACK');\n throw error;\n }\n}\n\nexport function isAdmin(userId) {\n return hasPermission(userId, 'ADMIN');\n}\n\nexport function hasPermission(userId, permission) {\n return getUserPermission(userId) === permission;\n}\n\nexport async function enableOpenID(loginSettings) {\n if (!loginSettings || !loginSettings.openId) {\n return { error: 'invalid-login-settings' };\n }\n\n const { error } = (await bootstrapOpenId(loginSettings.openId)) || {};\n if (error) {\n return { error };\n }\n\n getAccountDb().mutate('DELETE FROM sessions');\n}\n\nexport async function disableOpenID(loginSettings) {\n if (!loginSettings || !loginSettings.password) {\n return { error: 'invalid-login-settings' };\n }\n\n const accountDb = getAccountDb();\n const { extra_data: passwordHash } =\n accountDb.first('SELECT extra_data FROM auth WHERE method = ?', [\n 'password',\n ]) || {};\n\n if (!passwordHash) {\n return { error: 'invalid-password' };\n }\n\n if (!loginSettings?.password) {\n return { error: 'invalid-password' };\n }\n\n const confirmed = bcrypt.compareSync(loginSettings.password, passwordHash);\n\n if (!confirmed) {\n return { error: 'invalid-password' };\n }\n\n const { error } = bootstrapPassword(loginSettings.password);\n if (error) {\n return { error };\n }\n\n try {\n accountDb.transaction(() => {\n accountDb.mutate('DELETE FROM sessions');\n accountDb.mutate(\n `DELETE FROM user_access\n WHERE user_access.user_id IN (\n SELECT users.id\n FROM users\n WHERE users.user_name <> ?\n );`,\n [''],\n );\n accountDb.mutate('DELETE FROM users WHERE user_name <> ?', ['']);\n accountDb.mutate('DELETE FROM auth WHERE method = ?', ['openid']);\n });\n } catch (err) {\n console.error('Error cleaning up openid information:', err);\n return { error: 'database-error' };\n }\n}\n\nexport function getSession(token) {\n const accountDb = getAccountDb();\n return accountDb.first(\n `SELECT sessions.*\n FROM sessions\n JOIN users ON users.id = sessions.user_id\n WHERE sessions.token = ? AND users.enabled = 1`,\n [token],\n );\n}\n\nexport function getUserInfo(userId) {\n const accountDb = getAccountDb();\n return accountDb.first('SELECT * FROM users WHERE id = ?', [userId]);\n}\n\nexport function getUserPermission(userId) {\n const accountDb = getAccountDb();\n const { role } = accountDb.first(\n `SELECT role FROM users\n WHERE users.id = ?`,\n [userId],\n ) || { role: '' };\n\n return role;\n}\n\nexport function getServerPrefs() {\n const accountDb = getAccountDb();\n const rows = accountDb.all('SELECT key, value FROM server_prefs') || [];\n\n return rows.reduce((prefs, row) => {\n prefs[row.key] = row.value;\n return prefs;\n }, {});\n}\n\nexport function setServerPrefs(prefs) {\n const accountDb = getAccountDb();\n\n if (!prefs) {\n return;\n }\n\n accountDb.transaction(() => {\n Object.entries(prefs).forEach(([key, value]) => {\n accountDb.mutate(\n 'INSERT INTO server_prefs (key, value) VALUES (?, ?) ON CONFLICT (key) DO UPDATE SET value = excluded.value',\n [key, value],\n );\n });\n });\n}\n\nexport function clearExpiredSessions() {\n const clearThreshold = Math.floor(Date.now() / 1000) - 3600;\n\n const deletedSessions = getAccountDb().mutate(\n 'DELETE FROM sessions WHERE expires_at <> -1 and expires_at < ?',\n [clearThreshold],\n ).changes;\n\n console.log(`Deleted ${deletedSessions} old sessions`);\n}\n"],"mappings":"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"}
@@ -4849,7 +4849,6 @@ var FilesService = class {
4849
4849
  });
4850
4850
  }
4851
4851
  };
4852
- new FilesService(getAccountDb());
4853
4852
  //#endregion
4854
4853
  //#region src/app-sync/validation.js
4855
4854
  var SYNC_FORMAT_VERSION = 2;
@@ -5423,4 +5422,4 @@ async function run() {
5423
5422
  //#endregion
5424
5423
  export { run };
5425
5424
 
5426
- //# sourceMappingURL=app-B9HVY4ZU.js.map
5425
+ //# sourceMappingURL=app-BByUQmkt.js.map