});
}); // fetchProfile
+ describe('fetchMetadata', function () {
+ let metadataUrl;
+ beforeEach(function () {
+ metadataUrl = new URL('https://thuza.ratfeathers.com/');
+ sinon.stub(communication, 'fetchJSON');
+ });
+ it('covers success', async function () {
+ communication.fetchJSON.resolves({
+ 'issuer': 'https://ia.squeep.com/',
+ 'authorization_endpoint': 'https://ia.squeep.com/auth',
+ 'token_endpoint': 'https://ia.squeep.com/token',
+ 'introspection_endpoint': 'https://ia.squeep.com/introspect',
+ 'introspection_endpoint_auth_methods_supported': [ '' ],
+ 'revocation_endpoint': 'https://ia.squeep.com/revoke',
+ 'revocation_endpoint_auth_methods_supported': [ 'none' ],
+ 'scopes_supported': [ 'profile', 'email' ],
+ 'service_documentation': 'https://indieauth.spec.indieweb.org/',
+ 'code_challenge_methods_supported': [ 'S256', 'SHA256' ],
+ 'authorization_response_iss_parameter_supported': true,
+ 'userinfo_endpoint': 'https://ia.squeep.com/userinfo',
+ });
+ const expected = {
+ authorizationEndpoint: 'https://ia.squeep.com/auth',
+ tokenEndpoint: 'https://ia.squeep.com/token',
+ issuer: 'https://ia.squeep.com/',
+ introspectionEndpoint: 'https://ia.squeep.com/introspect',
+ introspectionEndpointAuthMethodsSupported: [ '' ],
+ revocationEndpoint: 'https://ia.squeep.com/revoke',
+ revocationEndpointAuthMethodsSupported: [ 'none' ],
+ scopesSupported: [ 'profile', 'email' ],
+ serviceDocumentation: 'https://indieauth.spec.indieweb.org/',
+ codeChallengeMethodsSupported: [ 'S256', 'SHA256' ],
+ authorizationResponseIssParameterSupported: true,
+ userinfoEndpoint: 'https://ia.squeep.com/userinfo',
+ };
+ const result = await communication.fetchMetadata(metadataUrl);
+ assert.deepStrictEqual(result, expected);
+ });
+ it('covers failure', async function () {
+ communication.fetchJSON.resolves(undefined);
+ const expected = {};
+ const result = await communication.fetchMetadata(metadataUrl);
+ assert.deepStrictEqual(result, expected);
+ });
+ }); // fetchMetadata
+
describe('redeemCode', function () {
let expected, urlObj, code, codeVerifier, clientId, redirectURI;
beforeEach(function () {
}); // introspectToken
describe('deliverTicket', function () {
- let ticketEndpointUrlObj, resourceUrlObj, subjectUrlObj, ticket;
+ let ticketEndpointUrlObj, resourceUrlObj, subjectUrlObj, ticket, issuerUrlObj;
beforeEach(function () {
ticketEndpointUrlObj = new URL('https://ticket.example.com/');
resourceUrlObj = new URL('https://resource.example.com/');
subjectUrlObj = new URL('https://subject.example.com/');
+ issuerUrlObj = new URL('https://idp.example.com/');
ticket = 'XXXThisIsATicketXXX';
});
it('covers success', async function () {
+ const expected = { body: 'blah', statusCode: 200 };
+ communication.got.resolves(expected);
+ const result = await communication.deliverTicket(ticketEndpointUrlObj, resourceUrlObj, subjectUrlObj, ticket, issuerUrlObj);
+ assert.deepStrictEqual(result, expected);
+ });
+ it('covers success, no issuer', async function () {
const expected = { body: 'blah', statusCode: 200 };
communication.got.resolves(expected);
const result = await communication.deliverTicket(ticketEndpointUrlObj, resourceUrlObj, subjectUrlObj, ticket);
});
}); // deliverTicket
+ describe('_fetchMetadataOrTokenEndpoint', function () {
+ let urlObj, metadataUrl, tokenUrl;
+ beforeEach(function () {
+ urlObj = new URL('https://idp.example.com/');
+ metadataUrl = new URL('https://idp.example.com/meta');
+ tokenUrl = new URL('https://idp.example.com/token');
+ sinon.stub(communication, 'fetchMicroformat').resolves({
+ rels: {
+ 'indieauth-metadata': [ metadataUrl.href ],
+ 'token_endpoint': [ tokenUrl.href ],
+ },
+ });
+ });
+ it('covers success', async function () {
+ const expected = {
+ metadataUrl,
+ tokenUrl: undefined,
+ };
+ const result = await communication._fetchMetadataOrTokenEndpoint(urlObj);
+ assert.deepStrictEqual(result, expected);
+ });
+ it('covers bad metadata url', async function () {
+ communication.fetchMicroformat.resolves({
+ rels: {
+ 'indieauth-metadata': [ 'not a url' ],
+ 'token_endpoint': [ tokenUrl.href ],
+ },
+ });
+ const expected = {
+ metadataUrl: undefined,
+ tokenUrl,
+ };
+ const result = await communication._fetchMetadataOrTokenEndpoint(urlObj);
+ assert.deepStrictEqual(result, expected);
+ });
+ it('covers bad token url', async function () {
+ communication.fetchMicroformat.resolves({
+ rels: {
+ 'indieauth-metadata': [],
+ 'token_endpoint': [ 'not a url' ],
+ },
+ });
+ const expected = {
+ metadataUrl: undefined,
+ tokenUrl: undefined,
+ };
+ const result = await communication._fetchMetadataOrTokenEndpoint(urlObj);
+ assert.deepStrictEqual(result, expected);
+ });
+ it('covers no rels', async function () {
+ communication.fetchMicroformat.resolves({
+ rels: {
+ 'indieauth-metadata': [],
+ 'token_endpoint': [],
+ },
+ });
+ const expected = {
+ metadataUrl: undefined,
+ tokenUrl: undefined,
+ };
+ const result = await communication._fetchMetadataOrTokenEndpoint(urlObj);
+ assert.deepStrictEqual(result, expected);
+ });
+ it('covers no url', async function () {
+ const expected = {
+ metadataUrl: undefined,
+ tokenUrl: undefined,
+ };
+ const result = await communication._fetchMetadataOrTokenEndpoint();
+ assert.deepStrictEqual(result, expected);
+ });
+ }); // _fetchMetadataOrTokenEndpoint
+
+ describe('redeemTicket', function () {
+ let ticket, resourceUrlObj, issuerUrlObj;
+ beforeEach(function () {
+ resourceUrlObj = new URL('https://resource.example.com/');
+ issuerUrlObj = new URL('https://idp.example.com/');
+ ticket = 'XXXThisIsATicketXXX';
+ sinon.stub(communication, '_fetchMetadataOrTokenEndpoint').resolves({
+ metadataUrl: new URL('https://example.com'),
+ tokenUrl: undefined,
+ });
+ sinon.stub(communication, 'fetchMetadata').resolves({ tokenEndpoint: 'https://idp.example.com/' });
+ });
+ it('covers success', async function () {
+ const expected = { 'access_token': 'XXXThisIsAnAccessTokenXXX' };
+ const response = { body: expected, headers: {}, statusCode: 200 };
+ communication.got.resolves(response);
+ const result = await communication.redeemTicket(ticket, resourceUrlObj, issuerUrlObj);
+ assert.deepStrictEqual(result, expected);
+ });
+ it('covers success without issuer', async function () {
+ const expected = { 'access_token': 'XXXThisIsAnAccessTokenXXX' };
+ const response = { body: expected, headers: {}, statusCode: 200 };
+ communication.got.resolves(response);
+ const result = await communication.redeemTicket(ticket, resourceUrlObj);
+ assert.deepStrictEqual(result, expected);
+ });
+ it('covers got failure', async function () {
+ const expectedException = new Error('oh no');
+ communication.got.rejects(expectedException);
+ await assert.rejects(() => communication.redeemTicket(ticket, resourceUrlObj, issuerUrlObj), expectedException);
+ });
+ it('covers no metadata url', async function () {
+ communication._fetchMetadataOrTokenEndpoint.resolves({ metadataUrl: undefined, tokenUrl: undefined });
+ await assert.rejects(() => communication.redeemTicket(ticket, resourceUrlObj, issuerUrlObj), ValidationError);
+ });
+ it('covers bad token url', async function () {
+ communication.fetchMetadata.resolves({ tokenEndpoint: 'not a url' });
+ await assert.rejects(() => communication.redeemTicket(ticket, resourceUrlObj, issuerUrlObj), ValidationError);
+ });
+ }); // redeemTicket
+
}); // Communication