passport-steam-openid 1.0.3 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -59,7 +59,7 @@ Install using npm:
59
59
  ```
60
60
  npm install passport-steam-openid
61
61
  ```
62
- Released in early stage, library's api is subject to change.
62
+ Library's API has been unchanged and stable for some time now. It will not change unless a breaking change is issued by steam (very unlikely).
63
63
 
64
64
  ## License
65
65
  This library is released under MIT license.
@@ -34,12 +34,22 @@ export declare class SteamOpenIdStrategy<TOptions extends SteamOpenIdStrategyOpt
34
34
  * optional callback, called when user is successfully authenticated
35
35
  */
36
36
  protected verify?: VerifyCallback<TUser>;
37
+ /**
38
+ * Optional setting for validating nonce time delay,
39
+ * in seconds.
40
+ *
41
+ * Measures time between nonce creation date and verification.
42
+ */
43
+ protected maxNonceTimeDelay: number | undefined;
37
44
  /**
38
45
  * @constructor
39
46
  *
40
47
  * @param options.returnURL where steam redirects after parameters are passed
41
48
  * @param options.profile if set, we will fetch user's profile from steam api
42
49
  * @param options.apiKey api key to fetch user profile, not used if profile is false
50
+ * @param options.maxNonceTimeDelay optional setting for validating nonce time delay,
51
+ * this is just an extra security measure, it is not required nor recommended, but
52
+ * might be extra layer of security you want to have.
43
53
  * @param verify optional callback, called when user is successfully authenticated
44
54
  */
45
55
  constructor(options: TOptions, verify?: VerifyCallback<TUser>);
@@ -64,6 +74,14 @@ export declare class SteamOpenIdStrategy<TOptions extends SteamOpenIdStrategyOpt
64
74
  * @throws {Error} Non-recoverable errors, such as query object missing.
65
75
  */
66
76
  handleRequest(req: any): Promise<TUser>;
77
+ /**
78
+ * Check if nonce date has expired against current delay setting,
79
+ * if no setting was set, then it is considered as not expired.
80
+ *
81
+ * @param nonceDate date when nonce was created
82
+ * @returns true, if nonce has expired and error should be thrown
83
+ */
84
+ protected hasNonceExpired(query: SteamOpenIdQuery): boolean;
67
85
  /**
68
86
  * Checks if error is retryable,
69
87
  * meaning user gets redirected to steam openid page.
@@ -1 +1 @@
1
- {"version":3,"file":"strategy.d.ts","sourceRoot":"","sources":["../src/strategy.ts"],"names":[],"mappings":";AAAA,OAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACjD,OAAc,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAUpC,OAAO,EACL,sBAAsB,EACtB,eAAe,EACf,gBAAgB,EAGhB,qCAAqC,EACrC,wCAAwC,EACxC,cAAc,EACf,MAAM,QAAQ,CAAC;AAEhB;;;;;;;GAOG;AACH,qBAAa,mBAAmB,CAC9B,QAAQ,SACJ,qCAAqC,GACrC,wCAAwC,EAC5C,KAAK,SACD,eAAe,GACf,sBAAsB,GAAG,QAAQ,SAAS,qCAAqC,GAC/E,sBAAsB,GACtB,eAAe,CACnB,SAAQ,QAAQ;IAChB;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAExC;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAErC;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEnC;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAEpC;;OAEG;IACH,SAAS,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC;IAEzC;;;;;;;OAOG;gBACS,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,cAAc,CAAC,KAAK,CAAC;IAW7D;;;;OAIG;IACmB,YAAY,CAAC,GAAG,EAAE,GAAG;IA+B3C;;;;;;;;;;;;;OAaG;IACU,aAAa,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC;IA8BpD;;;;;;;;OAQG;IACH,SAAS,CAAC,gBAAgB,CAAC,GAAG,EAAE,OAAO;IAOvC;;;;;;OAMG;IACH,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,cAAc;IAQ5C;;;;;;OAMG;IACH,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,cAAc;IAI5C;;;;OAIG;IACI,gBAAgB;IAYvB;;;;;;;OAOG;IACH,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG,KAAK,IAAI,gBAAgB;IAcxE;;;;;;OAMG;IACH,SAAS,CAAC,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IASpD;;;;;;OAMG;IACH,SAAS,CAAC,oBAAoB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IAoBzE;;;;OAIG;IACH,SAAS,CAAC,8BAA8B,CAAC,KAAK,EAAE,gBAAgB;IAMhE;;;;;;OAMG;IACH,SAAS,CAAC,oBAAoB,CAAC,QAAQ,EAAE,GAAG;IAQ5C;;;;;OAKG;IACH,SAAS,CAAC,UAAU,CAAC,KAAK,EAAE,gBAAgB;IAM5C;;;;;;;;OAQG;cACa,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IASxD;;;;;;;;;;OAUG;cACa,kBAAkB,CAChC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,sBAAsB,CAAC;CAiCnC"}
1
+ {"version":3,"file":"strategy.d.ts","sourceRoot":"","sources":["../src/strategy.ts"],"names":[],"mappings":";AAAA,OAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACjD,OAAc,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAUpC,OAAO,EACL,sBAAsB,EACtB,eAAe,EACf,gBAAgB,EAGhB,qCAAqC,EACrC,wCAAwC,EACxC,cAAc,EACf,MAAM,QAAQ,CAAC;AAEhB;;;;;;;GAOG;AACH,qBAAa,mBAAmB,CAC9B,QAAQ,SACJ,qCAAqC,GACrC,wCAAwC,EAC5C,KAAK,SACD,eAAe,GACf,sBAAsB,GAAG,QAAQ,SAAS,qCAAqC,GAC/E,sBAAsB,GACtB,eAAe,CACnB,SAAQ,QAAQ;IAChB;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAExC;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAErC;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEnC;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAEpC;;OAEG;IACH,SAAS,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC;IAEzC;;;;;OAKG;IACH,SAAS,CAAC,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;IAEhD;;;;;;;;;;OAUG;gBACS,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,cAAc,CAAC,KAAK,CAAC;IAY7D;;;;OAIG;IACmB,YAAY,CAAC,GAAG,EAAE,GAAG;IA+B3C;;;;;;;;;;;;;OAaG;IACU,aAAa,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC;IAmCpD;;;;;;OAMG;IACH,SAAS,CAAC,eAAe,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO;IAW3D;;;;;;;;OAQG;IACH,SAAS,CAAC,gBAAgB,CAAC,GAAG,EAAE,OAAO;IAOvC;;;;;;OAMG;IACH,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,cAAc;IAQ5C;;;;;;OAMG;IACH,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,cAAc;IAI5C;;;;OAIG;IACI,gBAAgB;IAYvB;;;;;;;OAOG;IACH,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG,KAAK,IAAI,gBAAgB;IAcxE;;;;;;OAMG;IACH,SAAS,CAAC,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IASpD;;;;;;OAMG;IACH,SAAS,CAAC,oBAAoB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IAoBzE;;;;OAIG;IACH,SAAS,CAAC,8BAA8B,CAAC,KAAK,EAAE,gBAAgB;IAMhE;;;;;;OAMG;IACH,SAAS,CAAC,oBAAoB,CAAC,QAAQ,EAAE,GAAG;IAQ5C;;;;;OAKG;IACH,SAAS,CAAC,UAAU,CAAC,KAAK,EAAE,gBAAgB;IAM5C;;;;;;;;OAQG;cACa,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IASxD;;;;;;;;;;OAUG;cACa,kBAAkB,CAChC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,sBAAsB,CAAC;CAiCnC"}
package/dist/strategy.js CHANGED
@@ -23,6 +23,9 @@ class SteamOpenIdStrategy extends passport_1.Strategy {
23
23
  * @param options.returnURL where steam redirects after parameters are passed
24
24
  * @param options.profile if set, we will fetch user's profile from steam api
25
25
  * @param options.apiKey api key to fetch user profile, not used if profile is false
26
+ * @param options.maxNonceTimeDelay optional setting for validating nonce time delay,
27
+ * this is just an extra security measure, it is not required nor recommended, but
28
+ * might be extra layer of security you want to have.
26
29
  * @param verify optional callback, called when user is successfully authenticated
27
30
  */
