+ describe('fetchJSON', function () {
+ let expected, response, result, urlObj;
+ beforeEach(function () {
+ expected = undefined;
+ result = undefined;
+ urlObj = new URL('https://thuza.ratfeathers.com/');
+ response = {
+ headers: Object.assign({}, testData.linkHeaders),
+ data: testData.hCardHtml,
+ };
+ });
+ it('covers', async function () {
+ communication.axios.resolves(response);
+ expected = { foo: 'bar', baz: 123 };
+ response.data = JSON.stringify(expected);
+
+ result = await communication.fetchJSON(urlObj);
+ assert.deepStrictEqual(result, expected);
+ });
+ it('covers axios error', async function () {
+ communication.axios.rejects(new Error('blah'));
+ expected = undefined;
+
+ result = await communication.fetchJSON(urlObj);
+
+ assert.deepStrictEqual(result, expected);
+ });
+ it('covers non-parsable content', async function () {
+ response.data = 'some bare text';
+ response.headers = {};
+ communication.axios.resolves(response);
+ expected = undefined;
+
+ result = await communication.fetchJSON(urlObj);
+
+ assert.deepStrictEqual(result, expected);
+ });
+ }); // fetchJSON
+
+ describe('validateProfile', function () {
+ let url, validationOptions;
+ beforeEach(function () {
+ url = 'https://example.com/';
+ options = {};
+ sinon.stub(dns, 'lookupAsync').resolves([{ family: 4, address: '10.11.12.14' }]);
+ });
+ it('rejects invalid url', async function () {
+ url = 'bad url';
+ await assert.rejects(() => communication.validateProfile(url, validationOptions), ValidationError);
+ });
+ it('covers success', async function () {
+ const result = await communication.validateProfile(url, validationOptions);
+ assert.strictEqual(result.isLoopback, false);
+ });
+ it('rejects invalid', async function () {
+ url = 'ftp://example.com/';
+ await assert.rejects(() => communication.validateProfile(url, validationOptions), ValidationError);
+ });
+
+ }); // validateProfile
+
+ describe('validateClientIdentifier', function () {
+ let url, validationOptions;
+ beforeEach(function () {
+ url = 'https://example.com/';
+ options = {};
+ sinon.stub(dns, 'lookupAsync').resolves([{ family: 4, address: '10.11.12.13' }]);
+ });
+ it('rejects invalid url', async function () {
+ try {
+ await communication.validateClientIdentifier('bad url');
+ assert.fail(noExpectedException);
+ } catch (e) {
+ assert(e instanceof ValidationError);
+ }
+ });
+ it('rejects invalid scheme', async function () {
+ url = 'ftp://example.com/';
+ try {
+ await communication.validateClientIdentifier(url, validationOptions);
+ assert.fail(noExpectedException);
+ } catch (e) {
+ assert(e instanceof ValidationError);
+ }
+ });
+ it('rejects fragment', async function () {
+ url = 'https://example.com/#foo';
+ try {
+ await communication.validateClientIdentifier(url, validationOptions);
+ assert.fail(noExpectedException);
+ } catch (e) {
+ assert(e instanceof ValidationError);
+ }
+ });
+ it('rejects username', async function () {
+ url = 'https://user@example.com/';
+ try {
+ await communication.validateClientIdentifier(url, validationOptions);
+ assert.fail(noExpectedException);
+ } catch (e) {
+ assert(e instanceof ValidationError);
+ }
+ });
+ it('rejects password', async function () {
+ url = 'https://:foo@example.com/';
+ try {
+ await communication.validateClientIdentifier(url, validationOptions);
+ assert.fail(noExpectedException);
+ } catch (e) {
+ assert(e instanceof ValidationError);
+ }
+ });
+ it('rejects relative path', async function () {
+ url = 'https://example.com/client/../sneaky';
+ try {
+ await communication.validateClientIdentifier(url, validationOptions);
+ assert.fail(noExpectedException);
+ } catch (e) {
+ assert(e instanceof ValidationError);
+ }
+ });
+ it('rejects ipv4', async function () {
+ url = 'https://10.11.12.13/';
+ try {
+ await communication.validateClientIdentifier(url, validationOptions);
+ assert.fail(noExpectedException);
+ } catch (e) {
+ assert(e instanceof ValidationError);
+ }
+ });
+ it('rejects ipv6', async function () {
+ url = 'https://[fd64:defa:00e5:caf4:0dff::ad39]/';
+ try {
+ await communication.validateClientIdentifier(url, validationOptions);
+ assert.fail(noExpectedException);
+ } catch (e) {
+ assert(e instanceof ValidationError);
+ }
+ });
+ it('accepts ipv4 loopback', async function () {
+ url = 'https://127.0.0.1/';
+ const result = await communication.validateClientIdentifier(url, validationOptions);
+ assert.strictEqual(result.isLoopback, true);
+ });
+ it('accepts ipv6 loopback', async function () {
+ url = 'https://[::1]/';
+ const result = await communication.validateClientIdentifier(url, validationOptions);
+ assert.strictEqual(result.isLoopback, true);
+ });
+ it('accepts resolved ipv4 loopback', async function () {
+ dns.lookupAsync.resolves([{ family: 4, address: '127.0.0.1' }]);
+ const result = await communication.validateClientIdentifier(url, validationOptions);
+ assert.strictEqual(result.isLoopback, true);
+ });
+ it('accepts resolved ipv6 loopback', async function () {
+ dns.lookupAsync.resolves([{ family: 6, address: '::1' }]);
+ const result = await communication.validateClientIdentifier(url, validationOptions);
+ assert.strictEqual(result.isLoopback, true);
+ });
+ it('covers success', async function () {
+ const result = await communication.validateClientIdentifier(url, validationOptions);
+ assert.strictEqual(result.isLoopback, false);
+ });
+ it('rejects resolution failure', async function () {
+ dns.lookupAsync.rejects(new Error('oh no'));
+ try {
+ await communication.validateClientIdentifier(url, validationOptions);
+ assert.fail(noExpectedException);
+ } catch (e) {
+ assert(e instanceof ValidationError);
+ }
+ });
+ it('rejects mismatched resolutions', async function () {
+ dns.lookupAsync.onCall(1).resolves([{ family: 4, address: '10.9.8.7' }]);
+ try {
+ await communication.validateClientIdentifier(url, validationOptions);
+ assert.fail(noExpectedException);
+ } catch (e) {
+ assert(e instanceof ValidationError);
+ }
+ });
+ it('ignores unknown dns family', async function () {
+ dns.lookupAsync.resolves([{ family: 5, address: '10.9.8.7' }]);
+ const result = await communication.validateClientIdentifier(url, validationOptions);
+ assert.strictEqual(result.isLoopback, false);
+ });
+ it('covers rooted hostname', async function() {
+ url = 'https://example.com./';
+ const result = await communication.validateClientIdentifier(url, validationOptions);
+ assert.strictEqual(result.isLoopback, false);
+ });
+ it('covers unresolved', async function () {
+ dns.lookupAsync.resolves();
+ const result = await communication.validateClientIdentifier(url, validationOptions);
+ assert.strictEqual(result.isLoopback, false);
+ });
+ }); // validateClientIdentifier
+