]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - server/lib/auth/oauth-model.ts
External auth can update user on login
[github/Chocobozzz/PeerTube.git] / server / lib / auth / oauth-model.ts
index 603cc0f5f541b473f137d047a9f75dc118ceeb17..43909284f8c10b283d36bc490110b240ff5f7da4 100644 (file)
@@ -1,10 +1,13 @@
 import express from 'express'
 import { AccessDeniedError } from '@node-oauth/oauth2-server'
 import { PluginManager } from '@server/lib/plugins/plugin-manager'
+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 { AttributesOnly } from '@shared/typescript-utils'
 import { logger } from '../../helpers/logger'
 import { CONFIG } from '../../initializers/config'
 import { OAuthClientModel } from '../../models/oauth/oauth-client'
@@ -27,6 +30,7 @@ export type BypassLogin = {
   pluginName: string
   authName?: string
   user: ExternalUser
+  userUpdater: RegisterServerAuthenticatedResult['userUpdater']
 }
 
 async function getAccessToken (bearerToken: string) {
@@ -84,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.')
@@ -234,6 +240,51 @@ async function createUserFromExternal (pluginAuth: string, userOptions: External
   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.')
 }