28
31
  constructor(options, verify) {
@@ -31,6 +34,7 @@ class SteamOpenIdStrategy extends passport_1.Strategy {
31
34
  this.axios = axios_1.default.create();
32
35
  this.returnURL = options.returnURL;
33
36
  this.profile = options.profile;
37
+ this.maxNonceTimeDelay = options.maxNonceTimeDelay;
34
38
  if (options.profile)
35
39
  this.apiKey = options.apiKey;
36
40
  if (verify)
@@ -93,7 +97,9 @@ class SteamOpenIdStrategy extends passport_1.Strategy {
93
97
  if (!this.isQueryValid(query)) {
94
98
  throw new error_1.SteamOpenIdError('Supplied query is invalid.', type_1.SteamOpenIdErrorType.InvalidQuery);
95
99
  }
96
- // TODO: validate nonce time
100
+ if (this.hasNonceExpired(query)) {
101
+ throw new error_1.SteamOpenIdError('Nonce time delay was too big.', type_1.SteamOpenIdErrorType.NonceExpired);
102
+ }
97
103
  const valid = yield this.validateAgainstSteam(query);
98
104
  if (!valid) {
99
105
  throw new error_1.SteamOpenIdError('Failed to validate query against steam.', type_1.SteamOpenIdErrorType.Unauthorized);
@@ -102,6 +108,22 @@ class SteamOpenIdStrategy extends passport_1.Strategy {
102
108
  return yield this.getUser(steamId);
103
109
  });
104
110
  }
111
+ /**
112
+ * Check if nonce date has expired against current delay setting,
113
+ * if no setting was set, then it is considered as not expired.
114
+ *
115
+ * @param nonceDate date when nonce was created
116
+ * @returns true, if nonce has expired and error should be thrown
117
+ */
118
+ hasNonceExpired(query) {
119
+ if (typeof this.maxNonceTimeDelay == 'undefined') {
120
+ return false;
121
+ }
122
+ const nonceDate = new Date(query['openid.response_nonce'].slice(0, 20));
123
+ const nonceSeconds = Math.floor(nonceDate.getTime() / 1000);
124
+ const nowSeconds = Math.floor(Date.now() / 1000);
125
+ return nowSeconds - nonceSeconds > this.maxNonceTimeDelay;
126
+ }
105
127
  /**
106
128
  * Checks if error is retryable,
107
129
  * meaning user gets redirected to steam openid page.
package/dist/type.d.ts CHANGED
@@ -1,6 +1,16 @@
1
1
  import { DoneCallback } from 'passport';
2
2
  export type BaseSteamOpenIdStrategyOptions = {
3
3
  returnURL: string;
4
+ /**
5
+ * Maximum time delay between the nonce creation and the nonce verification,
6
+ * in seconds.
7
+ *
8
+ * nonce includes a timestamp we can validate against the current time,
9
+ * while the steam server validates this as well, you might want to
10
+ * set maximum number of seconds between the nonce creation and the nonce
11
+ * verification.
12
+ */
13
+ maxNonceTimeDelay?: number;
4
14
  };
5
15
  export type SteamOpenIdStrategyOptionsWithProfile = {
6
16
  profile: true;
@@ -31,7 +41,11 @@ export declare enum SteamOpenIdErrorType {
31
41
  /**
32
42
  * SteamId is not valid.
33
43
  */
34
- InvalidSteamId = 3
44
+ InvalidSteamId = 3,
45
+ /**
46
+ * Nonce has expired.
47
+ */
48
+ NonceExpired = 4
35
49
  }
36
50
  /** When profile is not used, we just send a steamid. */
37
51
  export type SteamOpenIdUser = {
@@ -1 +1 @@
1
- {"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../src/type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,MAAM,MAAM,8BAA8B,GAAG;IAC3C,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,qCAAqC,GAAG;IAClD,OAAO,EAAE,IAAI,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,8BAA8B,CAAC;AAEnC,MAAM,MAAM,wCAAwC,GAAG;IACrD,OAAO,EAAE,KAAK,CAAC;CAChB,GAAG,8BAA8B,CAAC;AAEnC,MAAM,MAAM,0BAA0B,GAClC,qCAAqC,GACrC,wCAAwC,CAAC;AAE7C;;;;GAIG;AACH,oBAAY,oBAAoB;IAC9B;;OAEG;IACH,WAAW,IAAI;IACf;;OAEG;IACH,YAAY,IAAI;IAChB;;OAEG;IACH,YAAY,IAAI;IAChB;;OAEG;IACH,cAAc,IAAI;CACnB;AAED,wDAAwD;AACxD,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,+BAA+B;AAC/B,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE;QACR,OAAO,EAAE,sBAAsB,EAAE,CAAC;KACnC,CAAC;CACH,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,wBAAwB,EAAE,MAAM,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,CACxB,KAAK,SAAS,eAAe,GAAG,sBAAsB,IACpD,CAAC,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,KAAK,GAAG,CAAC;AAE9E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,uBAAuB,EAAE,MAAM,CAAC;IAChC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC"}
1
+ {"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../src/type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,MAAM,MAAM,8BAA8B,GAAG;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;;;OAQG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,qCAAqC,GAAG;IAClD,OAAO,EAAE,IAAI,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,8BAA8B,CAAC;AAEnC,MAAM,MAAM,wCAAwC,GAAG;IACrD,OAAO,EAAE,KAAK,CAAC;CAChB,GAAG,8BAA8B,CAAC;AAEnC,MAAM,MAAM,0BAA0B,GAClC,qCAAqC,GACrC,wCAAwC,CAAC;AAE7C;;;;GAIG;AACH,oBAAY,oBAAoB;IAC9B;;OAEG;IACH,WAAW,IAAI;IACf;;OAEG;IACH,YAAY,IAAI;IAChB;;OAEG;IACH,YAAY,IAAI;IAChB;;OAEG;IACH,cAAc,IAAI;IAClB;;OAEG;IACH,YAAY,IAAI;CACjB;AAED,wDAAwD;AACxD,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,+BAA+B;AAC/B,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE;QACR,OAAO,EAAE,sBAAsB,EAAE,CAAC;KACnC,CAAC;CACH,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,wBAAwB,EAAE,MAAM,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,CACxB,KAAK,SAAS,eAAe,GAAG,sBAAsB,IACpD,CAAC,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,KAAK,GAAG,CAAC;AAE9E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,uBAAuB,EAAE,MAAM,CAAC;IAChC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC"}
package/dist/type.js CHANGED
@@ -24,4 +24,8 @@ var SteamOpenIdErrorType;
24
24
  * SteamId is not valid.
25
25
  */
26
26
  SteamOpenIdErrorType[SteamOpenIdErrorType["InvalidSteamId"] = 3] = "InvalidSteamId";
27
+ /**
28
+ * Nonce has expired.
29
+ */
30
+ SteamOpenIdErrorType[SteamOpenIdErrorType["NonceExpired"] = 4] = "NonceExpired";
27
31
  })(SteamOpenIdErrorType || (exports.SteamOpenIdErrorType = SteamOpenIdErrorType = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "passport-steam-openid",
3
- "version": "1.0.3",
3
+ "version": "1.1.0",
4
4
  "description": "Passport strategy for authenticating with steam openid without the use of 3rd party openid packages.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -10,7 +10,7 @@
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "dotenv": "^16.3.1",
13
- "express": "^4.18.2",
13
+ "express": "^4.19.2",
14
14
  "express-session": "^1.17.3",
15
15
  "passport": "^0.6.0",
16
16
  "passport-steam-openid": "^1.0.0"
@@ -710,6 +710,29 @@
710
710
  "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
711
711
  "dev": true
712
712
  },
713
+ "node_modules/body-parser": {
714
+ "version": "1.20.2",
715
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
716
+ "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
717
+ "dependencies": {
718
+ "bytes": "3.1.2",
719
+ "content-type": "~1.0.5",
720
+ "debug": "2.6.9",
721
+ "depd": "2.0.0",
722
+ "destroy": "1.2.0",
723
+ "http-errors": "2.0.0",
724
+ "iconv-lite": "0.4.24",
725
+ "on-finished": "2.4.1",
726
+ "qs": "6.11.0",
727
+ "raw-body": "2.5.2",
728
+ "type-is": "~1.6.18",
729
+ "unpipe": "1.0.0"
730
+ },
731
+ "engines": {
732
+ "node": ">= 0.8",
733
+ "npm": "1.2.8000 || >= 1.4.16"
734
+ }
735
+ },
713
736
  "node_modules/brace-expansion": {
714
737
  "version": "1.1.11",
715
738
  "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -741,12 +764,18 @@
741
764
  }
742
765
  },
743
766
  "node_modules/call-bind": {
744
- "version": "1.0.2",
745
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
746
- "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
767
+ "version": "1.0.7",
768
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
769
+ "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
747
770
  "dependencies": {
748
- "function-bind": "^1.1.1",
749
- "get-intrinsic": "^1.0.2"
771
+ "es-define-property": "^1.0.0",
772
+ "es-errors": "^1.3.0",
773
+ "function-bind": "^1.1.2",
774
+ "get-intrinsic": "^1.2.4",
775
+ "set-function-length": "^1.2.1"
776
+ },
777
+ "engines": {
778
+ "node": ">= 0.4"
750
779
  },
751
780
  "funding": {
752
781
  "url": "https://github.com/sponsors/ljharb"
@@ -832,9 +861,9 @@
832
861
  }
833
862
  },
834
863
  "node_modules/cookie": {
835
- "version": "0.5.0",
836
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
837
- "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
864
+ "version": "0.6.0",
865
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
866
+ "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
838
867
  "engines": {
839
868
  "node": ">= 0.6"
840
869
  }
@@ -872,6 +901,22 @@
872
901
  "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
873
902
  "dev": true
874
903
  },
904
+ "node_modules/define-data-property": {
905
+ "version": "1.1.4",
906
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
907
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
908
+ "dependencies": {
909
+ "es-define-property": "^1.0.0",
910
+ "es-errors": "^1.3.0",
911
+ "gopd": "^1.0.1"
912
+ },
913
+ "engines": {
914
+ "node": ">= 0.4"
915
+ },
916
+ "funding": {
917
+ "url": "https://github.com/sponsors/ljharb"
918
+ }
919
+ },
875
920
  "node_modules/delayed-stream": {
876
921
  "version": "1.0.0",
877
922
  "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -945,6 +990,25 @@
945
990
  "node": ">= 0.8"
946
991
  }
947
992
  },
