@@ -11,6 +11,8 @@ import { MAKE_MOVE, GAME_EVENT } from '../core/action-types';
1111import { createStore } from 'redux' ;
1212import * as logging from '../core/logger' ;
1313
14+ const GameMetadataKey = gameID => `${ gameID } :metadata` ;
15+
1416/**
1517 * Redact the log.
1618 *
@@ -53,6 +55,45 @@ export function redactLog(redactedMoves, log, playerID) {
5355 } ) ;
5456}
5557
58+ /**
59+ * Verifies that the move came from a player with the
60+ * appropriate credentials.
61+ */
62+ export const isActionFromAuthenticPlayer = ( {
63+ action,
64+ gameMetadata,
65+ playerID,
66+ } ) => {
67+ if ( ! gameMetadata ) {
68+ return true ;
69+ }
70+
71+ if ( ! action . payload ) {
72+ return true ;
73+ }
74+
75+ const hasCredentials = Object . keys ( gameMetadata . players ) . some ( key => {
76+ return ! ! (
77+ gameMetadata . players [ key ] && gameMetadata . players [ key ] . credentials
78+ ) ;
79+ } ) ;
80+ if ( ! hasCredentials ) {
81+ return true ;
82+ }
83+
84+ if ( ! action . payload . credentials ) {
85+ return false ;
86+ }
87+
88+ if (
89+ action . payload . credentials !== gameMetadata . players [ playerID ] . credentials
90+ ) {
91+ return false ;
92+ }
93+
94+ return true ;
95+ } ;
96+
5697/**
5798 * Master
5899 *
@@ -61,14 +102,16 @@ export function redactLog(redactedMoves, log, playerID) {
61102 * storageAPI to communicate with the database.
62103 */
63104export class Master {
64- constructor ( game , storageAPI , transportAPI , isActionFromAuthenticPlayer ) {
105+ constructor ( game , storageAPI , transportAPI , auth ) {
65106 this . game = game ;
66107 this . storageAPI = storageAPI ;
67108 this . transportAPI = transportAPI ;
68- this . isActionFromAuthenticPlayer = ( ) => true ;
109+ this . auth = ( ) => true ;
69110
70- if ( isActionFromAuthenticPlayer !== undefined ) {
71- this . isActionFromAuthenticPlayer = isActionFromAuthenticPlayer ;
111+ if ( auth === true ) {
112+ this . auth = isActionFromAuthenticPlayer ;
113+ } else if ( typeof auth === 'function' ) {
114+ this . auth = auth ;
72115 }
73116 }
74117
@@ -78,8 +121,37 @@ export class Master {
78121 * along with a deltalog.
79122 */
80123 async onUpdate ( action , stateID , gameID , playerID ) {
124+ let isActionAuthentic ;
125+
126+ if ( this . executeSynchronously ) {
127+ const gameMetadata = this . storageAPI . get ( GameMetadataKey ( gameID ) ) ;
128+ isActionAuthentic = this . auth ( {
129+ action,
130+ gameMetadata,
131+ gameID,
132+ playerID,
133+ } ) ;
134+ } else {
135+ const gameMetadata = await this . storageAPI . get ( GameMetadataKey ( gameID ) ) ;
136+ isActionAuthentic = this . auth ( {
137+ action,
138+ gameMetadata,
139+ gameID,
140+ playerID,
141+ } ) ;
142+ }
143+ if ( ! isActionAuthentic ) {
144+ return { error : 'unauthorized action' } ;
145+ }
146+
81147 const key = gameID ;
82- let state = await this . storageAPI . get ( key ) ;
148+
149+ let state ;
150+ if ( this . executeSynchronously ) {
151+ state = this . storageAPI . get ( key ) ;
152+ } else {
153+ state = await this . storageAPI . get ( key ) ;
154+ }
83155
84156 if ( state === undefined ) {
85157 logging . error ( `game not found, gameID=[${ key } ]` ) ;
@@ -92,16 +164,6 @@ export class Master {
92164 } ) ;
93165 const store = createStore ( reducer , state ) ;
94166
95- const isActionAuthentic = await this . isActionFromAuthenticPlayer ( {
96- action,
97- db : this . storageAPI ,
98- gameID,
99- playerID,
100- } ) ;
101- if ( ! isActionAuthentic ) {
102- return { error : 'unauthorized action' } ;
103- }
104-
105167 // Check whether the player is allowed to make the move.
106168 if (
107169 action . type == MAKE_MOVE &&
@@ -162,7 +224,11 @@ export class Master {
162224 log = [ ...log , ...state . deltalog ] ;
163225 const stateWithLog = { ...state , log } ;
164226
165- await this . storageAPI . set ( key , stateWithLog ) ;
227+ if ( this . executeSynchronously ) {
228+ this . storageAPI . set ( key , stateWithLog ) ;
229+ } else {
230+ await this . storageAPI . set ( key , stateWithLog ) ;
231+ }
166232 }
167233
168234 /**
@@ -172,14 +238,26 @@ export class Master {
172238 async onSync ( gameID , playerID , numPlayers ) {
173239 const key = gameID ;
174240
175- let state = await this . storageAPI . get ( key ) ;
241+ let state ;
242+
243+ if ( this . executeSynchronously ) {
244+ state = this . storageAPI . get ( key ) ;
245+ } else {
246+ state = await this . storageAPI . get ( key ) ;
247+ }
176248
177249 // If the game doesn't exist, then create one on demand.
178250 // TODO: Move this out of the sync call.
179251 if ( state === undefined ) {
180252 state = InitializeGame ( { game : this . game , numPlayers } ) ;
181- await this . storageAPI . set ( key , state ) ;
182- state = await this . storageAPI . get ( key ) ;
253+
254+ if ( this . executeSynchronously ) {
255+ this . storageAPI . set ( key , state ) ;
256+ state = this . storageAPI . get ( key ) ;
257+ } else {
258+ await this . storageAPI . set ( key , state ) ;
259+ state = await this . storageAPI . get ( key ) ;
260+ }
183261 }
184262
185263 const filteredState = {
0 commit comments