aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib/auth/oauth-model.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/lib/auth/oauth-model.ts')
-rw-r--r--server/lib/auth/oauth-model.ts75
1 files changed, 58 insertions, 17 deletions
diff --git a/server/lib/auth/oauth-model.ts b/server/lib/auth/oauth-model.ts
index 322b69e3a..43909284f 100644
--- a/server/lib/auth/oauth-model.ts
+++ b/server/lib/auth/oauth-model.ts
@@ -1,11 +1,13 @@
1import express from 'express' 1import express from 'express'
2import { AccessDeniedError } from '@node-oauth/oauth2-server' 2import { AccessDeniedError } from '@node-oauth/oauth2-server'
3import { PluginManager } from '@server/lib/plugins/plugin-manager' 3import { PluginManager } from '@server/lib/plugins/plugin-manager'
4import { AccountModel } from '@server/models/account/account'
5import { AuthenticatedResultUpdaterFieldName, RegisterServerAuthenticatedResult } from '@server/types'
4import { MOAuthClient } from '@server/types/models' 6import { MOAuthClient } from '@server/types/models'
5import { MOAuthTokenUser } from '@server/types/models/oauth/oauth-token' 7import { MOAuthTokenUser } from '@server/types/models/oauth/oauth-token'
6import { MUser } from '@server/types/models/user/user' 8import { MUser, MUserDefault } from '@server/types/models/user/user'
7import { pick } from '@shared/core-utils' 9import { pick } from '@shared/core-utils'
8import { UserRole } from '@shared/models/users/user-role' 10import { AttributesOnly } from '@shared/typescript-utils'
9import { logger } from '../../helpers/logger' 11import { logger } from '../../helpers/logger'
10import { CONFIG } from '../../initializers/config' 12import { CONFIG } from '../../initializers/config'
11import { OAuthClientModel } from '../../models/oauth/oauth-client' 13import { OAuthClientModel } from '../../models/oauth/oauth-client'
@@ -13,6 +15,7 @@ import { OAuthTokenModel } from '../../models/oauth/oauth-token'
13import { UserModel } from '../../models/user/user' 15import { UserModel } from '../../models/user/user'
14import { findAvailableLocalActorName } from '../local-actor' 16import { findAvailableLocalActorName } from '../local-actor'
15import { buildUser, createUserAccountAndChannelAndPlaylist } from '../user' 17import { buildUser, createUserAccountAndChannelAndPlaylist } from '../user'
18import { ExternalUser } from './external-auth'
16import { TokensCache } from './tokens-cache' 19import { TokensCache } from './tokens-cache'
17 20
18type TokenInfo = { 21type TokenInfo = {
@@ -26,12 +29,8 @@ export type BypassLogin = {
26 bypass: boolean 29 bypass: boolean
27 pluginName: string 30 pluginName: string
28 authName?: string 31 authName?: string
29 user: { 32 user: ExternalUser
30 username: string 33 userUpdater: RegisterServerAuthenticatedResult['userUpdater']
31 email: string
32 displayName: string
33 role: UserRole
34 }
35} 34}
36 35
37async function getAccessToken (bearerToken: string) { 36async function getAccessToken (bearerToken: string) {
@@ -89,7 +88,9 @@ async function getUser (usernameOrEmail?: string, password?: string, bypassLogin
89 logger.info('Bypassing oauth login by plugin %s.', bypassLogin.pluginName) 88 logger.info('Bypassing oauth login by plugin %s.', bypassLogin.pluginName)
90 89
91 let user = await UserModel.loadByEmail(bypassLogin.user.email) 90 let user = await UserModel.loadByEmail(bypassLogin.user.email)
91
92 if (!user) user = await createUserFromExternal(bypassLogin.pluginName, bypassLogin.user) 92 if (!user) user = await createUserFromExternal(bypassLogin.pluginName, bypassLogin.user)
93 else user = await updateUserFromExternal(user, bypassLogin.user, bypassLogin.userUpdater)
93 94
94 // Cannot create a user 95 // Cannot create a user
95 if (!user) throw new AccessDeniedError('Cannot create such user: an actor with that name already exists.') 96 if (!user) throw new AccessDeniedError('Cannot create such user: an actor with that name already exists.')
@@ -219,16 +220,11 @@ export {
219 220
220// --------------------------------------------------------------------------- 221// ---------------------------------------------------------------------------
221 222
222async function createUserFromExternal (pluginAuth: string, options: { 223async function createUserFromExternal (pluginAuth: string, userOptions: ExternalUser) {
223 username: string 224 const username = await findAvailableLocalActorName(userOptions.username)
224 email: string
225 role: UserRole
226 displayName: string
227}) {
228 const username = await findAvailableLocalActorName(options.username)
229 225
230 const userToCreate = buildUser({ 226 const userToCreate = buildUser({
231 ...pick(options, [ 'email', 'role' ]), 227 ...pick(userOptions, [ 'email', 'role', 'adminFlags', 'videoQuota', 'videoQuotaDaily' ]),
232 228
233 username, 229 username,
234 emailVerified: null, 230 emailVerified: null,
@@ -238,12 +234,57 @@ async function createUserFromExternal (pluginAuth: string, options: {
238 234
239 const { user } = await createUserAccountAndChannelAndPlaylist({ 235 const { user } = await createUserAccountAndChannelAndPlaylist({
240 userToCreate, 236 userToCreate,
241 userDisplayName: options.displayName 237 userDisplayName: userOptions.displayName
242 }) 238 })
243 239
244 return user 240 return user
245} 241}
246 242
243async function updateUserFromExternal (
244 user: MUserDefault,
245 userOptions: ExternalUser,
246 userUpdater: RegisterServerAuthenticatedResult['userUpdater']
247) {
248 if (!userUpdater) return user
249
250 {
251 type UserAttributeKeys = keyof AttributesOnly<UserModel>
252 const mappingKeys: { [ id in UserAttributeKeys ]?: AuthenticatedResultUpdaterFieldName } = {
253 role: 'role',
254 adminFlags: 'adminFlags',
255 videoQuota: 'videoQuota',
256 videoQuotaDaily: 'videoQuotaDaily'
257 }
258
259 for (const modelKey of Object.keys(mappingKeys)) {
260 const pluginOptionKey = mappingKeys[modelKey]
261
262 const newValue = userUpdater({ fieldName: pluginOptionKey, currentValue: user[modelKey], newValue: userOptions[pluginOptionKey] })
263 user.set(modelKey, newValue)
264 }
265 }
266
267 {
268 type AccountAttributeKeys = keyof Partial<AttributesOnly<AccountModel>>
269 const mappingKeys: { [ id in AccountAttributeKeys ]?: AuthenticatedResultUpdaterFieldName } = {
270 name: 'displayName'
271 }
272
273 for (const modelKey of Object.keys(mappingKeys)) {
274 const optionKey = mappingKeys[modelKey]
275
276 const newValue = userUpdater({ fieldName: optionKey, currentValue: user.Account[modelKey], newValue: userOptions[optionKey] })
277 user.Account.set(modelKey, newValue)
278 }
279 }
280
281 logger.debug('Updated user %s with plugin userUpdated function.', user.email, { user, userOptions })
282
283 user.Account = await user.Account.save()
284
285 return user.save()
286}
287
247function checkUserValidityOrThrow (user: MUser) { 288function checkUserValidityOrThrow (user: MUser) {
248 if (user.blocked) throw new AccessDeniedError('User is blocked.') 289 if (user.blocked) throw new AccessDeniedError('User is blocked.')
249} 290}