diff --git a/app/common/constants.js b/app/common/constants.js
index 12e1dbc45b..45c14d8291 100644
--- a/app/common/constants.js
+++ b/app/common/constants.js
@@ -139,6 +139,7 @@ export const AUTH_BASIC = 'basic';
export const AUTH_DIGEST = 'digest';
export const AUTH_BEARER = 'bearer';
export const AUTH_NTLM = 'ntlm';
+export const AUTH_HAWK = 'hawk';
export const AUTH_AWS_IAM = 'iam';
export const AUTH_NETRC = 'netrc';
@@ -149,6 +150,7 @@ const authTypesMap = {
[AUTH_BEARER]: ['Bearer', 'Bearer Token'],
[AUTH_OAUTH_1]: ['OAuth 1', 'OAuth 1.0'],
[AUTH_OAUTH_2]: ['OAuth 2', 'OAuth 2.0'],
+ [AUTH_HAWK]: ['Hawk', 'Hawk'],
[AUTH_AWS_IAM]: ['AWS', 'AWS IAM v4'],
[AUTH_NETRC]: ['Netrc', 'Netrc']
};
diff --git a/app/common/har.js b/app/common/har.js
index df56b2350c..8b446a42f8 100644
--- a/app/common/har.js
+++ b/app/common/har.js
@@ -8,6 +8,8 @@ import {getAuthHeader} from '../network/authentication';
export async function exportHarWithRequest (renderedRequest, addContentLength = false) {
let postData = '';
+ const url = misc.prepareUrlForSending(renderedRequest.url);
+
if (renderedRequest.body.fileName) {
try {
postData = newBodyRaw(fs.readFileSync(renderedRequest.body.fileName, 'base64'));
@@ -36,6 +38,8 @@ export async function exportHarWithRequest (renderedRequest, addContentLength =
if (!misc.hasAuthHeader(renderedRequest.headers)) {
const header = await getAuthHeader(
renderedRequest._id,
+ url,
+ renderedRequest.method,
renderedRequest.authentication
);
header && renderedRequest.headers.push(header);
@@ -43,7 +47,7 @@ export async function exportHarWithRequest (renderedRequest, addContentLength =
return {
method: renderedRequest.method,
- url: misc.prepareUrlForSending(renderedRequest.url),
+ url,
httpVersion: 'HTTP/1.1',
cookies: getCookies(renderedRequest),
headers: renderedRequest.headers,
diff --git a/app/models/request.js b/app/models/request.js
index 54ce9403ed..914ad44975 100644
--- a/app/models/request.js
+++ b/app/models/request.js
@@ -1,6 +1,6 @@
// @flow
import type {BaseModel} from './index';
-import {AUTH_BASIC, AUTH_DIGEST, AUTH_NONE, AUTH_NTLM, AUTH_OAUTH_2, AUTH_AWS_IAM, AUTH_NETRC, CONTENT_TYPE_FILE, CONTENT_TYPE_FORM_DATA, CONTENT_TYPE_FORM_URLENCODED, CONTENT_TYPE_OTHER, getContentTypeFromHeaders, METHOD_GET, CONTENT_TYPE_GRAPHQL, CONTENT_TYPE_JSON, METHOD_POST} from '../common/constants';
+import {AUTH_BASIC, AUTH_DIGEST, AUTH_NONE, AUTH_NTLM, AUTH_OAUTH_2, AUTH_HAWK, AUTH_AWS_IAM, AUTH_NETRC, CONTENT_TYPE_FILE, CONTENT_TYPE_FORM_DATA, CONTENT_TYPE_FORM_URLENCODED, CONTENT_TYPE_OTHER, getContentTypeFromHeaders, METHOD_GET, CONTENT_TYPE_GRAPHQL, CONTENT_TYPE_JSON, METHOD_POST} from '../common/constants';
import * as db from '../common/database';
import {getContentTypeHeader} from '../common/misc';
import {buildFromParams, deconstructToParams} from '../common/querystring';
@@ -116,6 +116,10 @@ export function newAuth (type: string, oldAuth: RequestAuthentication = {}): Req
case AUTH_NETRC:
return {type};
+ // hawk
+ case AUTH_HAWK:
+ return {type, algorithm: 'sha256'};
+
// Types needing no defaults
default:
return {type};
diff --git a/app/network/authentication.js b/app/network/authentication.js
index 8c36b65276..0ffe4d40c3 100644
--- a/app/network/authentication.js
+++ b/app/network/authentication.js
@@ -1,8 +1,9 @@
-import {AUTH_BASIC, AUTH_BEARER, AUTH_OAUTH_2} from '../common/constants';
+import {AUTH_BASIC, AUTH_BEARER, AUTH_OAUTH_2, AUTH_HAWK} from '../common/constants';
import {getBasicAuthHeader, getBearerAuthHeader} from '../common/misc';
import getOAuth2Token from './o-auth-2/get-token';
+import * as Hawk from 'hawk';
-export async function getAuthHeader (requestId, authentication) {
+export async function getAuthHeader (requestId, url, method, authentication) {
if (authentication.disabled) {
return null;
}
@@ -27,6 +28,21 @@ export async function getAuthHeader (requestId, authentication) {
}
}
+ if (authentication.type === AUTH_HAWK) {
+ const {id, key, algorithm} = authentication;
+
+ const header = Hawk.client.header(
+ url,
+ method,
+ {credentials: {id, key, algorithm}}
+ );
+
+ return {
+ name: 'Authorization',
+ value: header.field
+ };
+ }
+
return null;
}
diff --git a/app/network/network.js b/app/network/network.js
index 62e208d608..c9459b91a2 100644
--- a/app/network/network.js
+++ b/app/network/network.js
@@ -473,6 +473,8 @@ export function _actuallySend (
} else {
const authHeader = await getAuthHeader(
renderedRequest._id,
+ finalUrl,
+ renderedRequest.method,
renderedRequest.authentication
);
diff --git a/app/ui/components/dropdowns/auth-dropdown.js b/app/ui/components/dropdowns/auth-dropdown.js
index f6035ab456..c88670b082 100644
--- a/app/ui/components/dropdowns/auth-dropdown.js
+++ b/app/ui/components/dropdowns/auth-dropdown.js
@@ -6,7 +6,7 @@ import {trackEvent} from '../../../analytics';
import {showModal} from '../modals';
import AlertModal from '../modals/alert-modal';
import * as models from '../../../models';
-import {AUTH_BASIC, AUTH_DIGEST, AUTH_BEARER, AUTH_NONE, AUTH_NTLM, AUTH_OAUTH_1, AUTH_OAUTH_2, AUTH_AWS_IAM, AUTH_NETRC, getAuthTypeName} from '../../../common/constants';
+import {AUTH_BASIC, AUTH_DIGEST, AUTH_BEARER, AUTH_NONE, AUTH_NTLM, AUTH_OAUTH_1, AUTH_OAUTH_2, AUTH_HAWK, AUTH_AWS_IAM, AUTH_NETRC, getAuthTypeName} from '../../../common/constants';
@autobind
class AuthDropdown extends PureComponent {
@@ -70,6 +70,7 @@ class AuthDropdown extends PureComponent {
{this.renderAuthType(AUTH_NTLM)}
{this.renderAuthType(AUTH_AWS_IAM)}
{this.renderAuthType(AUTH_NETRC)}
+ {this.renderAuthType(AUTH_HAWK)}
Other
{this.renderAuthType(AUTH_NONE, 'No Authentication')}
diff --git a/app/ui/components/editors/auth/auth-wrapper.js b/app/ui/components/editors/auth/auth-wrapper.js
index f8ffac68ed..4a653b323e 100644
--- a/app/ui/components/editors/auth/auth-wrapper.js
+++ b/app/ui/components/editors/auth/auth-wrapper.js
@@ -1,11 +1,12 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
-import {AUTH_BASIC, AUTH_DIGEST, AUTH_BEARER, AUTH_NTLM, AUTH_OAUTH_1, AUTH_OAUTH_2, AUTH_AWS_IAM, AUTH_NETRC} from '../../../../common/constants';
+import {AUTH_BASIC, AUTH_DIGEST, AUTH_BEARER, AUTH_NTLM, AUTH_OAUTH_1, AUTH_OAUTH_2, AUTH_AWS_IAM, AUTH_HAWK, AUTH_NETRC} from '../../../../common/constants';
import BasicAuth from './basic-auth';
import DigestAuth from './digest-auth';
import BearerAuth from './bearer-auth';
import NTLMAuth from './ntlm-auth';
import OAuth2Auth from './o-auth-2-auth';
+import HawkAuth from './hawk-auth';
import AWSAuth from './aws-auth';
import NetrcAuth from './netrc-auth';
import autobind from 'autobind-decorator';
@@ -49,6 +50,15 @@ class AuthWrapper extends PureComponent {
showPasswords={showPasswords}
/>
);
+ } else if (authentication.type === AUTH_HAWK) {
+ return (
+
+ );
} else if (authentication.type === AUTH_OAUTH_1) {
return (
diff --git a/app/ui/components/editors/auth/hawk-auth.js b/app/ui/components/editors/auth/hawk-auth.js
new file mode 100644
index 0000000000..2c7fc76df8
--- /dev/null
+++ b/app/ui/components/editors/auth/hawk-auth.js
@@ -0,0 +1,107 @@
+// @flow
+import type { Request } from '../../../../models/request';
+
+import React from 'react';
+import autobind from 'autobind-decorator';
+import OneLineEditor from '../../codemirror/one-line-editor';
+import * as misc from '../../../../common/misc';
+
+@autobind
+class HawkAuth extends React.PureComponent {
+ props: {
+ request: Request,
+ handleRender: Function,
+ handleGetRenderContext: Function,
+ onChange: Function
+ };
+
+ _handleChangeProperty: Function;
+
+ constructor (props: any) {
+ super(props);
+
+ this._handleChangeProperty = misc.debounce(this._handleChangeProperty, 500);
+ }
+
+ _handleChangeProperty (property: string, value: string | boolean): void {
+ const {request} = this.props;
+ const authentication = Object.assign({}, request.authentication, {[property]: value});
+ this.props.onChange(authentication);
+ }
+
+ _handleChangeHawkAuthId (value: string): void {
+ this._handleChangeProperty('id', value);
+ }
+
+ _handleChangeHawkAuthKey (value: string): void {
+ this._handleChangeProperty('key', value);
+ }
+
+ _handleChangeAlgorithm (value: string): void {
+ this._handleChangeProperty('algorithm', value);
+ }
+
+ renderHawkAuthenticationFields (): Array
> {
+ const hawkAuthId = this.renderInputRow(
+ 'Hawk Auth ID',
+ 'id',
+ this._handleChangeHawkAuthId
+ );
+
+ const hawkAuthKey = this.renderInputRow(
+ 'Hawk Auth Key',
+ 'key',
+ this._handleChangeHawkAuthKey
+ );
+
+ const algorithm = this.renderInputRow(
+ 'Algorithm',
+ 'algorithm',
+ this._handleChangeAlgorithm
+ );
+
+ return [hawkAuthId, hawkAuthKey, algorithm];
+ }
+
+ renderInputRow (label: string,
+ property: string,
+ onChange: Function): React.Element<*> {
+ const {handleRender, handleGetRenderContext, request} = this.props;
+ const id = label.replace(/ /g, '-');
+ return (
+
+ |
+
+ |
+
+
+
+
+ |
+
+ );
+ }
+
+ render () {
+ const fields = this.renderHawkAuthenticationFields();
+
+ return (
+
+ );
+ }
+}
+
+export default HawkAuth;
diff --git a/package-lock.json b/package-lock.json
index dd6d3faa6b..551873656b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1499,11 +1499,11 @@
"dev": true
},
"boom": {
- "version": "2.10.1",
- "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
- "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz",
+ "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=",
"requires": {
- "hoek": "2.16.3"
+ "hoek": "4.2.0"
}
},
"boxen": {
@@ -2478,11 +2478,21 @@
"integrity": "sha1-UYO8R6CVWb78+YzEZXlkmZNZNy8="
},
"cryptiles": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
- "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz",
+ "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=",
"requires": {
- "boom": "2.10.1"
+ "boom": "5.2.0"
+ },
+ "dependencies": {
+ "boom": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz",
+ "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==",
+ "requires": {
+ "hoek": "4.2.0"
+ }
+ }
}
},
"crypto-browserify": {
@@ -5610,14 +5620,14 @@
}
},
"hawk": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
- "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz",
+ "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==",
"requires": {
- "boom": "2.10.1",
- "cryptiles": "2.0.5",
- "hoek": "2.16.3",
- "sntp": "1.0.9"
+ "boom": "4.3.1",
+ "cryptiles": "3.1.2",
+ "hoek": "4.2.0",
+ "sntp": "2.0.2"
}
},
"highlight.js": {
@@ -5642,9 +5652,9 @@
}
},
"hoek": {
- "version": "2.16.3",
- "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
- "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0="
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz",
+ "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ=="
},
"hoist-non-react-statics": {
"version": "1.2.0",
@@ -10811,6 +10821,22 @@
"uuid": "3.0.0"
},
"dependencies": {
+ "boom": {
+ "version": "2.10.1",
+ "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
+ "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
+ "requires": {
+ "hoek": "2.16.3"
+ }
+ },
+ "cryptiles": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
+ "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
+ "requires": {
+ "boom": "2.10.1"
+ }
+ },
"form-data": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz",
@@ -10829,6 +10855,30 @@
"ajv": "4.11.8",
"har-schema": "1.0.5"
}
+ },
+ "hawk": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
+ "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=",
+ "requires": {
+ "boom": "2.10.1",
+ "cryptiles": "2.0.5",
+ "hoek": "2.16.3",
+ "sntp": "1.0.9"
+ }
+ },
+ "hoek": {
+ "version": "2.16.3",
+ "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
+ "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0="
+ },
+ "sntp": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
+ "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=",
+ "requires": {
+ "hoek": "2.16.3"
+ }
}
}
},
@@ -11247,11 +11297,11 @@
"dev": true
},
"sntp": {
- "version": "1.0.9",
- "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
- "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.0.2.tgz",
+ "integrity": "sha1-UGQRDwr4X3z9t9a2ekACjOUrSys=",
"requires": {
- "hoek": "2.16.3"
+ "hoek": "4.2.0"
}
},
"sockjs": {
diff --git a/package.json b/package.json
index 28a551c035..e6331afb51 100644
--- a/package.json
+++ b/package.json
@@ -122,6 +122,7 @@
"electron-devtools-installer": "^2.2.0",
"electron-squirrel-startup": "^1.0.0",
"graphql": "^0.10.5",
+ "hawk": "^6.0.2",
"highlight.js": "^9.12.0",
"hkdf": "^0.0.2",
"html-entities": "^1.2.0",