[@hapi/hawk] Add types for @hapi/hawk (#41702)

This commit is contained in:
Florian Keller 2020-01-22 01:17:32 +01:00 committed by Ben Lichtman
parent 8e8b6b6735
commit 5062ff431f
12 changed files with 514 additions and 0 deletions

View File

@ -0,0 +1 @@
lib/browser.d.ts

View File

@ -0,0 +1,48 @@
import * as Http from 'http';
import * as Hawk from '@hapi/hawk';
import * as request from 'request';
const credentialsFunc = (): Hawk.server.Credentials => {
const credentials: Hawk.server.Credentials = {
key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
algorithm: 'sha256',
user: 'Steve',
};
return credentials;
};
Http.createServer(async (req, res) => {
const { credentials, artifacts } = await Hawk.server.authenticate(req, credentialsFunc);
const payload = `Hello ${credentials.user} ${artifacts.ext}`;
const status = 200;
const headers: Record<string, string> = { 'Content-Type': 'text/plain' };
const header = Hawk.server.header(credentials, artifacts, { payload, contentType: headers['Content-Type'] });
headers['Server-Authorization'] = header;
res.writeHead(status, headers);
res.end(payload);
});
const credentials: Hawk.client.Credentials = {
id: 'dh37fgj492je',
key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
algorithm: 'sha256',
};
const requestOptions: request.OptionsWithUri = {
uri: 'http://example.com:8000/resource/1?b=1&a=2',
method: 'GET',
headers: {},
};
const header = Hawk.client.header('http://example.com:8000/resource/1?b=1&a=2', 'GET', {
credentials,
ext: 'some-app-data',
});
requestOptions.headers!.Authorization = header;
request(requestOptions, (_error, response, body) => {
Hawk.client.authenticate(response, credentials, header.artifacts, { payload: body });
});

22
types/hapi__hawk/index.d.ts vendored Executable file
View File

@ -0,0 +1,22 @@
// Type definitions for @hapi/hawk 8.0
// Project: https://github.com/hapijs/hawk/
// Definitions by: Florian Keller <https://github.com/ffflorian>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
/// <reference types="node" />
import * as sntp from '@hapi/sntp';
import * as server from './lib/server';
import * as client from './lib/client';
import * as crypto from './lib/crypto';
import * as utils from './lib/utils';
import * as plugin from './lib/plugin';
export namespace uri {
const authenticate: typeof server.authenticateBewit;
const getBewit: typeof client.getBewit;
}
export { sntp, server, client, crypto, utils, plugin };
export as namespace hawk;

62
types/hapi__hawk/lib/browser.d.ts vendored Executable file
View File

@ -0,0 +1,62 @@
import CryptoJS = require('crypto-js');
import * as Crypto from './crypto';
import * as Client from './client';
declare namespace hawk {
namespace client {
function authenticate(
request: XMLHttpRequest | Response,
credentials: Client.Credentials,
artifacts: Crypto.Artifacts,
options?: Client.AuthenticateOptions,
): boolean;
function authenticateTimestamp(
message: string,
credentials: Client.Credentials,
updateClock?: boolean,
): boolean;
function bewit(uri: string, options?: Client.BewitOptions): string;
function header(uri: string | utils.ParsedUri, method: string, options?: Client.HeaderOptions): Client.Header;
function message(host: string, port: number, message: string, options: Client.MessageOptions): Client.Message;
}
namespace crypto {
const headerVersion: string;
const algorithms: string[];
function calculateMac(type: string, credentials: Client.Credentials, options: Crypto.Artifacts): string;
function calculatePayloadHash(payload: string, algorithm: string, contentType: string): string;
function calculateTsMac(ts: string, credentials: Client.Credentials): string;
function generateNormalizedString(type: string, options: Crypto.Artifacts): string;
}
namespace utils {
interface ParsedUri {
host: string;
port: string;
resource: string;
}
const storage: Storage;
/** `scheme://credentials@host:port/resource#fragment` */
const uriRegex: RegExp;
function base64urlEncode(value: string | Buffer, encoding?: BufferEncoding): string;
function escapeHeaderAttribute(attribute: string): string;
function getNtpSecOffset(): number;
function now(localtimeOffsetMsec?: number): number;
function nowSec(localtimeOffsetMsec?: number): number;
function parseAuthorizationHeader(header: string, keys?: string[]): Record<string, string>;
function parseContentType(header?: string): string;
function parseUri(input: string): ParsedUri;
function randomString(size: number): string;
function setNtpSecOffset(offset: number): void;
function setStorage(storage: Storage): void;
}
namespace crypto {
const utils: typeof CryptoJS;
}
}
export = hawk;

88
types/hapi__hawk/lib/client.d.ts vendored Executable file
View File

@ -0,0 +1,88 @@
import * as Crypto from './crypto';
import * as http from 'http';
import * as request from 'request';
export interface Credentials {
algorithm: 'sha1' | 'sha256';
id: string;
key: string;
}
export interface HeaderOptions {
/** Oz application id */
app?: string;
/** Payload content-type (ignored if hash provided) */
contentType?: string;
credentials: Credentials;
/** Oz delegated-by application id */
dlg?: string;
/** Application specific data sent via the ext attribute */
ext?: string;
/** Pre-calculated payload hash */
hash?: string;
/** Time offset to sync with server time (ignored if timestamp provided) */
localtimeOffsetMsec?: number;
/** A pre-generated nonce */
nonce?: string;
/** UTF-8 encoded string for body hash generation (ignored if hash provided) */
payload?: string;
/** A pre-calculated timestamp in seconds */
timestamp?: number;
}
export interface Header {
header: string;
artifacts: Crypto.Artifacts;
}
export interface AuthenticateOptions {
/** optional payload received */
payload?: string;
/** specifies if a Server-Authorization header is required. Defaults to 'false' */
required?: boolean;
}
export interface Authentication {
headers: Record<string, string>;
}
export interface BewitOptions {
credentials: Credentials;
/** Application specific data sent via the ext attribute */
ext?: string;
/** Time offset to sync with server time */
localtimeOffsetMsec: number;
/** TTL in seconds */
ttlSec: number;
}
export interface MessageOptions {
credentials: Credentials;
/** Time offset to sync with server time (ignored if timestamp provided) */
localtimeOffsetMsec: number;
/** A pre-generated nonce */
nonce: string;
/** A pre-calculated timestamp in seconds */
timestamp: number;
}
export interface Message {
hash: string;
id: string;
mac: string;
nonce: string;
ts: string;
}
export function authenticate(
res: http.IncomingMessage | request.Response,
credentials: Credentials,
artifacts: Crypto.Artifacts,
options?: AuthenticateOptions,
): Authentication;
export function getBewit(uri: string, options: BewitOptions): string;
export function header(uri: string, method: string, options?: HeaderOptions): Header;
export function message(host: string, port: number, message: string, options?: MessageOptions): Message;

38
types/hapi__hawk/lib/crypto.d.ts vendored Executable file
View File

@ -0,0 +1,38 @@
import * as Crypto from 'crypto';
import * as Client from './client';
export interface Artifacts {
app?: string;
dlg?: string;
ext?: string;
hash?: string;
host: string;
method: string;
nonce: string;
port: number;
resource: string;
ts: string;
}
export interface TimestampMessage {
ts: number;
tsm: string;
}
export const headerVersion: string;
export const algorithms: string[];
export function calculateMac(type: string, credentials: Client.Credentials, options: Artifacts): string;
export function generateNormalizedString(type: string, options: Artifacts): string;
export function calculatePayloadHash(payload: string, algorithm: string, contentType: string): string;
export function initializePayloadHash(algorithm: string, contentType: string): string;
export function finalizePayloadHash(hash: Crypto.Hash): string;
export function calculateTsMac(ts: string, credentials: Client.Credentials): string;
export function timestampMessage(credentials: Client.Credentials, localtimeOffsetMsec: number): TimestampMessage;

7
types/hapi__hawk/lib/plugin.d.ts vendored Executable file
View File

@ -0,0 +1,7 @@
import * as Hapi from '@hapi/hapi';
export namespace plugin {
const pkg: Record<string, any>;
const requirements: Record<string, string>;
function register(server: Hapi.Server): void;
}

131
types/hapi__hawk/lib/server.d.ts vendored Executable file
View File

@ -0,0 +1,131 @@
import * as http from 'http';
import * as request from 'request';
import * as Crypto from './crypto';
import * as Utils from './utils';
import { Message } from './client';
export type CredentialsFunc = (id: string) => Promise<Credentials> | Credentials;
export type NonceFunc = (key: string, nonce: string, ts: string) => Promise<void> | void;
export interface AuthenticateOptions {
/**
* optional header field name, used to override the default 'Host' header when used
* behind a cache of a proxy. Apache2 changes the value of the 'Host' header while preserving
* the original (which is what the module must verify) in the 'x-forwarded-host' header field.
* Only used when passed a node `http.ServerRequest` object.
*/
hostHeaderName?: string;
/**
* optional nonce validation function. The function signature is `async function(key, nonce, ts)`
* and it must return no value for success or throw an error for invalid state.
*/
nonceFunc?: NonceFunc;
/**
* optional number of seconds of permitted clock skew for incoming timestamps. Defaults to 60 seconds.
* Provides a +/- skew which means actual allowed window is double the number of seconds.
*/
timestampSkewSec?: number;
/**
* Optional local clock time offset express in a number of milliseconds (positive or negative).
* Defaults to 0.
*/
localtimeOffsetMsec?: number;
/**
* optional payload for validation. The client calculates the hash value and includes it via the 'hash'
* header attribute. The server always ensures the value provided has been included in the request
* MAC. When this option is provided, it validates the hash value itself. Validation is done by calculating
* a hash value over the entire payload (assuming it has already be normalized to the same format and
* encoding used by the client to calculate the hash on request). If the payload is not available at the time
* of authentication, the `authenticatePayload()` method can be used by passing it the credentials and
* `attributes.hash` returned from `authenticate()`.
*/
payload?: string;
/**
* optional host name override. Only used when passed a node request object.
*/
host?: string;
/**
* optional port override. Only used when passed a node request object.
*/
port?: number;
}
export interface Credentials {
algorithm: 'sha1' | 'sha256';
key: string;
user: string;
}
export interface Authentication {
artifacts: Crypto.Artifacts;
credentials: Credentials;
}
export interface HeaderOptions {
/** Payload content-type (ignored if hash provided) */
contentType?: string;
/** Application specific data sent via the ext attribute */
ext?: string;
/** Pre-calculated payload hash */
hash?: string;
/** UTF-8 encoded string for body hash generation (ignored if hash provided) */
payload?: string;
}
export type AuthenticateBewitOptions = Pick<
AuthenticateOptions,
'hostHeaderName' | 'localtimeOffsetMsec' | 'host' | 'port'
>;
export interface Bewit {
id: string;
exp: string;
mac: string;
ext: string;
}
export interface AuthenticatedBewit extends AuthenticatedMessage {
bewit: Bewit;
}
export interface AuthenticatedMessage {
credentials: Credentials;
}
export type AuthenticateMessageOptions = Pick<
AuthenticateOptions,
'nonceFunc' | 'timestampSkewSec' | 'localtimeOffsetMsec'
>;
export function authenticate(
req: http.IncomingMessage,
credentialsFunc: CredentialsFunc,
options?: AuthenticateOptions,
): Promise<Authentication>;
export function authenticateBewit(
req: http.IncomingMessage,
credentialsFunc: CredentialsFunc,
options?: AuthenticateBewitOptions,
): AuthenticatedBewit;
export function authenticateMessage(
host: string,
port: number,
message: string,
authorization: Message,
credentialsFunc: CredentialsFunc,
options: AuthenticateMessageOptions,
): Promise<AuthenticatedMessage>;
export function authenticatePayload(
payload: string,
credentials: Credentials,
artifacts: Crypto.Artifacts,
contentType: string,
): void;
export function authenticatePayloadHash(calculatedHash: string, artifacts: Crypto.Artifacts): void;
export function header(credentials: Credentials, artifacts: Crypto.Artifacts, options?: HeaderOptions): string;

51
types/hapi__hawk/lib/utils.d.ts vendored Executable file
View File

@ -0,0 +1,51 @@
import * as Boom from '@hapi/boom';
import * as http from 'http';
import * as https from 'https';
export interface Host {
name: string;
port: number;
}
export interface CustomRequest {
authorization: string;
contentType: string;
host: string;
method: string;
port: number;
url: string;
}
export interface ParseRequestOptions {
host?: string;
hostHeaderName?: string;
name?: string;
port?: number;
}
export const version: string;
export const limits: {
/** Limit the length of uris and headers to avoid a DoS attack on string matching */
maxMatchLength: number;
};
export function now(localtimeOffsetMsec: number): number;
export function nowSecs(localtimeOffsetMsec: number): number;
export function parseAuthorizationHeader(header: string, keys?: string[]): Record<string, string>;
export function parseContentType(header?: string): string;
export function parseHost(req: http.RequestOptions | https.RequestOptions, hostHeaderName?: string): Host | null;
export function parseRequest(
req: http.RequestOptions | https.RequestOptions,
options?: ParseRequestOptions,
): CustomRequest;
export function unauthorized(
message?: string,
attributes?: string | Boom.unauthorized.Attributes,
): Boom.Boom & Boom.unauthorized.MissingAuth;

View File

@ -0,0 +1,6 @@
{
"private": true,
"dependencies": {
"@hapi/boom": "^9.0.0"
}
}

View File

@ -0,0 +1,59 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"dom",
"es6"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"baseUrl": "../",
"paths": {
"@hapi/basic": [
"hapi__basic"
],
"@hapi/boom": [
"hapi__boom"
],
"@hapi/catbox": [
"hapi__catbox"
],
"@hapi/hapi": [
"hapi__hapi"
],
"@hapi/hawk": [
"hapi__hawk"
],
"@hapi/iron": [
"hapi__iron"
],
"@hapi/joi": [
"hapi__joi"
],
"@hapi/mimos": [
"hapi__mimos"
],
"@hapi/podium": [
"hapi__podium"
],
"@hapi/shot": [
"hapi__shot"
],
"@hapi/sntp": [
"hapi__sntp"
]
},
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"hapi__hawk-tests.ts"
]
}

View File

@ -0,0 +1 @@
{ "extends": "dtslint/dt.json" }