Skip to content
This repository has been archived by the owner on Nov 29, 2020. It is now read-only.

Commit

Permalink
feat: adding support for client certificates (#arc-electron/29)
Browse files Browse the repository at this point in the history
  • Loading branch information
jarrodek committed Dec 23, 2019
1 parent f60d22f commit e36dd5c
Show file tree
Hide file tree
Showing 5 changed files with 3,169 additions and 2,312 deletions.
31 changes: 30 additions & 1 deletion arc-request-logic.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {LitElement} from 'lit-element';

import {EventsTargetMixin} from '@advanced-rest-client/events-target-mixin/events-target-mixin.js';

import {HeadersParserMixin} from '@advanced-rest-client/headers-parser-mixin/headers-parser-mixin.js';

declare namespace ApiElements {

/**
Expand Down Expand Up @@ -223,7 +225,7 @@ declare namespace ApiElements {
*
* @param request The request object
*/
_continueRequest(request: object|null): void;
_continueRequest(request: object|null): any;

/**
* Creates an immutable request data object to be send to the transport
Expand Down Expand Up @@ -267,6 +269,33 @@ declare namespace ApiElements {
* @param reason Error object for the reason.
*/
_reportCancelation(reason: Error|null): void;

/**
* Processes raw authorization configuration to transform it, if possible,
* into correct authorization configuration.
*
* Currently this method processes authorization for:
* - oauth 2
* - basic
* - client certificates.
*/
_processAuth(request: RequestObject|null): Promise<any>|null;

/**
* Adds `clientCertificate` property from authorization configuration.
* This requires `client-certificates-model` to be present in the DOM.
*/
_processClientCertificate(request: RequestObject|null): Promise<any>|null;

/**
* Adds `authorization` header for basic authentication.
*/
_processBasicAuth(request: RequestObject|null): Promise<any>|null;

/**
* Processes authorization data for OAuth 2 authorization.
*/
_processOAuth2(request: RequestObject|null): Promise<any>|null;
}
}

Expand Down
157 changes: 148 additions & 9 deletions arc-request-logic.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,19 @@ the License.
*/
import { LitElement } from 'lit-element';
import { EventsTargetMixin } from '@advanced-rest-client/events-target-mixin/events-target-mixin.js';
import { HeadersParserMixin } from '@advanced-rest-client/headers-parser-mixin/headers-parser-mixin.js';
import '@advanced-rest-client/variables-evaluator/variables-evaluator.js';
function noop() {}

