Skip to content
This repository has been archived by the owner on Aug 21, 2024. It is now read-only.

Commit

Permalink
Updated authentication-setting hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
MoizAdnan committed Oct 5, 2023
1 parent 02ecd7b commit a225101
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 132 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,17 @@ All portions of the code written by the Ethereal Engine team are Copyright © 20
Ethereal Engine. All Rights Reserved.
*/

import type { Id, Params } from '@feathersjs/feathers'
import type { KnexAdapterOptions } from '@feathersjs/knex'
import { KnexAdapter } from '@feathersjs/knex'
import * as k8s from '@kubernetes/client-node'
import type { Params } from '@feathersjs/feathers'
import { KnexService } from '@feathersjs/knex'

import {
AuthenticationSettingData,
AuthenticationSettingPatch,
authenticationSettingPath,
AuthenticationSettingQuery,
AuthenticationSettingType
} from '@etherealengine/engine/src/schemas/setting/authentication-setting.schema'
import { getState } from '@etherealengine/hyperflux'

import { Application } from '../../../declarations'
import { RootParams } from '../../api/root-params'
import config from '../../appconfig'
import logger from '../../ServerLogger'
import { ServerState } from '../../ServerState'
import { authenticationSettingSchemaToDb } from './authentication-setting.resolvers'

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface AuthenticationSettingParams extends RootParams<AuthenticationSettingQuery> {}
Expand All @@ -54,123 +45,9 @@ export interface AuthenticationSettingParams extends RootParams<AuthenticationSe
export class AuthenticationSettingService<
T = AuthenticationSettingType,
ServiceParams extends Params = AuthenticationSettingParams
> extends KnexAdapter<
> extends KnexService<
AuthenticationSettingType,
AuthenticationSettingData,
AuthenticationSettingParams,
AuthenticationSettingPatch
> {
app: Application

constructor(options: KnexAdapterOptions, app: Application) {
super(options)
this.app = app
}

async find(params?: AuthenticationSettingParams) {
const auth = await super._find()
const loggedInUser = params!.user!
const data = auth.data.map((el) => {
if (!loggedInUser.scopes || !loggedInUser.scopes.find((scope) => scope.type === 'admin:admin'))
return {
id: el.id,
entity: el.entity,
service: el.service,
authStrategies: el.authStrategies,
createdAt: el.createdAt,
updatedAt: el.updatedAt
}

return {
...el,
authStrategies: el.authStrategies,
jwtOptions: el.jwtOptions,
bearerToken: el.bearerToken,
callback: el.callback,
oauth: {
...el.oauth
}
}
})
return {
total: auth.total,
limit: auth.limit,
skip: auth.skip,
data
}
}

async get(id: Id, params?: AuthenticationSettingParams) {
return super._get(id, params)
}

async patch(id: Id, data: AuthenticationSettingPatch, params?: AuthenticationSettingParams) {
const authSettings = await this.app.service(authenticationSettingPath).get(id)

if (typeof data.oauth === 'string') {
data.oauth = JSON.parse(data.oauth)
}

const newOAuth = data.oauth!
data.callback = authSettings.callback

if (typeof data.callback === 'string') {
data.callback = JSON.parse(data.callback)

// Usually above JSON.parse should be enough. But since our pre-feathers 5 data
// was serialized multiple times, therefore we need to parse it twice.
if (typeof data.callback === 'string') {
data.callback = JSON.parse(data.callback)
}
}

for (const key of Object.keys(newOAuth)) {
if (config.authentication.oauth[key]?.scope) newOAuth[key].scope = config.authentication.oauth[key].scope
if (config.authentication.oauth[key]?.custom_data)
newOAuth[key].custom_data = config.authentication.oauth[key].custom_data
if (key !== 'defaults' && data.callback && !data.callback[key])
data.callback[key] = `${config.client.url}/auth/oauth/${key}`
}

const patchResult = await super._patch(id, authenticationSettingSchemaToDb(data) as any, params)

const k8AppsClient = getState(ServerState).k8AppsClient

if (k8AppsClient) {
try {
logger.info('Attempting to refresh API pods')
const refreshApiPodResponse = await k8AppsClient.patchNamespacedDeployment(
`${config.server.releaseName}-etherealengine-api`,
'default',
{
spec: {
template: {
metadata: {
annotations: {
'kubectl.kubernetes.io/restartedAt': new Date().toISOString()
}
}
}
}
},
undefined,
undefined,
undefined,
undefined,
undefined,
{
headers: {
'Content-Type': k8s.PatchUtils.PATCH_FORMAT_STRATEGIC_MERGE_PATCH
}
}
)
logger.info(refreshApiPodResponse, 'updateBuilderTagResponse')
} catch (e) {
logger.error(e)
return e
}
}

return patchResult
}
}
> {}
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,132 @@ import { iff, isProvider } from 'feathers-hooks-common'
import {
authenticationSettingDataValidator,
authenticationSettingPatchValidator,
authenticationSettingPath,
authenticationSettingQueryValidator
} from '@etherealengine/engine/src/schemas/setting/authentication-setting.schema'
import * as k8s from '@kubernetes/client-node'