993
+ "node_modules/es-define-property": {
994
+ "version": "1.0.0",
995
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
996
+ "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
997
+ "dependencies": {
998
+ "get-intrinsic": "^1.2.4"
999
+ },
1000
+ "engines": {
1001
+ "node": ">= 0.4"
1002
+ }
1003
+ },
1004
+ "node_modules/es-errors": {
1005
+ "version": "1.3.0",
1006
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
1007
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
1008
+ "engines": {
1009
+ "node": ">= 0.4"
1010
+ }
1011
+ },
948
1012
  "node_modules/escape-html": {
949
1013
  "version": "1.0.3",
950
1014
  "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -1222,16 +1286,16 @@
1222
1286
  }
1223
1287
  },
1224
1288
  "node_modules/express": {
1225
- "version": "4.18.2",
1226
- "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
1227
- "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
1289
+ "version": "4.19.2",
1290
+ "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
1291
+ "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
1228
1292
  "dependencies": {
1229
1293
  "accepts": "~1.3.8",
1230
1294
  "array-flatten": "1.1.1",
1231
- "body-parser": "1.20.1",
1295
+ "body-parser": "1.20.2",
1232
1296
  "content-disposition": "0.5.4",
1233
1297
  "content-type": "~1.0.4",
1234
- "cookie": "0.5.0",
1298
+ "cookie": "0.6.0",
1235
1299
  "cookie-signature": "1.0.6",
1236
1300
  "debug": "2.6.9",
1237
1301
  "depd": "2.0.0",
@@ -1288,57 +1352,6 @@
1288
1352
  "node": ">= 0.6"
1289
1353
  }
1290
1354
  },
