221 lines
8.7 KiB
JavaScript
221 lines
8.7 KiB
JavaScript
const GameCenterAuth = require('../../../lib/Adapters/Auth/gcenter').default;
|
|
const { pki } = require('node-forge');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
describe('GameCenterAuth Adapter', function () {
|
|
let adapter;
|
|
|
|
beforeEach(function () {
|
|
adapter = new GameCenterAuth.constructor();
|
|
|
|
const gcProd4 = fs.readFileSync(path.resolve(__dirname, '../../support/cert/gc-prod-4.cer'));
|
|
const digicertPem = fs.readFileSync(path.resolve(__dirname, '../../support/cert/DigiCertTrustedG4CodeSigningRSA4096SHA3842021CA1.crt.pem')).toString();
|
|
|
|
mockFetch([
|
|
{
|
|
url: 'https://static.gc.apple.com/public-key/gc-prod-4.cer',
|
|
method: 'GET',
|
|
response: {
|
|
ok: true,
|
|
headers: new Map(),
|
|
arrayBuffer: () => Promise.resolve(
|
|
gcProd4.buffer.slice(gcProd4.byteOffset, gcProd4.byteOffset + gcProd4.length)
|
|
),
|
|
},
|
|
},
|
|
{
|
|
url: 'https://cacerts.digicert.com/DigiCertTrustedG4CodeSigningRSA4096SHA3842021CA1.crt.pem',
|
|
method: 'GET',
|
|
response: {
|
|
ok: true,
|
|
headers: new Map([['content-type', 'application/x-pem-file'], ['content-length', digicertPem.length.toString()]]),
|
|
text: () => Promise.resolve(digicertPem),
|
|
},
|
|
}
|
|
]);
|
|
});
|
|
|
|
describe('Test config failing due to missing params or wrong types', function () {
|
|
it('should throw error for invalid options', async function () {
|
|
const invalidOptions = [
|
|
null,
|
|
undefined,
|
|
{},
|
|
{ bundleId: '' },
|
|
{ enableInsecureAuth: false }, // Missing bundleId in secure mode
|
|
];
|
|
|
|
for (const options of invalidOptions) {
|
|
expect(() => adapter.validateOptions(options)).withContext(JSON.stringify(options)).toThrow()
|
|
}
|
|
});
|
|
|
|
it('should validate options successfully with valid parameters', function () {
|
|
const validOptions = { bundleId: 'com.valid.app', enableInsecureAuth: false };
|
|
expect(() => adapter.validateOptions(validOptions)).not.toThrow();
|
|
});
|
|
});
|
|
|
|
describe('Test payload failing due to missing params or wrong types', function () {
|
|
it('should throw error for missing authData fields', async function () {
|
|
await expectAsync(adapter.validateAuthData({})).toBeRejectedWithError(
|
|
'AuthData id is missing.'
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('Test payload fails due to incorrect appId / certificate', function () {
|
|
it('should throw error for invalid publicKeyUrl', async function () {
|
|
const invalidPublicKeyUrl = 'https://malicious.url.com/key.cer';
|
|
|
|
spyOn(adapter, 'fetchCertificate').and.throwError(
|
|
new Error('Invalid publicKeyUrl')
|
|
);
|
|
|
|
await expectAsync(
|
|
adapter.getAppleCertificate(invalidPublicKeyUrl)
|
|
).toBeRejectedWithError('Invalid publicKeyUrl: https://malicious.url.com/key.cer');
|
|
});
|
|
|
|
it('should throw error for invalid signature verification', async function () {
|
|
const fakePublicKey = 'invalid-key';
|
|
const fakeAuthData = {
|
|
id: '1234567',
|
|
publicKeyUrl: 'https://static.gc.apple.com/public-key/gc-prod-4.cer',
|
|
timestamp: 1460981421303,
|
|
salt: 'saltST==',
|
|
signature: 'invalidSignature',
|
|
};
|
|
|
|
spyOn(adapter, 'getAppleCertificate').and.returnValue(Promise.resolve(fakePublicKey));
|
|
spyOn(adapter, 'verifySignature').and.throwError('Invalid signature.');
|
|
|
|
await expectAsync(adapter.validateAuthData(fakeAuthData)).toBeRejectedWithError(
|
|
'Invalid signature.'
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('Test payload passing', function () {
|
|
it('should successfully process valid payload and save auth data', async function () {
|
|
const validAuthData = {
|
|
id: '1234567',
|
|
publicKeyUrl: 'https://static.gc.apple.com/public-key/gc-prod-4.cer',
|
|
timestamp: 1460981421303,
|
|
salt: 'saltST==',
|
|
signature: 'validSignature',
|
|
bundleId: 'com.valid.app',
|
|
};
|
|
|
|
spyOn(adapter, 'getAppleCertificate').and.returnValue(Promise.resolve('validKey'));
|
|
spyOn(adapter, 'verifySignature').and.returnValue(true);
|
|
|
|
await expectAsync(adapter.validateAuthData(validAuthData)).toBeResolved();
|
|
});
|
|
});
|
|
|
|
describe('Certificate and Signature Validation', function () {
|
|
it('should fetch and validate Apple certificate', async function () {
|
|
const certUrl = 'https://static.gc.apple.com/public-key/gc-prod-4.cer';
|
|
const mockCertificate = 'mockCertificate';
|
|
|
|
spyOn(adapter, 'fetchCertificate').and.returnValue(
|
|
Promise.resolve({ certificate: mockCertificate, headers: new Map() })
|
|
);
|
|
spyOn(pki, 'certificateFromPem').and.returnValue({});
|
|
|
|
adapter.cache[certUrl] = mockCertificate;
|
|
|
|
const cert = await adapter.getAppleCertificate(certUrl);
|
|
expect(cert).toBe(mockCertificate);
|
|
});
|
|
|
|
it('should verify signature successfully', async function () {
|
|
const authData = {
|
|
id: 'G:1965586982',
|
|
publicKeyUrl: 'https://static.gc.apple.com/public-key/gc-prod-4.cer',
|
|
timestamp: 1565257031287,
|
|
signature:
|
|
'uqLBTr9Uex8zCpc1UQ1MIDMitb+HUat2Mah4Kw6AVLSGe0gGNJXlih2i5X+0ZwVY0S9zY2NHWi2gFjmhjt/4kxWGMkupqXX5H/qhE2m7hzox6lZJpH98ZEUbouWRfZX2ZhUlCkAX09oRNi7fI7mWL1/o88MaI/y6k6tLr14JTzmlxgdyhw+QRLxRPA6NuvUlRSJpyJ4aGtNH5/wHdKQWL8nUnFYiYmaY8R7IjzNxPfy8UJTUWmeZvMSgND4u8EjADPsz7ZtZyWAPi8kYcAb6M8k0jwLD3vrYCB8XXyO2RQb/FY2TM4zJuI7PzLlvvgOJXbbfVtHx7Evnm5NYoyzgzw==',
|
|
salt: 'DzqqrQ==',
|
|
};
|
|
|
|
adapter.bundleId = 'cloud.xtralife.gamecenterauth';
|
|
adapter.enableInsecureAuth = false;
|
|
|
|
spyOn(adapter, 'verifyPublicKeyIssuer').and.returnValue();
|
|
|
|
const publicKey = await adapter.getAppleCertificate(authData.publicKeyUrl);
|
|
|
|
expect(() => adapter.verifySignature(publicKey, authData)).not.toThrow();
|
|
|
|
});
|
|
|
|
it('should not use bundle id from authData payload in secure mode', async function () {
|
|
const authData = {
|
|
id: 'G:1965586982',
|
|
publicKeyUrl: 'https://static.gc.apple.com/public-key/gc-prod-4.cer',
|
|
timestamp: 1565257031287,
|
|
signature:
|
|
'uqLBTr9Uex8zCpc1UQ1MIDMitb+HUat2Mah4Kw6AVLSGe0gGNJXlih2i5X+0ZwVY0S9zY2NHWi2gFjmhjt/4kxWGMkupqXX5H/qhE2m7hzox6lZJpH98ZEUbouWRfZX2ZhUlCkAX09oRNi7fI7mWL1/o88MaI/y6k6tLr14JTzmlxgdyhw+QRLxRPA6NuvUlRSJpyJ4aGtNH5/wHdKQWL8nUnFYiYmaY8R7IjzNxPfy8UJTUWmeZvMSgND4u8EjADPsz7ZtZyWAPi8kYcAb6M8k0jwLD3vrYCB8XXyO2RQb/FY2TM4zJuI7PzLlvvgOJXbbfVtHx7Evnm5NYoyzgzw==',
|
|
salt: 'DzqqrQ==',
|
|
bundleId: 'com.example.insecure.app',
|
|
};
|
|
|
|
adapter.bundleId = 'cloud.xtralife.gamecenterauth';
|
|
adapter.enableInsecureAuth = false;
|
|
|
|
spyOn(adapter, 'verifyPublicKeyIssuer').and.returnValue();
|
|
|
|
const publicKey = await adapter.getAppleCertificate(authData.publicKeyUrl);
|
|
|
|
expect(() => adapter.verifySignature(publicKey, authData)).not.toThrow();
|
|
|
|
});
|
|
|
|
it('should not use bundle id from authData payload in insecure mode', async function () {
|
|
const authData = {
|
|
id: 'G:1965586982',
|
|
publicKeyUrl: 'https://static.gc.apple.com/public-key/gc-prod-4.cer',
|
|
timestamp: 1565257031287,
|
|
signature:
|
|
'uqLBTr9Uex8zCpc1UQ1MIDMitb+HUat2Mah4Kw6AVLSGe0gGNJXlih2i5X+0ZwVY0S9zY2NHWi2gFjmhjt/4kxWGMkupqXX5H/qhE2m7hzox6lZJpH98ZEUbouWRfZX2ZhUlCkAX09oRNi7fI7mWL1/o88MaI/y6k6tLr14JTzmlxgdyhw+QRLxRPA6NuvUlRSJpyJ4aGtNH5/wHdKQWL8nUnFYiYmaY8R7IjzNxPfy8UJTUWmeZvMSgND4u8EjADPsz7ZtZyWAPi8kYcAb6M8k0jwLD3vrYCB8XXyO2RQb/FY2TM4zJuI7PzLlvvgOJXbbfVtHx7Evnm5NYoyzgzw==',
|
|
salt: 'DzqqrQ==',
|
|
bundleId: 'com.example.insecure.app',
|
|
};
|
|
|
|
adapter.bundleId = 'cloud.xtralife.gamecenterauth';
|
|
adapter.enableInsecureAuth = true;
|
|
|
|
spyOn(adapter, 'verifyPublicKeyIssuer').and.returnValue();
|
|
|
|
const publicKey = await adapter.getAppleCertificate(authData.publicKeyUrl);
|
|
|
|
expect(() => adapter.verifySignature(publicKey, authData)).not.toThrow();
|
|
|
|
});
|
|
|
|
it('can use bundle id from authData payload in insecure mode', async function () {
|
|
const authData = {
|
|
id: 'G:1965586982',
|
|
publicKeyUrl: 'https://static.gc.apple.com/public-key/gc-prod-4.cer',
|
|
timestamp: 1565257031287,
|
|
signature:
|
|
'uqLBTr9Uex8zCpc1UQ1MIDMitb+HUat2Mah4Kw6AVLSGe0gGNJXlih2i5X+0ZwVY0S9zY2NHWi2gFjmhjt/4kxWGMkupqXX5H/qhE2m7hzox6lZJpH98ZEUbouWRfZX2ZhUlCkAX09oRNi7fI7mWL1/o88MaI/y6k6tLr14JTzmlxgdyhw+QRLxRPA6NuvUlRSJpyJ4aGtNH5/wHdKQWL8nUnFYiYmaY8R7IjzNxPfy8UJTUWmeZvMSgND4u8EjADPsz7ZtZyWAPi8kYcAb6M8k0jwLD3vrYCB8XXyO2RQb/FY2TM4zJuI7PzLlvvgOJXbbfVtHx7Evnm5NYoyzgzw==',
|
|
salt: 'DzqqrQ==',
|
|
bundleId: 'cloud.xtralife.gamecenterauth',
|
|
};
|
|
|
|
adapter.enableInsecureAuth = true;
|
|
|
|
spyOn(adapter, 'verifyPublicKeyIssuer').and.returnValue();
|
|
|
|
const publicKey = await adapter.getAppleCertificate(authData.publicKeyUrl);
|
|
|
|
expect(() => adapter.verifySignature(publicKey, authData)).not.toThrow();
|
|
|
|
});
|
|
});
|
|
});
|