import { getState } from '@etherealengine/hyperflux'
import { HookContext } from '@feathersjs/feathers'
import logger from '../../ServerLogger'
import { ServerState } from '../../ServerState'
import config from '../../appconfig'
import authenticate from '../../hooks/authenticate'
import verifyScope from '../../hooks/verify-scope'
import {
authenticationSettingDataResolver,
authenticationSettingExternalResolver,
authenticationSettingPatchResolver,
authenticationSettingQueryResolver,
authenticationSettingResolver
authenticationSettingResolver,
authenticationSettingSchemaToDb
} from './authentication-setting.resolvers'

const mapSettingsAdmin = async (context: HookContext) => {
const auth = context.params.paginate === false ? context.result : context.result.data
const loggedInUser = context.params!.user!
const data = auth.map((el) => {
if (!loggedInUser.scopes || !loggedInUser.scopes.find((scope) => scope.type === 'admin:admin'))
return {
id: el.id,
entity: el.entity,
service: el.service,
authStrategies: el.authStrategies,
createdAt: el.createdAt,
updatedAt: el.updatedAt
}

return {
...el,
authStrategies: el.authStrategies,
jwtOptions: el.jwtOptions,
bearerToken: el.bearerToken,
callback: el.callback,
oauth: {
...el.oauth
}
}
})
return context.params.paginate === false
? data
: {
total: auth.total,
limit: auth.limit,
skip: auth.skip,
data
}
}

const ensureOAuth = async (context: HookContext) => {
const authSettings = await context.app.service(authenticationSettingPath).get(context.id!)

if (typeof context.data.oauth === 'string') {
context.data.oauth = JSON.parse(context.data.oauth)
}

const newOAuth = context.data.oauth!
context.data.callback = authSettings.callback

if (typeof context.data.callback === 'string') {
context.data.callback = JSON.parse(context.data.callback)

// Usually above JSON.parse should be enough. But since our pre-feathers 5 data
// was serialized multiple times, therefore we need to parse it twice.
if (typeof context.data.callback === 'string') {
context.data.callback = JSON.parse(context.data.callback)
}
}

for (const key of Object.keys(newOAuth)) {
if (config.authentication.oauth[key]?.scope) newOAuth[key].scope = config.authentication.oauth[key].scope
if (config.authentication.oauth[key]?.custom_data)
newOAuth[key].custom_data = config.authentication.oauth[key].custom_data
if (key !== 'defaults' && context.data.callback && !context.data.callback[key])
context.data.callback[key] = `${config.client.url}/auth/oauth/${key}`
}

context.data = authenticationSettingSchemaToDb(context.data) as any
}

const refreshAPIPods = async (context: HookContext) => {
const k8AppsClient = getState(ServerState).k8AppsClient

if (k8AppsClient) {
try {
logger.info('Attempting to refresh API pods')
const refreshApiPodResponse = await k8AppsClient.patchNamespacedDeployment(
`${config.server.releaseName}-etherealengine-api`,
'default',
{
spec: {
template: {
metadata: {
annotations: {
'kubectl.kubernetes.io/restartedAt': new Date().toISOString()
}
}
}
}
},
undefined,
undefined,
undefined,
undefined,
undefined,
{
headers: {
'Content-Type': k8s.PatchUtils.PATCH_FORMAT_STRATEGIC_MERGE_PATCH
}
}
)
logger.info(refreshApiPodResponse, 'updateBuilderTagResponse')
} catch (e) {
logger.error(e)
return e
}
}
}

export default {
around: {
all: [
Expand All @@ -67,18 +180,19 @@ export default {
patch: [
iff(isProvider('external'), verifyScope('admin', 'admin'), verifyScope('settings', 'write')),
() => schemaHooks.validateData(authenticationSettingPatchValidator),
schemaHooks.resolveData(authenticationSettingPatchResolver)
schemaHooks.resolveData(authenticationSettingPatchResolver),
ensureOAuth
],
remove: [iff(isProvider('external'), verifyScope('admin', 'admin'), verifyScope('settings', 'write'))]
},

after: {
all: [],
find: [],
find: [mapSettingsAdmin],
get: [],
create: [],
update: [],
patch: [],
patch: [refreshAPIPods],
remove: []
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default (app: Application): void => {
multi: true
}

app.use(authenticationSettingPath, new AuthenticationSettingService(options, app), {
app.use(authenticationSettingPath, new AuthenticationSettingService(options), {
// A list of all methods this service exposes externally
methods: authenticationSettingMethods,
// You can add additional custom events to be sent to clients here
Expand Down

0 comments on commit a225101

Please sign in to comment.