1291
- "node_modules/express/node_modules/body-parser": {
1292
- "version": "1.20.1",
1293
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
1294
- "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
1295
- "dependencies": {
1296
- "bytes": "3.1.2",
1297
- "content-type": "~1.0.4",
1298
- "debug": "2.6.9",
1299
- "depd": "2.0.0",
1300
- "destroy": "1.2.0",
1301
- "http-errors": "2.0.0",
1302
- "iconv-lite": "0.4.24",
1303
- "on-finished": "2.4.1",
1304
- "qs": "6.11.0",
1305
- "raw-body": "2.5.1",
1306
- "type-is": "~1.6.18",
1307
- "unpipe": "1.0.0"
1308
- },
1309
- "engines": {
1310
- "node": ">= 0.8",
1311
- "npm": "1.2.8000 || >= 1.4.16"
1312
- }
1313
- },
1314
- "node_modules/express/node_modules/qs": {
1315
- "version": "6.11.0",
1316
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
1317
- "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
1318
- "dependencies": {
1319
- "side-channel": "^1.0.4"
1320
- },
1321
- "engines": {
1322
- "node": ">=0.6"
1323
- },
1324
- "funding": {
1325
- "url": "https://github.com/sponsors/ljharb"
1326
- }
1327
- },
1328
- "node_modules/express/node_modules/raw-body": {
1329
- "version": "2.5.1",
1330
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
1331
- "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
1332
- "dependencies": {
1333
- "bytes": "3.1.2",
1334
- "http-errors": "2.0.0",
1335
- "iconv-lite": "0.4.24",
1336
- "unpipe": "1.0.0"
1337
- },
1338
- "engines": {
1339
- "node": ">= 0.8"
1340
- }
1341
- },
1342
1355
  "node_modules/fast-deep-equal": {
1343
1356
  "version": "3.1.3",
1344
1357
  "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -1477,9 +1490,9 @@
1477
1490
  "dev": true
1478
1491
  },
