@xrengine/server-core
Version:
Shared components for XREngine server
131 lines (122 loc) • 5.42 kB
text/typescript
import { AuthenticationRequest } from '@feathersjs/authentication'
import { Paginated, Params } from '@feathersjs/feathers'
import { random } from 'lodash'
import { AvatarInterface } from '@xrengine/common/src/interfaces/AvatarInterface'
import { UserInterface } from '@xrengine/common/src/interfaces/User'
import { Application } from '../../../declarations'
import config from '../../appconfig'
import getFreeInviteCode from '../../util/get-free-invite-code'
import makeInitialAdmin from '../../util/make-initial-admin'
import CustomOAuthStrategy, { CustomOAuthParams } from './custom-oauth'
export class GithubStrategy extends CustomOAuthStrategy {
constructor(app: Application) {
super()
this.app = app
}
async getEntityData(profile: any, entity: any, params: CustomOAuthParams): Promise<any> {
const baseData = await super.getEntityData(profile, null, {})
const authResult = await (this.app.service('authentication') as any).strategies.jwt.authenticate(
{ accessToken: params?.authentication?.accessToken },
{}
)
const identityProvider = authResult['identity-provider']
const userId = identityProvider ? identityProvider.userId : params?.query ? params.query.userId : undefined
return {
...baseData,
email: profile.email,
type: 'github',
oauthToken: params.access_token!,
userName: profile.login,
userId,
accountIdentifier: profile.login
}
}
async updateEntity(entity: any, profile: any, params: CustomOAuthParams): Promise<any> {
const authResult = await (this.app.service('authentication') as any).strategies.jwt.authenticate(
{ accessToken: params?.authentication?.accessToken },
{}
)
if (!entity.userId) {
const avatars = (await this.app.service('avatar').find({ isInternal: true })) as Paginated<AvatarInterface>
const code = await getFreeInviteCode(this.app)
const newUser = (await this.app.service('user').create({
isGuest: false,
inviteCode: code,
avatarId: avatars[random(avatars.total - 1)].id
})) as UserInterface
entity.userId = newUser.id
await this.app.service('identity-provider').patch(entity.id, {
userId: newUser.id
})
}
const identityProvider = authResult['identity-provider']
const user = await this.app.service('user').get(entity.userId)
await makeInitialAdmin(this.app, user.id)
if (user.isGuest)
await this.app.service('user').patch(entity.userId, {
isGuest: false
})
const apiKey = await this.app.service('user-api-key').find({
query: {
userId: entity.userId
}
})
if ((apiKey as any).total === 0)
await this.app.service('user-api-key').create({
userId: entity.userId
})
if (entity.type !== 'guest' && identityProvider.type === 'guest') {
await this.app.service('identity-provider').remove(identityProvider.id)
await this.app.service('user').remove(identityProvider.userId)
await this.app.service('github-repo-access-refresh').find(Object.assign({}, params, { user }))
return super.updateEntity(entity, profile, params)
}
const existingEntity = await super.findEntity(profile, params)
if (!existingEntity) {
profile.userId = user.id
profile.oauthToken = params.access_token
const newIP = await super.createEntity(profile, params)
if (entity.type === 'guest') await this.app.service('identity-provider').remove(entity.id)
await this.app.service('github-repo-access-refresh').find(Object.assign({}, params, { user }))
return newIP
} else if (existingEntity.userId === identityProvider.userId) {
await this.app.service('github-repo-access-refresh').find(Object.assign({}, params, { user }))
return existingEntity
} else {
throw new Error('Another user is linked to this account')
}
}
async getRedirect(data: any, params: CustomOAuthParams): Promise<string> {
const redirectHost = config.authentication.callback.github
const type = params?.query?.userId ? 'connection' : 'login'
if (data instanceof Error || Object.getPrototypeOf(data) === Error.prototype) {
const err = data.message as string
return redirectHost + `?error=${err}`
} else {
const token = data.accessToken as string
const redirect = params.redirect!
let parsedRedirect
try {
parsedRedirect = JSON.parse(redirect)
} catch (err) {
parsedRedirect = {}
}
const path = parsedRedirect.path
const instanceId = parsedRedirect.instanceId
let returned = redirectHost + `?token=${token}&type=${type}`
if (path != null) returned = returned.concat(`&path=${path}`)
if (instanceId != null) returned = returned.concat(`&instanceId=${instanceId}`)
return returned
}
}
async authenticate(authentication: AuthenticationRequest, originalParams: CustomOAuthParams) {
if (authentication.error) {
if (authentication.error.message === 'Bad credentials')
throw new Error('You canceled the GitHub OAuth login flow')
else throw new Error('There was a problem with the GitHub OAuth login flow: ' + authentication.error_description)
}
originalParams.access_token = authentication.access_token
return super.authenticate(authentication, originalParams)
}
}
export default GithubStrategy