const bruToJson = require('../src/bruToJson'); const jsonToBru = require('../src/jsonToBru'); const collectionBruToJson = require('../src/collectionBruToJson'); const jsonToCollectionBru = require('../src/jsonToCollectionBru'); // --------------------------------------------------------------------------- // bruToJson – request-level parsing // --------------------------------------------------------------------------- describe('OAuth1 bruToJson (request-level)', () => { it('should parse all oauth1 fields with text private key', () => { const input = ` meta { name: OAuth1 Test type: http seq: 1 } get { url: https://api.example.com/resource body: none auth: oauth1 } auth:oauth1 { consumer_key: my_consumer_key consumer_secret: my_consumer_secret access_token: my_access_token token_secret: my_token_secret callback_url: https://example.com/callback verifier: my_verifier signature_method: HMAC-SHA1 private_key: my_private_key timestamp: 1234567890 nonce: abc123 version: 1.0 realm: my_realm placement: header include_body_hash: true } `.trim(); const result = bruToJson(input); expect(result.auth.oauth1).toEqual({ consumerKey: 'my_consumer_key', consumerSecret: 'my_consumer_secret', accessToken: 'my_access_token', accessTokenSecret: 'my_token_secret', callbackUrl: 'https://example.com/callback', verifier: 'my_verifier', signatureMethod: 'HMAC-SHA1', privateKey: 'my_private_key', privateKeyType: 'text', timestamp: '1234567890', nonce: 'abc123', version: '1.0', realm: 'my_realm', placement: 'header', includeBodyHash: true }); }); it('should parse empty/missing optional fields as empty strings', () => { const input = ` meta { name: Minimal OAuth1 type: http } get { url: https://api.example.com/resource auth: oauth1 } auth:oauth1 { consumer_key: ck consumer_secret: access_token: token_secret: callback_url: verifier: signature_method: HMAC-SHA1 private_key: timestamp: nonce: version: realm: placement: header include_body_hash: false } `.trim(); const result = bruToJson(input); expect(result.auth.oauth1.consumerKey).toBe('ck'); expect(result.auth.oauth1.consumerSecret).toBe(''); expect(result.auth.oauth1.accessToken).toBe(''); expect(result.auth.oauth1.accessTokenSecret).toBe(''); expect(result.auth.oauth1.callbackUrl).toBe(''); expect(result.auth.oauth1.verifier).toBe(''); expect(result.auth.oauth1.privateKey).toBe(''); expect(result.auth.oauth1.privateKeyType).toBe('text'); expect(result.auth.oauth1.timestamp).toBe(''); expect(result.auth.oauth1.nonce).toBe(''); expect(result.auth.oauth1.version).toBe(''); expect(result.auth.oauth1.realm).toBe(''); expect(result.auth.oauth1.includeBodyHash).toBe(false); }); it('should parse @file() private key as file type', () => { const input = ` meta { name: OAuth1 File Key type: http } get { url: https://api.example.com/resource auth: oauth1 } auth:oauth1 { consumer_key: ck consumer_secret: access_token: at token_secret: ts callback_url: verifier: signature_method: RSA-SHA1 private_key: @file(keys/my-private-key.pem) timestamp: nonce: version: 1.0 realm: placement: header include_body_hash: false } `.trim(); const result = bruToJson(input); expect(result.auth.oauth1.privateKey).toBe('keys/my-private-key.pem'); expect(result.auth.oauth1.privateKeyType).toBe('file'); }); it('should parse multiline private key (triple-quoted PEM)', () => { const input = ` meta { name: OAuth1 Multiline PEM type: http } get { url: https://api.example.com/resource auth: oauth1 } auth:oauth1 { consumer_key: ck consumer_secret: cs access_token: at token_secret: ts callback_url: verifier: signature_method: RSA-SHA1 private_key: ''' -----BEGIN FAKE TEST KEY----- TESTREPLACEMENTdGhpcyBpcyBub3QgYQ== -----END FAKE TEST KEY----- ''' timestamp: nonce: version: 1.0 realm: placement: header include_body_hash: false } `.trim(); const result = bruToJson(input); expect(result.auth.oauth1.privateKeyType).toBe('text'); expect(result.auth.oauth1.privateKey).toContain('-----BEGIN FAKE TEST KEY-----'); expect(result.auth.oauth1.privateKey).toContain('-----END FAKE TEST KEY-----'); expect(result.auth.oauth1.privateKey).toContain('TESTREPLACEMENTdGhpcyBpcyBub3QgYQ=='); // Verify no leading spaces are preserved in the parsed key lines const keyLines = result.auth.oauth1.privateKey.split('\n').filter((l) => l.length > 0); keyLines.forEach((line) => { expect(line).not.toMatch(/^\s/); }); }); it('should parse variable reference in private key as text type', () => { const input = ` meta { name: OAuth1 Variable Key type: http } get { url: https://api.example.com/resource auth: oauth1 } auth:oauth1 { consumer_key: ck consumer_secret: access_token: at token_secret: ts callback_url: verifier: signature_method: RSA-SHA1 private_key: {{my_private_key}} timestamp: nonce: version: 1.0 realm: placement: header include_body_hash: false } `.trim(); const result = bruToJson(input); expect(result.auth.oauth1.privateKey).toBe('{{my_private_key}}'); expect(result.auth.oauth1.privateKeyType).toBe('text'); }); it('should parse all signature methods correctly', () => { const signatureMethods = ['HMAC-SHA1', 'HMAC-SHA256', 'HMAC-SHA512', 'RSA-SHA1', 'RSA-SHA256', 'RSA-SHA512', 'PLAINTEXT']; for (const method of signatureMethods) { const input = ` meta { name: OAuth1 ${method} type: http } get { url: https://api.example.com/resource auth: oauth1 } auth:oauth1 { consumer_key: ck consumer_secret: cs access_token: at token_secret: ts callback_url: verifier: signature_method: ${method} private_key: timestamp: nonce: version: 1.0 realm: placement: header include_body_hash: false } `.trim(); const result = bruToJson(input); expect(result.auth.oauth1.signatureMethod).toBe(method); } }); it('should parse placement values: header, query, body', () => { for (const placement of ['header', 'query', 'body']) { const input = ` meta { name: OAuth1 Params To ${placement} type: http } get { url: https://api.example.com/resource auth: oauth1 } auth:oauth1 { consumer_key: ck consumer_secret: cs access_token: at token_secret: ts callback_url: verifier: signature_method: HMAC-SHA1 private_key: timestamp: nonce: version: 1.0 realm: placement: ${placement} include_body_hash: false } `.trim(); const result = bruToJson(input); expect(result.auth.oauth1.placement).toBe(placement); } }); it('should parse include_body_hash true and false', () => { const makeInput = (val) => ` meta { name: OAuth1 Body Hash type: http } get { url: https://api.example.com/resource auth: oauth1 } auth:oauth1 { consumer_key: ck consumer_secret: cs access_token: token_secret: callback_url: verifier: signature_method: HMAC-SHA1 private_key: timestamp: nonce: version: 1.0 realm: placement: header include_body_hash: ${val} } `.trim(); expect(bruToJson(makeInput('true')).auth.oauth1.includeBodyHash).toBe(true); expect(bruToJson(makeInput('false')).auth.oauth1.includeBodyHash).toBe(false); }); }); // --------------------------------------------------------------------------- // collectionBruToJson – collection/folder-level parsing // --------------------------------------------------------------------------- describe('OAuth1 collectionBruToJson (collection/folder-level)', () => { it('should parse all oauth1 fields at collection level', () => { const input = ` auth { mode: oauth1 } auth:oauth1 { consumer_key: col_consumer_key consumer_secret: col_consumer_secret access_token: col_access_token token_secret: col_token_secret callback_url: https://col.example.com/cb verifier: col_verifier signature_method: HMAC-SHA256 private_key: col_private_key timestamp: 9999999999 nonce: col_nonce version: 1.0 realm: col_realm placement: query include_body_hash: true } `.trim(); const result = collectionBruToJson(input); expect(result.auth.mode).toBe('oauth1'); expect(result.auth.oauth1).toEqual({ consumerKey: 'col_consumer_key', consumerSecret: 'col_consumer_secret', accessToken: 'col_access_token', accessTokenSecret: 'col_token_secret', callbackUrl: 'https://col.example.com/cb', verifier: 'col_verifier', signatureMethod: 'HMAC-SHA256', privateKey: 'col_private_key', privateKeyType: 'text', timestamp: '9999999999', nonce: 'col_nonce', version: '1.0', realm: 'col_realm', placement: 'query', includeBodyHash: true }); }); it('should parse @file() private key at collection level', () => { const input = ` auth { mode: oauth1 } auth:oauth1 { consumer_key: ck consumer_secret: access_token: token_secret: callback_url: verifier: signature_method: RSA-SHA1 private_key: @file(certs/private.pem) timestamp: nonce: version: 1.0 realm: placement: header include_body_hash: false } `.trim(); const result = collectionBruToJson(input); expect(result.auth.oauth1.privateKey).toBe('certs/private.pem'); expect(result.auth.oauth1.privateKeyType).toBe('file'); }); it('should parse multiline private key at collection level', () => { const input = ` auth { mode: oauth1 } auth:oauth1 { consumer_key: ck consumer_secret: access_token: token_secret: callback_url: verifier: signature_method: RSA-SHA256 private_key: ''' -----BEGIN FAKE RSA TEST KEY----- RkFLRUtFWXJlYWxrZXlkYXRhZm9ydGVz -----END FAKE RSA TEST KEY----- ''' timestamp: nonce: version: 1.0 realm: placement: header include_body_hash: false } `.trim(); const result = collectionBruToJson(input); expect(result.auth.oauth1.privateKeyType).toBe('text'); expect(result.auth.oauth1.privateKey).toContain('-----BEGIN FAKE RSA TEST KEY-----'); expect(result.auth.oauth1.privateKey).toContain('RkFLRUtFWXJlYWxrZXlkYXRhZm9ydGVz'); expect(result.auth.oauth1.privateKey).toContain('-----END FAKE RSA TEST KEY-----'); // Verify no leading spaces are preserved in the parsed key lines const keyLines = result.auth.oauth1.privateKey.split('\n').filter((l) => l.length > 0); keyLines.forEach((line) => { expect(line).not.toMatch(/^\s/); }); }); }); // --------------------------------------------------------------------------- // jsonToBru – request-level serialization // --------------------------------------------------------------------------- describe('OAuth1 jsonToBru (request-level)', () => { it('should serialize all oauth1 fields with text private key', () => { const json = { meta: { name: 'OAuth1 Serialize', type: 'http', seq: 1 }, http: { method: 'get', url: 'https://api.example.com/resource', body: 'none', auth: 'oauth1' }, auth: { oauth1: { consumerKey: 'ck', consumerSecret: 'cs', accessToken: 'at', accessTokenSecret: 'ts', callbackUrl: 'https://example.com/cb', verifier: 'v', signatureMethod: 'HMAC-SHA1', privateKey: 'pk', privateKeyType: 'text', timestamp: '123', nonce: 'n', version: '1.0', realm: 'r', placement: 'header', includeBodyHash: false } } }; const bru = jsonToBru(json); expect(bru).toContain('auth:oauth1 {'); expect(bru).toContain('consumer_key: ck'); expect(bru).toContain('consumer_secret: cs'); expect(bru).toContain('access_token: at'); expect(bru).toContain('token_secret: ts'); expect(bru).toContain('callback_url: https://example.com/cb'); expect(bru).toContain('verifier: v'); expect(bru).toContain('signature_method: HMAC-SHA1'); expect(bru).toContain('private_key: pk'); expect(bru).toContain('timestamp: 123'); expect(bru).toContain('nonce: n'); expect(bru).toContain('version: 1.0'); expect(bru).toContain('realm: r'); expect(bru).toContain('placement: header'); expect(bru).toContain('include_body_hash: false'); }); it('should serialize file private key with @file() wrapper', () => { const json = { meta: { name: 'OAuth1 File', type: 'http', seq: 1 }, http: { method: 'get', url: 'https://api.example.com/resource', auth: 'oauth1' }, auth: { oauth1: { consumerKey: 'ck', consumerSecret: '', accessToken: '', accessTokenSecret: '', callbackUrl: '', verifier: '', signatureMethod: 'RSA-SHA1', privateKey: 'keys/private.pem', privateKeyType: 'file', timestamp: '', nonce: '', version: '1.0', realm: '', placement: 'header', includeBodyHash: false } } }; const bru = jsonToBru(json); expect(bru).toContain('private_key: @file(keys/private.pem)'); }); it('should serialize multiline private key with triple quotes', () => { const pem = '-----BEGIN FAKE TEST KEY-----\nTESTREPLACEMENTdGhpcyBpcyBub3QgYQ==\nRkFLRUtFWXJlYWxrZXlkYXRhZm9ydGVz\n-----END FAKE TEST KEY-----'; const json = { meta: { name: 'OAuth1 PEM', type: 'http', seq: 1 }, http: { method: 'get', url: 'https://api.example.com/resource', auth: 'oauth1' }, auth: { oauth1: { consumerKey: 'ck', consumerSecret: '', accessToken: '', accessTokenSecret: '', callbackUrl: '', verifier: '', signatureMethod: 'RSA-SHA1', privateKey: pem, privateKeyType: 'text', timestamp: '', nonce: '', version: '1.0', realm: '', placement: 'header', includeBodyHash: false } } }; const bru = jsonToBru(json); expect(bru).toContain('private_key: \'\'\''); expect(bru).toContain('-----BEGIN FAKE TEST KEY-----'); expect(bru).toContain('-----END FAKE TEST KEY-----'); }); it('should serialize empty optional fields', () => { const json = { meta: { name: 'OAuth1 Empty', type: 'http', seq: 1 }, http: { method: 'get', url: 'https://api.example.com/resource', auth: 'oauth1' }, auth: { oauth1: { consumerKey: 'ck', consumerSecret: '', accessToken: '', accessTokenSecret: '', callbackUrl: '', verifier: '', signatureMethod: 'HMAC-SHA1', privateKey: '', privateKeyType: 'text', timestamp: '', nonce: '', version: '', realm: '', placement: 'header', includeBodyHash: false } } }; const bru = jsonToBru(json); // Empty fields should still be present expect(bru).toMatch(/consumer_secret:\s*$/m); expect(bru).toMatch(/access_token:\s*$/m); expect(bru).toMatch(/token_secret:\s*$/m); expect(bru).toMatch(/callback_url:\s*$/m); expect(bru).toMatch(/verifier:\s*$/m); expect(bru).toMatch(/private_key:\s*$/m); expect(bru).toMatch(/timestamp:\s*$/m); expect(bru).toMatch(/nonce:\s*$/m); expect(bru).toMatch(/version:\s*$/m); expect(bru).toMatch(/realm:\s*$/m); }); }); // --------------------------------------------------------------------------- // jsonToCollectionBru – collection/folder-level serialization // --------------------------------------------------------------------------- describe('OAuth1 jsonToCollectionBru (collection/folder-level)', () => { it('should serialize oauth1 at collection level', () => { const json = { auth: { mode: 'oauth1', oauth1: { consumerKey: 'col_ck', consumerSecret: 'col_cs', accessToken: 'col_at', accessTokenSecret: 'col_ts', callbackUrl: '', verifier: '', signatureMethod: 'HMAC-SHA256', privateKey: '', privateKeyType: 'text', timestamp: '', nonce: '', version: '1.0', realm: '', placement: 'query', includeBodyHash: true } } }; const bru = jsonToCollectionBru(json); expect(bru).toContain('auth {'); expect(bru).toContain('mode: oauth1'); expect(bru).toContain('auth:oauth1 {'); expect(bru).toContain('consumer_key: col_ck'); expect(bru).toContain('consumer_secret: col_cs'); expect(bru).toContain('signature_method: HMAC-SHA256'); expect(bru).toContain('placement: query'); expect(bru).toContain('include_body_hash: true'); }); it('should serialize @file() private key at collection level', () => { const json = { auth: { mode: 'oauth1', oauth1: { consumerKey: 'ck', consumerSecret: '', accessToken: '', accessTokenSecret: '', callbackUrl: '', verifier: '', signatureMethod: 'RSA-SHA1', privateKey: 'certs/key.pem', privateKeyType: 'file', timestamp: '', nonce: '', version: '1.0', realm: '', placement: 'header', includeBodyHash: false } } }; const bru = jsonToCollectionBru(json); expect(bru).toContain('private_key: @file(certs/key.pem)'); }); }); // --------------------------------------------------------------------------- // Round-trip tests – bruToJson → jsonToBru → bruToJson // --------------------------------------------------------------------------- describe('OAuth1 round-trip (request-level)', () => { it('should survive round-trip with all fields populated', () => { const json = { meta: { name: 'OAuth1 Roundtrip', type: 'http', seq: '1' }, http: { method: 'get', url: 'https://api.example.com/resource', body: 'none', auth: 'oauth1' }, auth: { oauth1: { consumerKey: 'ck', consumerSecret: 'cs', accessToken: 'at', accessTokenSecret: 'ts', callbackUrl: 'https://example.com/cb', verifier: 'ver', signatureMethod: 'HMAC-SHA1', privateKey: 'inline_pk', privateKeyType: 'text', timestamp: '1234567890', nonce: 'abc', version: '1.0', realm: 'testrealm', placement: 'header', includeBodyHash: true } }, settings: { encodeUrl: true, timeout: 0 } }; const bru = jsonToBru(json); const parsed = bruToJson(bru); expect(parsed.auth.oauth1).toEqual(json.auth.oauth1); }); it('should survive round-trip with file private key', () => { const json = { meta: { name: 'OAuth1 File RT', type: 'http', seq: '1' }, http: { method: 'get', url: 'https://api.example.com/resource', auth: 'oauth1' }, auth: { oauth1: { consumerKey: 'ck', consumerSecret: '', accessToken: 'at', accessTokenSecret: 'ts', callbackUrl: '', verifier: '', signatureMethod: 'RSA-SHA1', privateKey: 'keys/private.pem', privateKeyType: 'file', timestamp: '', nonce: '', version: '1.0', realm: '', placement: 'header', includeBodyHash: false } }, settings: { encodeUrl: true, timeout: 0 } }; const bru = jsonToBru(json); const parsed = bruToJson(bru); expect(parsed.auth.oauth1.privateKey).toBe('keys/private.pem'); expect(parsed.auth.oauth1.privateKeyType).toBe('file'); }); it('should survive round-trip with multiline PEM private key', () => { const pem = '-----BEGIN FAKE TEST KEY-----\nTESTREPLACEMENTdGhpcyBpcyBub3QgYQ==\nRkFLRUtFWXJlYWxrZXlkYXRhZm9ydGVz\n-----END FAKE TEST KEY-----'; const json = { meta: { name: 'OAuth1 PEM RT', type: 'http', seq: '1' }, http: { method: 'get', url: 'https://api.example.com/resource', auth: 'oauth1' }, auth: { oauth1: { consumerKey: 'ck', consumerSecret: '', accessToken: '', accessTokenSecret: '', callbackUrl: '', verifier: '', signatureMethod: 'RSA-SHA256', privateKey: pem, privateKeyType: 'text', timestamp: '', nonce: '', version: '1.0', realm: '', placement: 'header', includeBodyHash: false } }, settings: { encodeUrl: true, timeout: 0 } }; const bru = jsonToBru(json); const parsed = bruToJson(bru); expect(parsed.auth.oauth1.privateKey).toBe(pem); expect(parsed.auth.oauth1.privateKeyType).toBe('text'); }); }); describe('OAuth1 round-trip (collection-level)', () => { it('should survive round-trip at collection level', () => { const json = { auth: { mode: 'oauth1', oauth1: { consumerKey: 'ck', consumerSecret: 'cs', accessToken: 'at', accessTokenSecret: 'ts', callbackUrl: 'https://example.com/cb', verifier: 'ver', signatureMethod: 'HMAC-SHA512', privateKey: '', privateKeyType: 'text', timestamp: '', nonce: '', version: '1.0', realm: '', placement: 'body', includeBodyHash: false } } }; const bru = jsonToCollectionBru(json); const parsed = collectionBruToJson(bru); expect(parsed.auth.mode).toBe('oauth1'); expect(parsed.auth.oauth1).toEqual(json.auth.oauth1); }); it('should survive round-trip with file key at collection level', () => { const json = { auth: { mode: 'oauth1', oauth1: { consumerKey: 'ck', consumerSecret: '', accessToken: '', accessTokenSecret: '', callbackUrl: '', verifier: '', signatureMethod: 'RSA-SHA512', privateKey: 'keys/rsa.pem', privateKeyType: 'file', timestamp: '', nonce: '', version: '1.0', realm: '', placement: 'header', includeBodyHash: false } } }; const bru = jsonToCollectionBru(json); const parsed = collectionBruToJson(bru); expect(parsed.auth.oauth1.privateKey).toBe('keys/rsa.pem'); expect(parsed.auth.oauth1.privateKeyType).toBe('file'); }); });