1479
1492
  "node_modules/follow-redirects": {
1480
- "version": "1.15.4",
1481
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
1482
- "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
1493
+ "version": "1.15.6",
1494
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
1495
+ "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
1483
1496
  "funding": [
1484
1497
  {
1485
1498
  "type": "individual",
@@ -1531,19 +1544,26 @@
1531
1544
  "dev": true
1532
1545
  },
1533
1546
  "node_modules/function-bind": {
1534
- "version": "1.1.1",
1535
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
1536
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
1547
+ "version": "1.1.2",
1548
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
1549
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
1550
+ "funding": {
1551
+ "url": "https://github.com/sponsors/ljharb"
1552
+ }
1537
1553
  },
1538
1554
  "node_modules/get-intrinsic": {
1539
- "version": "1.2.1",
1540
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
1541
- "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==",
1555
+ "version": "1.2.4",
1556
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
1557
+ "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
1542
1558
  "dependencies": {
1543
- "function-bind": "^1.1.1",
1544
- "has": "^1.0.3",
1559
+ "es-errors": "^1.3.0",
1560
+ "function-bind": "^1.1.2",
1545
1561
  "has-proto": "^1.0.1",
1546
- "has-symbols": "^1.0.3"
1562
+ "has-symbols": "^1.0.3",
1563
+ "hasown": "^2.0.0"
1564
+ },
1565
+ "engines": {
1566
+ "node": ">= 0.4"
1547
1567
  },
1548
1568
  "funding": {
1549
1569
  "url": "https://github.com/sponsors/ljharb"
@@ -1616,6 +1636,17 @@
1616
1636
  "url": "https://github.com/sponsors/sindresorhus"
1617
1637
  }
1618
1638
  },
1639
+ "node_modules/gopd": {
1640
+ "version": "1.0.1",
1641
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
1642
+ "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
1643
+ "dependencies": {
1644
+ "get-intrinsic": "^1.1.3"
1645
+ },
1646
+ "funding": {
1647
+ "url": "https://github.com/sponsors/ljharb"
1648
+ }
1649
+ },
1619
1650
  "node_modules/grapheme-splitter": {
1620
1651
  "version": "1.0.4",
1621
1652
  "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
@@ -1628,17 +1659,6 @@
1628
1659
  "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
1629
1660
  "dev": true
1630
1661
  },
1631
- "node_modules/has": {
1632
- "version": "1.0.3",
1633
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
1634
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
1635
- "dependencies": {
1636
- "function-bind": "^1.1.1"
1637
- },
1638
- "engines": {
1639
- "node": ">= 0.4.0"
1640
- }
1641
- },
1642
1662
  "node_modules/has-flag": {
1643
1663
  "version": "4.0.0",
1644
1664
  "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -1648,10 +1668,21 @@
1648
1668
  "node": ">=8"
1649
1669
  }
1650
1670
  },
1671
+ "node_modules/has-property-descriptors": {
1672
+ "version": "1.0.2",
1673
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
1674
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
1675
+ "dependencies": {
1676
+ "es-define-property": "^1.0.0"
1677
+ },
1678
+ "funding": {
1679
+ "url": "https://github.com/sponsors/ljharb"
1680
+ }
1681
+ },
1651
1682
  "node_modules/has-proto": {
1652
- "version": "1.0.1",
1653
- "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
1654
- "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
1683
+ "version": "1.0.3",
1684
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
1685
+ "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
1655
1686
  "engines": {
1656
1687
  "node": ">= 0.4"
1657
1688
  },
@@ -1670,6 +1701,17 @@
1670
1701
  "url": "https://github.com/sponsors/ljharb"
1671
1702
  }
1672
1703
  },
1704
+ "node_modules/hasown": {
1705
+ "version": "2.0.2",
1706
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
1707
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
1708
+ "dependencies": {
1709
+ "function-bind": "^1.1.2"
1710
+ },
1711
+ "engines": {
1712
+ "node": ">= 0.4"
1713
+ }
1714
+ },
1673
1715
  "node_modules/http-errors": {
1674
1716
  "version": "2.0.0",
1675
1717
  "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
@@ -1979,9 +2021,9 @@
1979
2021
  }
1980
2022
  },
1981
2023
  "node_modules/object-inspect": {
1982
- "version": "1.12.3",
1983
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
1984
- "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
2024
+ "version": "1.13.1",
2025
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
2026
+ "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
1985
2027
  "funding": {
1986
2028
  "url": "https://github.com/sponsors/ljharb"
1987
2029
  }
@@ -2236,6 +2278,20 @@
2236
2278
  "node": ">=6"
2237
2279
  }
2238
2280
  },
2281
+ "node_modules/qs": {
2282
+ "version": "6.11.0",
2283
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
2284
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
2285
+ "dependencies": {
2286
+ "side-channel": "^1.0.4"
2287
+ },
2288
+ "engines": {
2289
+ "node": ">=0.6"
2290
+ },
2291
+ "funding": {
2292
+ "url": "https://github.com/sponsors/ljharb"
2293
+ }
2294
+ },
2239
2295
  "node_modules/queue-microtask": {
2240
2296
  "version": "1.2.3",
2241
2297
  "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -2272,6 +2328,20 @@
2272
2328
  "node": ">= 0.6"
2273
2329
  }
2274
2330
  },
