Page MenuHomePhabricator

D6022.id20089.diff
No OneTemporary

D6022.id20089.diff

diff --git a/keyserver/src/responders/landing-handler.js b/keyserver/src/responders/landing-handler.js
--- a/keyserver/src/responders/landing-handler.js
+++ b/keyserver/src/responders/landing-handler.js
@@ -7,6 +7,8 @@
import ReactDOMServer from 'react-dom/server';
import { promisify } from 'util';
+import { isValidSIWENonce } from 'lib/utils/siwe-utils.js';
+
import { type LandingSSRProps } from '../landing/landing-ssr.react';
import { waitForStream } from '../utils/json-stream';
import { getAndAssertLandingURLFacts } from '../utils/urls';
@@ -104,6 +106,16 @@
async function landingResponder(req: $Request, res: $Response) {
const siweNonce = req.header('siwe-nonce');
+ if (
+ siweNonce !== null &&
+ siweNonce !== undefined &&
+ !isValidSIWENonce(siweNonce)
+ ) {
+ res.status(400).send({
+ message: 'Invalid nonce in siwe-nonce header.',
+ });
+ return;
+ }
const [{ jsURL, fontURLs, cssInclude }, LandingSSR] = await Promise.all([
getAssetInfo(),
getWebpackCompiledRootComponentForSSR(),
diff --git a/lib/utils/siwe-utils.js b/lib/utils/siwe-utils.js
new file mode 100644
--- /dev/null
+++ b/lib/utils/siwe-utils.js
@@ -0,0 +1,8 @@
+// @flow
+
+const siweNonceRegex: RegExp = /^[a-zA-Z0-9]{17}$/;
+function isValidSIWENonce(candidate: string): boolean {
+ return siweNonceRegex.test(candidate);
+}
+
+export { isValidSIWENonce };
diff --git a/lib/utils/siwe-utils.test.js b/lib/utils/siwe-utils.test.js
new file mode 100644
--- /dev/null
+++ b/lib/utils/siwe-utils.test.js
@@ -0,0 +1,78 @@
+// @flow
+
+import { isValidSIWENonce } from './siwe-utils.js';
+
+describe('SIWE Nonce utils', () => {
+ it('isValidSIWENonce should match valid nonces', () => {
+ // Following valid nonces generated using `siwe/generateNonce()` function
+ const validNonces = [
+ '1VxXbANmmHLFP4eks',
+ '2MmJuAAseMtLv5mCn',
+ '2USPurs7uBwua8S8x',
+ '3Qk22CmMo65LpaG9c',
+ '4QXu7RFVlXreNzQrK',
+ '5BLyDYtuk7coJCvzC',
+ '7K2JD4wCmGrKsTkOF',
+ 'Akx19qnKDuvB48SZC',
+ 'aTirbrzPTKVPOCl4D',
+ 'bkjdjOg4tA7Xpy452',
+ 'BNhdFo59dEribfobg',
+ 'buf0Wxv4bGLjcWT3c',
+ 'CoXCHoJTCdVy5sTtf',
+ 'd7oetTb1wJuvhCA4l',
+ 'DMaRtZ6yiLRnuyafK',
+ 'e7Sdl1z6EQiXCN8l9',
+ 'EF4Hdiej0gxDmBjvy',
+ 'EFauh8CSAIRlDwOLg',
+ 'eqbMxIOjiJdjskqlN',
+ 'fOYFxCD5ir430agxl',
+ 'GCN1lI61eRvHUws1M',
+ 'gGDMKiPcbykhCwzMO',
+ 'gJCSvNZ1pHksy5TpJ',
+ 'gzgnURrK65KTlfYBp',
+ 'H4wZ6w5qiisbulWzI',
+ 'hNJFuzAdnSEU4bx8X',
+ 'HWaO4nN9aDGH8AnaA',
+ 'IU5DJWa9TUXz5H1tV',
+ 'kDE8OPvsheXIihCj4',
+ 'LaQ8i3ZJY3DpdwCPI',
+ 'LBWHU6XM4MFjLqXrd',
+ 'lf3hoCBuqTdsl58EA',
+ 'm1nx1X4EQJRL3Sg9b',
+ 'Mk6t3PKZnL8jwcd0n',
+ 'mnkumoUJFtI9Zhxdu',
+ 'OPL9f2NvQL3d8rHce',
+ 'orJqvnFu0dsIDuPPv',
+ 'ox9zchmtBRDUxhiKr',
+ 'q35RUCfsoGHszDi2W',
+ 'qc13k7CZp9noVr9Xm',
+ 'QnyXVsOu4ul4E8UTT',
+ 'RBDJVgUWxrxVoOYpg',
+ 'u3vxhrCwHihNlwZOf',
+ 'wBF0fzrjy4oWrager',
+ 'xEmvoMx72izf48yKN',
+ 'Xha2QfepadZtolkTi',
+ 'XZLvZW0VqcK3og31l',
+ 'yGMxs0bt7r15KxAFF',
+ 'YmHPiTCKGzTMyWe3x',
+ 'YzxFDqTd84pTDbcJP',
+ ];
+
+ validNonces.forEach(nonce => {
+ expect(isValidSIWENonce(nonce)).toBe(true);
+ });
+ });
+
+ it('isValidSIWENonce should fail if nonce is wrong length', () => {
+ const shortNonce = '1VxXbANmmHLFP4ek';
+ expect(isValidSIWENonce(shortNonce)).toBe(false);
+
+ const longNonce = '1VxXbANmmHLFP4eks1';
+ expect(isValidSIWENonce(longNonce)).toBe(false);
+ });
+
+ it('isValidSIWENonce should fail if nonce has invalid characters', () => {
+ const invalidNonce = '1VxXbANmmHLFP4ek!';
+ expect(isValidSIWENonce(invalidNonce)).toBe(false);
+ });
+});

File Metadata

Mime Type
text/plain
Expires
Sat, Oct 5, 6:21 PM (21 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2244863
Default Alt Text
D6022.id20089.diff (3 KB)

Event Timeline