]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - server/lib/auth/oauth-model.ts
Bumped to version v5.2.1
[github/Chocobozzz/PeerTube.git] / server / lib / auth / oauth-model.ts
index 910fdeec1099d4e38e04515ca19089baaafa75f0..d3a5eccd5c255e20a6437f5fa68c0c23b495d111 100644 (file)
@@ -1,18 +1,21 @@
 import express from 'express'
-import { AccessDeniedError } from 'oauth2-server'
+import { AccessDeniedError } from '@node-oauth/oauth2-server'
 import { PluginManager } from '@server/lib/plugins/plugin-manager'
-import { ActorModel } from '@server/models/actor/actor'
+import { AccountModel } from '@server/models/account/account'
+import { AuthenticatedResultUpdaterFieldName, RegisterServerAuthenticatedResult } from '@server/types'
 import { MOAuthClient } from '@server/types/models'
 import { MOAuthTokenUser } from '@server/types/models/oauth/oauth-token'
-import { MUser } from '@server/types/models/user/user'
+import { MUser, MUserDefault } from '@server/types/models/user/user'
 import { pick } from '@shared/core-utils'
-import { UserRole } from '@shared/models/users/user-role'
+import { AttributesOnly } from '@shared/typescript-utils'
 import { logger } from '../../helpers/logger'
 import { CONFIG } from '../../initializers/config'
 import { OAuthClientModel } from '../../models/oauth/oauth-client'
 import { OAuthTokenModel } from '../../models/oauth/oauth-token'
 import { UserModel } from '../../models/user/user'
+import { findAvailableLocalActorName } from '../local-actor'
 import { buildUser, createUserAccountAndChannelAndPlaylist } from '../user'
+import { ExternalUser } from './external-auth'
 import { TokensCache } from './tokens-cache'
 
 type TokenInfo = {
@@ -26,16 +29,12 @@ export type BypassLogin = {
   bypass: boolean
   pluginName: string
   authName?: string
-  user: {
-    username: string
-    email: string
-    displayName: string
-    role: UserRole
-  }
+  user: ExternalUser
+  userUpdater: RegisterServerAuthenticatedResult['userUpdater']
 }
 
 async function getAccessToken (bearerToken: string) {
-  logger.debug('Getting access token (bearerToken: ' + bearerToken + ').')
+  logger.debug('Getting access token.')
 
   if (!bearerToken) return undefined
 
@@ -89,7 +88,9 @@ async function getUser (usernameOrEmail?: string, password?: string, bypassLogin
     logger.info('Bypassing oauth login by plugin %s.', bypassLogin.pluginName)
 
     let user = await UserModel.loadByEmail(bypassLogin.user.email)
+
     if (!user) user = await createUserFromExternal(bypassLogin.pluginName, bypassLogin.user)
+    else user = await updateUserFromExternal(user, bypassLogin.user, bypassLogin.userUpdater)
 
     // Cannot create a user
     if (!user) throw new AccessDeniedError('Cannot create such user: an actor with that name already exists.')
@@ -219,19 +220,13 @@ export {
 
 // ---------------------------------------------------------------------------
 
-async function createUserFromExternal (pluginAuth: string, options: {
-  username: string
-  email: string
-  role: UserRole
-  displayName: string
-}) {
-  // Check an actor does not already exists with that name (removed user)
-  const actor = await ActorModel.loadLocalByName(options.username)
-  if (actor) return null
+async function createUserFromExternal (pluginAuth: string, userOptions: ExternalUser) {
+  const username = await findAvailableLocalActorName(userOptions.username)
 
   const userToCreate = buildUser({
-    ...pick(options, [ 'username', 'email', 'role' ]),
+    ...pick(userOptions, [ 'email', 'role', 'adminFlags', 'videoQuota', 'videoQuotaDaily' ]),
 
+    username,
     emailVerified: null,
     password: null,
     pluginAuth
@@ -239,12 +234,57 @@ async function createUserFromExternal (pluginAuth: string, options: {
 
   const { user } = await createUserAccountAndChannelAndPlaylist({
     userToCreate,
-    userDisplayName: options.displayName
+    userDisplayName: userOptions.displayName
   })
 
   return user
 }
 
+async function updateUserFromExternal (
+  user: MUserDefault,
+  userOptions: ExternalUser,
+  userUpdater: RegisterServerAuthenticatedResult['userUpdater']
+) {
+  if (!userUpdater) return user
+
+  {
+    type UserAttributeKeys = keyof AttributesOnly<UserModel>
+    const mappingKeys: { [ id in UserAttributeKeys ]?: AuthenticatedResultUpdaterFieldName } = {
+      role: 'role',
+      adminFlags: 'adminFlags',
+      videoQuota: 'videoQuota',
+      videoQuotaDaily: 'videoQuotaDaily'
+    }
+
+    for (const modelKey of Object.keys(mappingKeys)) {
+      const pluginOptionKey = mappingKeys[modelKey]
+
+      const newValue = userUpdater({ fieldName: pluginOptionKey, currentValue: user[modelKey], newValue: userOptions[pluginOptionKey] })
+      user.set(modelKey, newValue)
+    }
+  }
+
+  {
+    type AccountAttributeKeys = keyof Partial<AttributesOnly<AccountModel>>
+    const mappingKeys: { [ id in AccountAttributeKeys ]?: AuthenticatedResultUpdaterFieldName } = {
+      name: 'displayName'
+    }
+
+    for (const modelKey of Object.keys(mappingKeys)) {
+      const optionKey = mappingKeys[modelKey]
+
+      const newValue = userUpdater({ fieldName: optionKey, currentValue: user.Account[modelKey], newValue: userOptions[optionKey] })
+      user.Account.set(modelKey, newValue)
+    }
+  }
+
+  logger.debug('Updated user %s with plugin userUpdated function.', user.email, { user, userOptions })
+
+  user.Account = await user.Account.save()
+
+  return user.save()
+}
+
 function checkUserValidityOrThrow (user: MUser) {
   if (user.blocked) throw new AccessDeniedError('User is blocked.')
 }