2331
+ "node_modules/raw-body": {
2332
+ "version": "2.5.2",
2333
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
2334
+ "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
2335
+ "dependencies": {
2336
+ "bytes": "3.1.2",
2337
+ "http-errors": "2.0.0",
2338
+ "iconv-lite": "0.4.24",
2339
+ "unpipe": "1.0.0"
2340
+ },
2341
+ "engines": {
2342
+ "node": ">= 0.8"
2343
+ }
2344
+ },
2275
2345
  "node_modules/resolve-from": {
2276
2346
  "version": "4.0.0",
2277
2347
  "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
@@ -2410,6 +2480,22 @@
2410
2480
  "node": ">= 0.8.0"
2411
2481
  }
2412
2482
  },
2483
+ "node_modules/set-function-length": {
2484
+ "version": "1.2.2",
2485
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
2486
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
2487
+ "dependencies": {
2488
+ "define-data-property": "^1.1.4",
2489
+ "es-errors": "^1.3.0",
2490
+ "function-bind": "^1.1.2",
2491
+ "get-intrinsic": "^1.2.4",
2492
+ "gopd": "^1.0.1",
2493
+ "has-property-descriptors": "^1.0.2"
2494
+ },
2495
+ "engines": {
2496
+ "node": ">= 0.4"
2497
+ }
2498
+ },
2413
2499
  "node_modules/setprototypeof": {
2414
2500
  "version": "1.2.0",
2415
2501
  "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
@@ -2437,13 +2523,17 @@
2437
2523
  }
2438
2524
  },
2439
2525
  "node_modules/side-channel": {
2440
- "version": "1.0.4",
2441
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
2442
- "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
2526
+ "version": "1.0.6",
2527
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
2528
+ "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
2443
2529
  "dependencies": {
2444
- "call-bind": "^1.0.0",
2445
- "get-intrinsic": "^1.0.2",
2446
- "object-inspect": "^1.9.0"
2530
+ "call-bind": "^1.0.7",
2531
+ "es-errors": "^1.3.0",
2532
+ "get-intrinsic": "^1.2.4",
2533
+ "object-inspect": "^1.13.1"
2534
+ },
2535
+ "engines": {
2536
+ "node": ">= 0.4"
2447
2537
  },
2448
2538
  "funding": {
2449
2539
  "url": "https://github.com/sponsors/ljharb"
@@ -13,7 +13,7 @@
13
13
  "license": "MIT",
14
14
  "dependencies": {
15
15
  "dotenv": "^16.3.1",
16
- "express": "^4.18.2",
16
+ "express": "^4.19.2",
17
17
  "express-session": "^1.17.3",
18
18
  "passport": "^0.6.0",
19
19
  "passport-steam-openid": "^1.0.0"
package/src/strategy.ts CHANGED
@@ -66,12 +66,23 @@ export class SteamOpenIdStrategy<
66
66
  */
67
67
  protected verify?: VerifyCallback<TUser>;
68
68
 
69
+ /**
70
+ * Optional setting for validating nonce time delay,
71
+ * in seconds.
72
+ *
73
+ * Measures time between nonce creation date and verification.
74
+ */
75
+ protected maxNonceTimeDelay: number | undefined;
76
+
69
77
  /**
70
78
  * @constructor
71
79
  *
72
80
  * @param options.returnURL where steam redirects after parameters are passed
73
81
  * @param options.profile if set, we will fetch user's profile from steam api
74
82
  * @param options.apiKey api key to fetch user profile, not used if profile is false
83
+ * @param options.maxNonceTimeDelay optional setting for validating nonce time delay,
84
+ * this is just an extra security measure, it is not required nor recommended, but
85
+ * might be extra layer of security you want to have.
75
86
  * @param verify optional callback, called when user is successfully authenticated
76
87
  */
77
88
  constructor(options: TOptions, verify?: VerifyCallback<TUser>) {
@@ -81,6 +92,7 @@ export class SteamOpenIdStrategy<
81
92
  this.axios = axios.create();
82
93
  this.returnURL = options.returnURL;
83
94
  this.profile = options.profile;
95
+ this.maxNonceTimeDelay = options.maxNonceTimeDelay;
84
96
  if (options.profile) this.apiKey = options.apiKey;
85
97
  if (verify) this.verify = verify;
86
98
  }
@@ -151,7 +163,12 @@ export class SteamOpenIdStrategy<
151
163
  );
152
164
  }
153
165
 
154
- // TODO: validate nonce time
166
+ if (this.hasNonceExpired(query)) {
167
+ throw new SteamOpenIdError(
168
+ 'Nonce time delay was too big.',
169
+ SteamOpenIdErrorType.NonceExpired,
170
+ );
171
+ }
155
172
 
156
173
  const valid = await this.validateAgainstSteam(query);
157
174
  if (!valid) {
@@ -165,6 +182,24 @@ export class SteamOpenIdStrategy<
165
182
  return await this.getUser(steamId);
166
183
  }
167
184
 
185
+ /**
186
+ * Check if nonce date has expired against current delay setting,
187
+ * if no setting was set, then it is considered as not expired.
188
+ *
189
+ * @param nonceDate date when nonce was created
190
+ * @returns true, if nonce has expired and error should be thrown
191
+ */
192
+ protected hasNonceExpired(query: SteamOpenIdQuery): boolean {
193
+ if (typeof this.maxNonceTimeDelay == 'undefined') {
194
+ return false;
195
+ }
196
+
197
+ const nonceDate = new Date(query['openid.response_nonce'].slice(0, 20));
198
+ const nonceSeconds = Math.floor(nonceDate.getTime() / 1000);
199
+ const nowSeconds = Math.floor(Date.now() / 1000);
200
+ return nowSeconds - nonceSeconds > this.maxNonceTimeDelay;
201
+ }
202
+
168
203
  /**
169
204
  * Checks if error is retryable,
170
205
  * meaning user gets redirected to steam openid page.
package/src/type.ts CHANGED
@@ -2,6 +2,16 @@ import { DoneCallback } from 'passport';
2
2
 
3
3
  export type BaseSteamOpenIdStrategyOptions = {
4
4
  returnURL: string;
5
+ /**
6
+ * Maximum time delay between the nonce creation and the nonce verification,
7
+ * in seconds.
8
+ *
9
+ * nonce includes a timestamp we can validate against the current time,
10
+ * while the steam server validates this as well, you might want to
11
+ * set maximum number of seconds between the nonce creation and the nonce
12
+ * verification.
13
+ */
14
+ maxNonceTimeDelay?: number;
5
15
  };