/**
* @typedef {Object} RequestObject
* @property {string} url
* @property {string} method
* @property {string=} headers
* @property {string|blob|FormData|null} payload
* @property {Object=} auth
* @property {string=} authType
* @property {Object=} config
*/
/**
* `arc-request-logic`
*
Expand All @@ -29,12 +40,11 @@ function noop() {}
* `--arc-request-logic` | Mixin applied to this elment | `{}`
*
* @customElement
* @polymer
* @demo demo/index.html
* @memberof ApiElements
* @appliesMixin EventsTargetMixin
*/
class ArcRequestLogic extends EventsTargetMixin(LitElement) {
class ArcRequestLogic extends EventsTargetMixin(HeadersParserMixin(LitElement)) {
static get properties() {
return {
/**
Expand Down Expand Up @@ -149,9 +159,11 @@ class ArcRequestLogic extends EventsTargetMixin(LitElement) {
* @return {Promise}
*/
async processRequest(request) {
const copy = this._prepareEventRequest(request);
let copy = this._prepareEventRequest(request);
this._queue[copy.id] = copy;
return await this._beforeProcessVariables(copy);
copy = await this._beforeProcessVariables(copy);
await this._beforeRequest(copy);
return copy;
}
/**
* Prepares a request object to be used to send it with the `before-request`
Expand Down Expand Up @@ -190,9 +202,9 @@ class ArcRequestLogic extends EventsTargetMixin(LitElement) {
request = await this.evalElement.processBeforeRequest(request, override);
}
} catch (_) {
noop();
// ...
}
return await this._beforeRequest(request);
return request;
}
/**
* Prepares scripts context override values for variables evaluator.
Expand Down Expand Up @@ -424,7 +436,7 @@ class ArcRequestLogic extends EventsTargetMixin(LitElement) {
*
* @param {Object} request The request object
*/
_continueRequest(request) {
async _continueRequest(request) {
this._clearBeforeRequestTimeout(request.id);
// request = Object.assign({}, request);
delete request.promises;
Expand All @@ -434,6 +446,7 @@ class ArcRequestLogic extends EventsTargetMixin(LitElement) {
delete request._beforeTimedOut;
delete request._currentTimeout;
delete request._cancelled;
await this._processAuth(request);
// Changes to the `_requestCopy` object won't affect sent object.
// However changes made to FormData or File object of the payload property
// or to the `auth` object will affect send object because those are
Expand Down Expand Up @@ -499,7 +512,7 @@ class ArcRequestLogic extends EventsTargetMixin(LitElement) {
try {
await this._processResponseActions(ra, arcResponse.request, arcResponse.response);
} catch (_) {
noop();
// ...
}
}
this._disaptchResponse(arcResponse);
Expand Down Expand Up @@ -537,12 +550,138 @@ class ArcRequestLogic extends EventsTargetMixin(LitElement) {
this._reportError(new Error(reason));
}

/**
* Processes raw authorization configuration to transform it, if possible,
* into correct authorization configuration.
*
* Currently this method processes authorization for:
* - oauth 2
* - basic
* - client certificates.
*
* @param {RequestObject} request
* @return {Promise}
*/
async _processAuth(request) {
switch (request.authType) {
case 'client certificate': await this._processClientCertificate(request); break;
case 'basic': await this._processBasicAuth(request); break;
case 'oauth 2': await this._processOAuth2(request); break;
}
}

/**
* Adds `clientCertificate` property from authorization configuration.
* This requires `client-certificates-model` to be present in the DOM.
*
* @param {RequestObject} request
* @return {Promise}
*/
async _processClientCertificate(request) {
const { auth } = request;
if (!auth || !auth.id) {
return;
}
const e = new CustomEvent('client-certificate-get', {
bubbles: true,
cancelable: true,
detail: {
id: auth.id
}
});
this.dispatchEvent(e);
try {
const result = await e.detail.result;
if (!result) {
return;
}
request.clientCertificate = {
type: result.type,
cert: [result.cert],
};
if (result.key) {
request.clientCertificate.key = [result.key];
}
} catch (e) {
// ...
}
}

/**
* Adds `authorization` header for basic authentication.
* @param {RequestObject} request
* @return {Promise}
*/
async _processBasicAuth(request) {
const { auth } = request;
if (!auth || !auth.username) {
return;
}
const { username, password } = auth;
let headers = this.headersToJSON(request.headers || '');
const value = btoa(`${username}:${password || ''}`);
headers = this.replaceHeaderValue(headers, 'authorization', value);
request.headers = this.headersToString(headers);
}

/**
* Processes authorization data for OAuth 2 authorization.
* @param {RequestObject} request
* @return {Promise}
*/
async _processOAuth2(request) {
const { auth } = request;
if (!auth) {
return;
}
const { accessToken, tokenType='Bearer', deliveryMethod='header', deliveryName='authorization' } = auth;
if (!accessToken) {
return;
}

if (deliveryMethod !== 'header') {
// TODO (pawel): add support for query parameters delivery method.
// Because the authorization panel does not support it right now it is
// not implemented, yet.
return;
}
let headers = this.headersToJSON(request.headers || '');
const value = `${tokenType} ${accessToken}`;
headers = this.replaceHeaderValue(headers, deliveryName, value);
request.headers = this.headersToString(headers);
}

/**
* Dispatched when request is made. This is handled by `urlhistory-model`
* to store URL history data.
*
* @event url-history-store
* @param {String} value The URL to store.
*/

/**
* @event variable-update-action
*/
/**
* @event before-request
*/
/**
* @event api-response
*/
/**
* @event transport-request
* @param {RequestObject}
*/
/**
* @event run-response-actions
* @param {Array<Object>} actions
* @param {RequestObject} request
* @param {Object} response
*/
/**
* Dispatched when requesting client certificate data from a data store.
* @event client-certificate-get
* @param {String} id
*/
}
window.customElements.define('arc-request-logic', ArcRequestLogic);

0 comments on commit e36dd5c

Please sign in to comment.