Skip to content

Commit

Permalink
Merge pull request #310 from TaloDev/develop
Browse files Browse the repository at this point in the history
Release 0.36.0
  • Loading branch information
tudddorrr authored Jul 11, 2024
2 parents 71ed5db + ea56026 commit d90270c
Show file tree
Hide file tree
Showing 50 changed files with 2,257 additions and 92 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "game-services",
"version": "0.35.0",
"version": "0.36.0",
"description": "",
"main": "src/index.ts",
"scripts": {
Expand Down
4 changes: 4 additions & 0 deletions src/config/api-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import limiterMiddleware from '../middlewares/limiter-middleware'
import currentPlayerMiddleware from '../middlewares/current-player-middleware'
import { apiRouteAuthMiddleware, getRouteInfo } from '../middlewares/route-middleware'
import apiKeyMiddleware from '../middlewares/api-key-middleware'
import playerAuthMiddleware from '../middlewares/player-auth-middleware'
import PlayerAuthAPIService from '../services/api/player-auth-api.service'

export default (app: Koa) => {
app.use(apiKeyMiddleware)
Expand All @@ -24,6 +26,7 @@ export default (app: Koa) => {
})

app.use(currentPlayerMiddleware)
app.use(playerAuthMiddleware)

app.use(service('/v1/game-feedback', new GameFeedbackAPIService()))
app.use(service('/v1/game-config', new GameConfigAPIService()))
Expand All @@ -32,4 +35,5 @@ export default (app: Koa) => {
app.use(service('/v1/leaderboards', new LeaderboardAPIService()))
app.use(service('/v1/events', new EventAPIService()))
app.use(service('/v1/players', new PlayerAPIService()))
app.use(service('/v1/players/auth', new PlayerAuthAPIService()))
}
2 changes: 1 addition & 1 deletion src/docs/game-stat-api.docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const GameStatAPIDocs: APIDocs<GameStatAPIService> = {
description: 'Update a stat value',
params: {
headers: {
'x-talo-alias': 'The ID of the player\'s alias'
'x-talo-player': 'The ID of the player'
},
body: {
change: 'The amount to add to the current value of the stat (can be negative)'
Expand Down
243 changes: 243 additions & 0 deletions src/docs/player-auth-api.docs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
import PlayerAuthAPIService from '../services/api/player-auth-api.service'
import APIDocs from './api-docs'

const PlayerAuthAPIDocs: APIDocs<PlayerAuthAPIService> = {
register: {
description: 'Create a new player account',
params: {
body: {
identifier: 'The unique identifier of the player. This can be their username, an email or a numeric ID',
password: 'The password the player will login with',
verificationEnabled: 'When enabled, the player will be sent a verification code to their email address before they can login',
email: 'Required when verification is enabled. This is also used for password resets: players without an email cannot reset their password'
}
},
samples: [
{
title: 'Sample request',
sample: {
identifier: 'boz',
password: 'password',
verificationEnabled: true,
email: '[email protected]'
}
},
{
title: 'Sample response',
sample: {
alias: {
id: 1,
service: 'talo',
identifier: 'boz',
player: {
id: '7a4e70ec-6ee6-418e-923d-b3a45051b7f9',
props: [],
aliases: [
'/* [Circular] */'
],
devBuild: false,
createdAt: '2024-06-28 12:37:43',
lastSeenAt: '2024-06-28 12:37:43',
groups: [],
auth: {
email: '[email protected]',
verificationEnabled: true,
sessionCreatedAt: '2024-06-28 12:37:43'
}
}
},
sessionToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwbGF5ZXJJZCI6IjdhNGU3MGVjLTZlZTYtNDE4ZS05MjNkLWIzYTQ1MDUxYjdmOSIsImFsaWFzSWQiOjEsImlhdCI6MTcxOTU5Mjk3Nn0.gb4-IA_fsDcXOnS3PkQp1eBqwYBaYWiHEmjlqXfd078'
}
}
]
},
login: {
description: 'Login to a player account',
params: {
body: {
identifier: 'The unique identifier of the player. This can be their username, an email or a numeric ID',
password: 'The player\'s password'
}
},
samples: [
{
title: 'Sample request',
sample: {
identifier: 'boz',
password: 'password'
}
},
{
title: 'Sample response (verification not enabled)',
sample: {
alias: {
id: 1,
service: 'talo',
identifier: 'boz',
player: {
id: '7a4e70ec-6ee6-418e-923d-b3a45051b7f9',
props: [],
aliases: [
'/* [Circular] */'
],
devBuild: false,
createdAt: '2024-06-28 12:37:43',
lastSeenAt: '2024-06-28 12:37:43',
groups: [],
auth: {
email: '[email protected]',
verificationEnabled: true,
sessionCreatedAt: '2024-06-28 12:37:43'
}
}
},
sessionToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwbGF5ZXJJZCI6IjdhNGU3MGVjLTZlZTYtNDE4ZS05MjNkLWIzYTQ1MDUxYjdmOSIsImFsaWFzSWQiOjEsImlhdCI6MTcxOTU5Mjk3Nn0.gb4-IA_fsDcXOnS3PkQp1eBqwYBaYWiHEmjlqXfd078'
}
},
{
title: 'Sample response (verification enabled)',
sample: {
aliasId: 1,
verificationRequired: true
}
}
]
},
verify: {
description: 'Provide the verification code to start the player session',
params: {
body: {
aliasId: 'The ID of the alias to verify',
code: 'The 6-digit verification code sent to the player (must be a string)'
}
},
samples: [
{
title: 'Sample request',
sample: {
aliasId: 1,
password: '023251'
}
},
{
title: 'Sample response',
sample: {
alias: {
id: 1,
service: 'talo',
identifier: 'boz',
player: {
id: '7a4e70ec-6ee6-418e-923d-b3a45051b7f9',
props: [],
aliases: [
'/* [Circular] */'
],
devBuild: false,
createdAt: '2024-06-28 12:37:43',
lastSeenAt: '2024-06-28 12:37:43',
groups: [],
auth: {
email: '[email protected]',
verificationEnabled: true,
sessionCreatedAt: '2024-06-28 12:37:43'
}
}
},
sessionToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwbGF5ZXJJZCI6IjdhNGU3MGVjLTZlZTYtNDE4ZS05MjNkLWIzYTQ1MDUxYjdmOSIsImFsaWFzSWQiOjEsImlhdCI6MTcxOTU5Mjk3Nn0.gb4-IA_fsDcXOnS3PkQp1eBqwYBaYWiHEmjlqXfd078'
}
}
]
},
logout: {
description: 'Logout of a player account (and invalidate the session token)',
params: {
headers: {
'x-talo-player': 'The ID of the player',
'x-talo-alias': 'The ID of the player\'s alias',
'x-talo-session': 'The session token'
}
}
},
changePassword: {
description: 'Change the password of a player account',
params: {
headers: {
'x-talo-player': 'The ID of the player',
'x-talo-alias': 'The ID of the player\'s alias',
'x-talo-session': 'The session token'
},
body: {
currentPassword: 'The current password of the player',
newPassword: 'The new password for the player'
}
},
samples: [
{
title: 'Sample request',
sample: {
currentPassword: 'password',
newPassword: 'new_password'
}
}
]
},
changeEmail: {
description: 'Change the email address of a player account',
params: {
headers: {
'x-talo-player': 'The ID of the player',
'x-talo-alias': 'The ID of the player\'s alias',
'x-talo-session': 'The session token'
},
body: {
currentPassword: 'The current password of the player',
newEmail: 'The new email address for the player'
}
},
samples: [
{
title: 'Sample request',
sample: {
currentPassword: 'password',
newEmail: '[email protected]'
}
}
]
},
forgotPassword: {
description: 'Send a password reset email to an email address',
params: {
body: {
email: 'The email address to send the verification code to. If no player with this email exists, the request will be ignored'
}
},
samples: [
{
title: 'Sample request',
sample: {
email: '[email protected]'
}
}
]
},
resetPassword: {
description: 'Reset the password of a player account (invalidates any existing session tokens)',
params: {
body: {
code: 'The 6-digit verification code sent to the email address (must be a string)',
password: 'The new password for the player'
}
},
samples: [
{
title: 'Sample request',
sample: {
code: '642230',
password: 'new_password'
}
}
]
}
}

export default PlayerAuthAPIDocs
4 changes: 2 additions & 2 deletions src/emails/confirm-email-mail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import Mail from './mail'

export default class ConfirmEmail extends Mail {
constructor(user: User, code: string) {
super(user.email, 'Welcome to Talo', `Hi, ${user.username}! Thanks for signing up to Talo. You'll need to confirm your account to get started.`)
super(user.email, 'Welcome to Talo', `Hi ${user.username}! Thanks for signing up to Talo. You'll need to confirm your account to get started.`)

this.title = 'Welcome!'
this.mainText = `Hi, ${user.username}! Thanks for signing up to Talo. To confirm your account, enter the following code into the dashboard: <strong>${code}</strong>`
this.mainText = `Hi ${user.username}! Thanks for signing up to Talo. To confirm your account, enter the following code into the dashboard: <strong>${code}</strong>`

this.ctaLink = process.env.DASHBOARD_URL
this.ctaText = 'Go to your dashboard'
Expand Down
16 changes: 16 additions & 0 deletions src/emails/player-auth-code-mail.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import PlayerAlias from '../entities/player-alias'
import Mail from './mail'

export default class PlayerAuthCode extends Mail {
constructor(alias: PlayerAlias, code: string) {
super(alias.player.auth.email, `Your ${alias.player.game.name} verification code`, `Hi ${alias.identifier}, here's your verification code to login to ${alias.player.game.name}.`)

this.title = `Login to ${alias.player.game.name}`
this.mainText = `Hi ${alias.identifier}, your verification code is: <strong>${code}</strong>.<br/>This code is only valid for 5 minutes.`

this.footer = 'Didn\'t request a code?'
this.footerText = 'Your account is still secure, however, you should update your password as soon as possible.'

this.why = `You are receiving this email because you enabled email verification for your ${alias.player.game.name} account`
}
}
16 changes: 16 additions & 0 deletions src/emails/player-auth-reset-password-mail.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import PlayerAlias from '../entities/player-alias'
import Mail from './mail'

export default class PlayerAuthResetPassword extends Mail {
constructor(alias: PlayerAlias, code: string) {
super(alias.player.auth.email, `Reset your ${alias.player.game.name} password`, `Hi ${alias.identifier}. A password reset was requested for your account. If you didn't request this you can safely ignore this email.`)

this.title = 'Reset your password'
this.mainText = `Hi ${alias.identifier}, a password reset requested was created for your ${alias.player.game.name} account.<br/><br/>Your reset code is: <strong>${code}</strong>.<br/>This code is only valid for 15 minutes.`

this.footer = 'Didn\'t request a code?'
this.footerText = 'Your account is still secure and you can safely ignore this email.'

this.why = `You are receiving this email because your ${alias.player.game.name} account is associated with this email address`
}
}
2 changes: 1 addition & 1 deletion src/emails/reset-password.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Mail from './mail'

export default class ResetPassword extends Mail {
constructor(user: User, accessToken: string) {
super(user.email, 'Reset your password', `Hi, ${user.username}. A password reset was requested for your account. If you did not do this you can safely ignore this email.`)
super(user.email, 'Reset your password', `Hi ${user.username}, a password reset was requested for your account. If you didn't request this you can safely ignore this email.`)

this.title = 'Reset your password'
this.mainText = `Hi ${user.username},<br/><br/>A password reset was requested for your account - please follow the link below to create a new password. This link is only valid for 15 minutes.<br/><br/>If you didn't request this you can safely ignore this email.`
Expand Down
4 changes: 2 additions & 2 deletions src/entities/game-feedback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ export default class GameFeedback {
@PrimaryKey()
id: number

@ManyToOne(() => GameFeedbackCategory, { cascade: [Cascade.REMOVE], eager: true })
@ManyToOne(() => GameFeedbackCategory, { nullable: false, cascade: [Cascade.REMOVE], eager: true })
category: GameFeedbackCategory

@ManyToOne(() => PlayerAlias, { cascade: [Cascade.REMOVE] })
@ManyToOne(() => PlayerAlias, { nullable: false, cascade: [Cascade.REMOVE] })
playerAlias: PlayerAlias

@Required()
Expand Down
2 changes: 2 additions & 0 deletions src/entities/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import PlayerAuth from './player-auth'
import GameFeedback from './game-feedback'
import Invite from './invite'
import PlayerGameStat from './player-game-stat'
Expand Down Expand Up @@ -32,6 +33,7 @@ import PlayerGroup from './player-group'
import GameSecret from './game-secret'

export default [
PlayerAuth,
GameFeedback,
GameSecret,
PlayerGroup,
Expand Down
3 changes: 2 additions & 1 deletion src/entities/player-alias.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ export enum PlayerAliasService {
EPIC = 'epic',
USERNAME = 'username',
EMAIL = 'email',
CUSTOM = 'custom'
CUSTOM = 'custom',
TALO = 'talo'
}

@Entity()
Expand Down
Loading

0 comments on commit d90270c

Please sign in to comment.