6
16
 
7
17
  export type SteamOpenIdStrategyOptionsWithProfile = {
@@ -39,6 +49,10 @@ export enum SteamOpenIdErrorType {
39
49
  * SteamId is not valid.
40
50
  */
41
51
  InvalidSteamId = 3,
52
+ /**
53
+ * Nonce has expired.
54
+ */
55
+ NonceExpired = 4,
42
56
  }
43
57
 
44
58
  /** When profile is not used, we just send a steamid. */
@@ -1,12 +1,18 @@
1
- import { VALID_NONCE, VALID_OPENID_ENDPOINT } from '../../src';
1
+ import {
2
+ SteamOpenIdQuery,
3
+ VALID_NONCE,
4
+ VALID_OPENID_ENDPOINT,
5
+ } from '../../src';
2
6
 
3
7
  export const RETURN_URL = '/auth/steam';
4
8
 
9
+ export const getISODate = (date: Date) => date.toISOString().split('.')[0] + 'Z';
10
+
5
11
  export const query: {
6
- properties: Record<string, string>;
7
- get(): Record<string, string>;
8
- change(change: Record<string, string>): Record<string, string>;
9
- remove(property: string): Record<string, string>;
12
+ properties: SteamOpenIdQuery;
13
+ get(): SteamOpenIdQuery;
14
+ change(change: Partial<SteamOpenIdQuery>): SteamOpenIdQuery;
15
+ remove(property: keyof SteamOpenIdQuery): SteamOpenIdQuery;
10
16
  } = {
11
17
  /**
12
18
  * Valid query properties
@@ -18,22 +24,22 @@ export const query: {
18
24
  'openid.claimed_id': `https://steamcommunity.com/openid/id/76561197960435530`,
19
25
  'openid.return_to': RETURN_URL,
20
26
  'openid.op_endpoint': VALID_OPENID_ENDPOINT,
21
- 'openid.response_nonce': `${new Date().toJSON()}8df86bac92ad1addaf3735a5aabdc6e2a7`,
27
+ 'openid.response_nonce': `${getISODate(new Date())}8df86bac92ad1addaf3735a5aabdc6e2a7`,
22
28
  'openid.assoc_handle': '1234567890',
23
29
  'openid.signed':
24
30
  'signed,op_endpoint,claimed_id,identity,return_to,response_nonce,assoc_handle',
25
31
  'openid.sig': 'dc6e2a79de2c6aceac495ad5f4c6b6e0bfe30',
26
32
  },
27
33
 
28
- get() {
34
+ get(): SteamOpenIdQuery {
29
35
  return { ...this.properties };
30
36
  },
31
37
 
32
- change(change: Record<string, string>) {
38
+ change(change: Partial<SteamOpenIdQuery>): SteamOpenIdQuery {
33
39
  return { ...this.get(), ...change };
34
40
  },
35
41
 
36
- remove(property: string) {
42
+ remove(property: keyof SteamOpenIdQuery): SteamOpenIdQuery {
37
43
  const properties = this.get();
38
44
  delete properties[property];
39
45
  return properties;
package/test/strategy.ts CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  VALID_OPENID_ENDPOINT,
16
16
  PLAYER_SUMMARY_URL,
17
17
  } from '../src';
18
- import { RETURN_URL, query } from './setup/data';
18
+ import { RETURN_URL, getISODate, query } from './setup/data';
19
19
 
20
20
  chai.use(chaiAsPromised);
21
21
 
@@ -214,12 +214,14 @@ describe('SteamOpenIdStrategy Unit Test', () => {
214
214
  let getQueryStub: sinon.SinonStub;
215
215
  let hasAuthQueryStub: sinon.SinonStub;
216
216
  let isQueryValidStub: sinon.SinonStub;
217
+ let hasNonceExpiredStub: sinon.SinonStub;
217
218
  let validateAgainstSteamStub: sinon.SinonStub;
218
219
 
219
220
  beforeEach(() => {
220
221
  getQueryStub = sinon.stub(strategy as any, 'getQuery').returns(query);
221
222
  hasAuthQueryStub = sinon.stub(strategy as any, 'hasAuthQuery');
222
223
  isQueryValidStub = sinon.stub(strategy as any, 'isQueryValid');
224
+ hasNonceExpiredStub = sinon.stub(strategy as any, 'hasNonceExpired');
223
225
  validateAgainstSteamStub = sinon.stub(
224
226
  strategy as any,
225
227
  'validateAgainstSteam',
@@ -237,6 +239,7 @@ describe('SteamOpenIdStrategy Unit Test', () => {
237
239
  hasAuthQueryStub.returns(true);
238
240
  isQueryValidStub.returns(true);
239
241
  validateAgainstSteamStub.resolves(true);
242
+ hasNonceExpiredStub.returns(false);
240
243
 
241
244
  const steamid = '76561197960435530';
242
245
  const user = { steamid: '76561197960435530' };
@@ -253,6 +256,8 @@ describe('SteamOpenIdStrategy Unit Test', () => {
253
256
  expect(getUserStub.calledWithExactly(steamid)).equal(true);
254
257
  expect(isQueryValidStub.callCount).equal(1);
255
258
  expect(isQueryValidStub.calledWithExactly(query)).equal(true);
259
+ expect(hasNonceExpiredStub.callCount).equal(1);
260
+ expect(hasNonceExpiredStub.calledWithExactly(query)).equal(true);
256
261
  expect(validateAgainstSteamStub.callCount).equal(1);
257
262
  expect(validateAgainstSteamStub.calledWithExactly(query)).equal(true);
258
263
  });
@@ -269,6 +274,9 @@ describe('SteamOpenIdStrategy Unit Test', () => {
269
274
 
270
275
  expect(err).to.be.instanceOf(SteamOpenIdError);
271
276
  expect(err).to.have.property('code', SteamOpenIdErrorType.InvalidMode);
277
+ expect(isQueryValidStub.callCount).equal(0);
278
+ expect(hasNonceExpiredStub.callCount).equal(0);
279
+ expect(validateAgainstSteamStub.callCount).equal(0);
272
280
  });
273
281
 
274
282
  it('Query is invalid', async () => {
@@ -286,11 +294,35 @@ describe('SteamOpenIdStrategy Unit Test', () => {
286
294
  expect(err).to.have.property('code', SteamOpenIdErrorType.InvalidQuery);
287
295
  expect(isQueryValidStub.callCount).equal(1);
288
296
  expect(isQueryValidStub.calledWithExactly(query)).equal(true);
297
+ expect(hasNonceExpiredStub.callCount).equal(0);
298
+ expect(validateAgainstSteamStub.callCount).equal(0);
299
+ });
300
+
301
+ it('Nonce has expired', async () => {
302
+ hasAuthQueryStub.returns(true);
303
+ isQueryValidStub.returns(true);
304
+ hasNonceExpiredStub.returns(true);
305
+
306
+ let err: any;
307
+ try {
308
+ await strategy.handleRequest(request);
309
+ } catch (e) {
310
+ err = e;
311
+ }
312
+
313
+ expect(err).to.be.instanceOf(SteamOpenIdError);
314
+ expect(err).to.have.property('code', SteamOpenIdErrorType.NonceExpired);
315
+ expect(isQueryValidStub.callCount).equal(1);
316
+ expect(isQueryValidStub.calledWithExactly(query)).equal(true);
317
+ expect(hasNonceExpiredStub.callCount).equal(1);
318
+ expect(hasNonceExpiredStub.calledWithExactly(query)).equal(true);
319
+ expect(validateAgainstSteamStub.callCount).equal(0);
289
320
  });
290
321
 
291
322
  it('Steam rejects this authentication request', async () => {
292
323
  hasAuthQueryStub.returns(true);
293
324
  isQueryValidStub.returns(true);
325
+ hasNonceExpiredStub.returns(false);
294
326
  validateAgainstSteamStub.resolves(false);
295
327
 
296
328
  let err: any;
@@ -304,6 +336,8 @@ describe('SteamOpenIdStrategy Unit Test', () => {
304
336
  expect(err).to.have.property('code', SteamOpenIdErrorType.Unauthorized);
305
337
  expect(isQueryValidStub.callCount).equal(1);
306
338
  expect(isQueryValidStub.calledWithExactly(query)).equal(true);
339
+ expect(hasNonceExpiredStub.callCount).equal(1);
340
+ expect(hasNonceExpiredStub.calledWithExactly(query)).equal(true);
307
341
  expect(validateAgainstSteamStub.callCount).equal(1);
308
342
  expect(validateAgainstSteamStub.calledWithExactly(query)).equal(true);
309
343
  });
@@ -722,4 +756,40 @@ describe('SteamOpenIdStrategy Unit Test', () => {
722
756
  expect(err).to.have.property('code', SteamOpenIdErrorType.InvalidSteamId);
723
757
  });
724
758
  });
759
+
760
+ describe('hasNonceExpired', () => {
761
+ const HOUR = 1000 * 60 * 60;
762
+
763
+ it('No setting set, could not expire', () => {
764
+ expect(strategy['hasNonceExpired'](query.properties)).equal(false);
765
+ });
766
+
767
+ it('Setting set, nonce expired', () => {
768
+ strategy['maxNonceTimeDelay'] = HOUR / 1000;
769
+
770
+ expect(
771
+ strategy['hasNonceExpired'](
772
+ query.change({
773
+ 'openid.response_nonce': `${getISODate(
774
+ new Date(Date.now() - 2 * HOUR),
775
+ )}8df86bac92ad1addaf3735a5aabdc6e2a7`,
776
+ }),
777
+ ),
778
+ ).equal(true);
779
+ });
780
+
781
+ it('Setting set, nonce not expired', () => {
782
+ strategy['maxNonceTimeDelay'] = HOUR / 1000;
783
+
784
+ expect(
785
+ strategy['hasNonceExpired'](
786
+ query.change({
787
+ 'openid.response_nonce': `${getISODate(
788
+ new Date(Date.now() + HOUR / 2),
789
+ )}8df86bac92ad1addaf3735a5aabdc6e2a7`,
790
+ }),
791
+ ),
792
+ ).equal(false);
793
+ });
794
+ });
725
795
  });