From 7e0c26066a5c59af742ae56bddaff9635debe034 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 29 Dec 2022 15:31:40 +0100 Subject: [PATCH] External auth can set more user fields videoQuota, videoQuotaDaily, adminFlags --- server/lib/auth/external-auth.ts | 60 ++++++++++--------- server/lib/auth/oauth-model.ts | 22 ++----- .../main.js | 5 +- server/tests/plugins/external-auth.ts | 8 ++- .../plugins/register-server-auth.model.ts | 7 ++- 5 files changed, 54 insertions(+), 48 deletions(-) diff --git a/server/lib/auth/external-auth.ts b/server/lib/auth/external-auth.ts index 053112801..155ec03d8 100644 --- a/server/lib/auth/external-auth.ts +++ b/server/lib/auth/external-auth.ts @@ -1,26 +1,33 @@ -import { isUserDisplayNameValid, isUserRoleValid, isUserUsernameValid } from '@server/helpers/custom-validators/users' +import { + isUserAdminFlagsValid, + isUserDisplayNameValid, + isUserRoleValid, + isUserUsernameValid, + isUserVideoQuotaDailyValid, + isUserVideoQuotaValid +} from '@server/helpers/custom-validators/users' import { logger } from '@server/helpers/logger' import { generateRandomString } from '@server/helpers/utils' import { PLUGIN_EXTERNAL_AUTH_TOKEN_LIFETIME } from '@server/initializers/constants' import { PluginManager } from '@server/lib/plugins/plugin-manager' import { OAuthTokenModel } from '@server/models/oauth/oauth-token' +import { MUser } from '@server/types/models' import { RegisterServerAuthenticatedResult, RegisterServerAuthPassOptions, RegisterServerExternalAuthenticatedResult } from '@server/types/plugins/register-server-auth.model' -import { UserRole } from '@shared/models' +import { UserAdminFlag, UserRole } from '@shared/models' + +export type ExternalUser = + Pick & + { displayName: string } // Token is the key, expiration date is the value const authBypassTokens = new Map() @@ -172,30 +179,20 @@ function getBypassFromExternalAuth (username: string, externalAuthToken: string) } function isAuthResultValid (npmName: string, authName: string, result: RegisterServerAuthenticatedResult) { - if (!isUserUsernameValid(result.username)) { - logger.error('Auth method %s of plugin %s did not provide a valid username.', authName, npmName, { username: result.username }) + const returnError = (field: string) => { + logger.error('Auth method %s of plugin %s did not provide a valid %s.', authName, npmName, field, { [field]: result[field] }) return false } - if (!result.email) { - logger.error('Auth method %s of plugin %s did not provide a valid email.', authName, npmName, { email: result.email }) - return false - } + if (!isUserUsernameValid(result.username)) return returnError('username') + if (!result.email) return returnError('email') - // role is optional - if (result.role && !isUserRoleValid(result.role)) { - logger.error('Auth method %s of plugin %s did not provide a valid role.', authName, npmName, { role: result.role }) - return false - } - - // display name is optional - if (result.displayName && !isUserDisplayNameValid(result.displayName)) { - logger.error( - 'Auth method %s of plugin %s did not provide a valid display name.', - authName, npmName, { displayName: result.displayName } - ) - return false - } + // Following fields are optional + if (result.role && !isUserRoleValid(result.role)) return returnError('role') + if (result.displayName && !isUserDisplayNameValid(result.displayName)) return returnError('displayName') + if (result.adminFlags && !isUserAdminFlagsValid(result.adminFlags)) return returnError('adminFlags') + if (result.videoQuota && !isUserVideoQuotaValid(result.videoQuota + '')) return returnError('videoQuota') + if (result.videoQuotaDaily && !isUserVideoQuotaDailyValid(result.videoQuotaDaily + '')) return returnError('videoQuotaDaily') return true } @@ -205,7 +202,12 @@ function buildUserResult (pluginResult: RegisterServerAuthenticatedResult) { username: pluginResult.username, email: pluginResult.email, role: pluginResult.role ?? UserRole.USER, - displayName: pluginResult.displayName || pluginResult.username + displayName: pluginResult.displayName || pluginResult.username, + + adminFlags: pluginResult.adminFlags ?? UserAdminFlag.NONE, + + videoQuota: pluginResult.videoQuota, + videoQuotaDaily: pluginResult.videoQuotaDaily } } diff --git a/server/lib/auth/oauth-model.ts b/server/lib/auth/oauth-model.ts index 322b69e3a..603cc0f5f 100644 --- a/server/lib/auth/oauth-model.ts +++ b/server/lib/auth/oauth-model.ts @@ -5,7 +5,6 @@ import { MOAuthClient } from '@server/types/models' import { MOAuthTokenUser } from '@server/types/models/oauth/oauth-token' import { MUser } from '@server/types/models/user/user' import { pick } from '@shared/core-utils' -import { UserRole } from '@shared/models/users/user-role' import { logger } from '../../helpers/logger' import { CONFIG } from '../../initializers/config' import { OAuthClientModel } from '../../models/oauth/oauth-client' @@ -13,6 +12,7 @@ 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,12 +26,7 @@ export type BypassLogin = { bypass: boolean pluginName: string authName?: string - user: { - username: string - email: string - displayName: string - role: UserRole - } + user: ExternalUser } async function getAccessToken (bearerToken: string) { @@ -219,16 +214,11 @@ export { // --------------------------------------------------------------------------- -async function createUserFromExternal (pluginAuth: string, options: { - username: string - email: string - role: UserRole - displayName: string -}) { - const username = await findAvailableLocalActorName(options.username) +async function createUserFromExternal (pluginAuth: string, userOptions: ExternalUser) { + const username = await findAvailableLocalActorName(userOptions.username) const userToCreate = buildUser({ - ...pick(options, [ 'email', 'role' ]), + ...pick(userOptions, [ 'email', 'role', 'adminFlags', 'videoQuota', 'videoQuotaDaily' ]), username, emailVerified: null, @@ -238,7 +228,7 @@ async function createUserFromExternal (pluginAuth: string, options: { const { user } = await createUserAccountAndChannelAndPlaylist({ userToCreate, - userDisplayName: options.displayName + userDisplayName: userOptions.displayName }) return user diff --git a/server/tests/fixtures/peertube-plugin-test-external-auth-one/main.js b/server/tests/fixtures/peertube-plugin-test-external-auth-one/main.js index c65b8d3a8..cdbaf11ac 100644 --- a/server/tests/fixtures/peertube-plugin-test-external-auth-one/main.js +++ b/server/tests/fixtures/peertube-plugin-test-external-auth-one/main.js @@ -33,7 +33,10 @@ async function register ({ username: 'kefka', email: 'kefka@example.com', role: 0, - displayName: 'Kefka Palazzo' + displayName: 'Kefka Palazzo', + adminFlags: 1, + videoQuota: 42000, + videoQuotaDaily: 42100 }) }, hookTokenValidity: (options) => { diff --git a/server/tests/plugins/external-auth.ts b/server/tests/plugins/external-auth.ts index 437777e90..ee78ae5aa 100644 --- a/server/tests/plugins/external-auth.ts +++ b/server/tests/plugins/external-auth.ts @@ -2,7 +2,7 @@ import { expect } from 'chai' import { wait } from '@shared/core-utils' -import { HttpStatusCode, UserRole } from '@shared/models' +import { HttpStatusCode, UserAdminFlag, UserRole } from '@shared/models' import { cleanupTests, createSingleServer, @@ -156,6 +156,9 @@ describe('Test external auth plugins', function () { expect(body.account.displayName).to.equal('cyan') expect(body.email).to.equal('cyan@example.com') expect(body.role.id).to.equal(UserRole.USER) + expect(body.adminFlags).to.equal(UserAdminFlag.NONE) + expect(body.videoQuota).to.equal(5242880) + expect(body.videoQuotaDaily).to.equal(-1) } }) @@ -178,6 +181,9 @@ describe('Test external auth plugins', function () { expect(body.account.displayName).to.equal('Kefka Palazzo') expect(body.email).to.equal('kefka@example.com') expect(body.role.id).to.equal(UserRole.ADMINISTRATOR) + expect(body.adminFlags).to.equal(UserAdminFlag.BYPASS_VIDEO_AUTO_BLACKLIST) + expect(body.videoQuota).to.equal(42000) + expect(body.videoQuotaDaily).to.equal(42100) } }) diff --git a/server/types/plugins/register-server-auth.model.ts b/server/types/plugins/register-server-auth.model.ts index 79c18c406..a17fc4b0f 100644 --- a/server/types/plugins/register-server-auth.model.ts +++ b/server/types/plugins/register-server-auth.model.ts @@ -1,5 +1,5 @@ import express from 'express' -import { UserRole } from '@shared/models' +import { UserAdminFlag, UserRole } from '@shared/models' import { MOAuthToken, MUser } from '../models' export type RegisterServerAuthOptions = RegisterServerAuthPassOptions | RegisterServerAuthExternalOptions @@ -9,6 +9,11 @@ export interface RegisterServerAuthenticatedResult { email: string role?: UserRole displayName?: string + + adminFlags?: UserAdminFlag + + videoQuota?: number + videoQuotaDaily?: number } export interface RegisterServerExternalAuthenticatedResult extends RegisterServerAuthenticatedResult {