Add hash template tag (#560)

This commit is contained in:
Gregory Schier
2017-11-01 12:24:00 +01:00
committed by GitHub
parent f6d00d3d99
commit ccdd0c0a8b
7 changed files with 137 additions and 9 deletions

View File

@@ -5,7 +5,7 @@ import {globalBeforeEach} from '../../../__jest__/before-each';
function assertTemplate (txt, context, expected) {
return async function () {
const result = await templating.render(txt, {context});
expect(result).toMatch(expected);
expect(result).toBe(expected);
};
}
@@ -24,7 +24,7 @@ describe('FileExtension', () => {
beforeEach(globalBeforeEach);
const ctx = {path: path.resolve(__dirname, path.join('./test.txt'))};
const escapedPath = ctx.path.replace(/\\/g, '\\\\');
it('reads from string', assertTemplate(`{% file "${escapedPath}" %}`, ctx, 'Hello World'));
it('reads from string', assertTemplate(`{% file "${escapedPath}" %}`, ctx, 'Hello World!'));
it('reads a file correctly', assertTemplate('{% file path %}', ctx, 'Hello World!'));
it('fails on missing file', assertTemplateFails('{% file "/foo" %}', ctx, `ENOENT: no such file or directory, open '${path.resolve('/foo')}'`));
it('fails on no 2nd param', assertTemplateFails('{% file %}', ctx, 'No file selected'));

View File

@@ -0,0 +1,73 @@
import * as templating from '../../index';
import {globalBeforeEach} from '../../../__jest__/before-each';
function assertTemplate (txt, expected) {
return async function () {
const result = await templating.render(txt);
expect(result).toBe(expected);
};
}
function assertTemplateFails (txt, expected) {
return async function () {
try {
await templating.render(txt);
fail(`Render should have thrown ${expected}`);
} catch (err) {
expect(err.message).toContain(expected);
}
};
}
describe('FileExtension', () => {
beforeEach(globalBeforeEach);
// Algorithms
it('hashes sha1', assertTemplate(
'{% hash "sha1", "hex", "foo" %}',
'0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33'
));
it('hashes sha256', assertTemplate(
'{% hash "sha256", "hex", "foo" %}',
'2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae'
));
it('hashes md5', assertTemplate(
'{% hash "md5", "hex", "foo" %}',
'acbd18db4cc2f85cedef654fccc4a4d8'
));
it('fails to hash invalid algorithm', assertTemplateFails(
'{% hash "bad", "hex", "foo" %}',
'Digest method not supported'
));
// Digests
it('hashes to latin1', assertTemplate(
'{% hash "md5", "latin1", "foo" %}',
'¬½ÛLÂø\\íïeOÌĤØ'
));
it('hashes to hex', assertTemplate(
'{% hash "md5", "hex", "foo" %}',
'acbd18db4cc2f85cedef654fccc4a4d8'
));
it('hashes to base64', assertTemplate(
'{% hash "md5", "base64", "foo" %}',
'rL0Y20zC+Fzt72VPzMSk2A=='
));
it('fails to hash to invalid', assertTemplateFails(
'{% hash "md5", "bad", "foo" %}',
'Invalid encoding bad. Choices are hex, latin1, base64'
));
// Values
it('hashes empty string', assertTemplate(
'{% hash "md5", "hex", "" %}',
'd41d8cd98f00b204e9800998ecf8427e'
));
it('hashes no string', assertTemplate(
'{% hash "md5", "hex" %}',
'd41d8cd98f00b204e9800998ecf8427e'
));
it('fails to hash non string', assertTemplateFails(
'{% hash "md5", "hex", true %}',
'Cannot hash value of type "boolean"'
));
});

View File

@@ -0,0 +1,49 @@
// @flow
import crypto from 'crypto';
import type {PluginTemplateTag} from './index';
export default ({
name: 'hash',
displayName: 'Hash',
description: 'Apply hash to a value',
args: [
{
displayName: 'Algorithm',
type: 'enum',
options: [
{displayName: 'MD5', value: 'md5'},
{displayName: 'SHA1', value: 'sha1'},
{displayName: 'SHA256', value: 'sha256'},
{displayName: 'SHA512', value: 'sha512'}
]
},
{
displayName: 'Digest Encoding',
description: 'The encoding of the output',
type: 'enum',
options: [
{displayName: 'Hexadecimal', value: 'hex'},
{displayName: 'Base64', value: 'base64'}
]
},
{
displayName: 'Input',
type: 'string',
placeholder: 'Value to hash'
}
],
run (context: Object, algorithm: string, encoding: string, value: string = ''): string {
if (encoding !== 'hex' && encoding !== 'latin1' && encoding !== 'base64') {
throw new Error(`Invalid encoding ${encoding}. Choices are hex, latin1, base64`);
}
const valueType = typeof value;
if (valueType !== 'string') {
throw new Error(`Cannot hash value of type "${valueType}"`);
}
const hash = crypto.createHash(algorithm);
hash.update(value || '', 'utf8');
return hash.digest(encoding);
}
}: PluginTemplateTag);

View File

@@ -7,6 +7,7 @@ import nowExtension from './now-extension';
import fileExtension from './file-extension';
import responseExtension from './response-extension';
import base64Extension from './base-64-extension';
import hashExtension from './hash-extension';
import requestExtension from './request-extension';
import type {NunjucksParsedTagArg} from '../utils';
import type {Request} from '../../models/request';
@@ -24,8 +25,8 @@ type PluginArgumentBase = {
export type PluginArgumentEnumOption = {
displayName: DisplayName,
description: string,
value: PluginArgumentValue,
description?: string,
placeholder?: string
}
@@ -96,10 +97,11 @@ export type PluginTemplateTag = {
const DEFAULT_EXTENSIONS: Array<PluginTemplateTag> = [
timestampExtension,
fileExtension,
nowExtension,
uuidExtension,
base64Extension,
fileExtension,
hashExtension,
requestExtension,
responseExtension
];

View File

@@ -1,6 +1,8 @@
// @flow
import uuid from 'uuid';
import type {PluginTemplateTag} from './index';
export default {
export default ({
displayName: 'UUID',
name: 'uuid',
description: 'generate v1 or v4 UUIDs',
@@ -30,4 +32,4 @@ export default {
throw new Error(`Invalid UUID type "${uuidType}"`);
}
}
};
}: PluginTemplateTag);

View File

@@ -384,8 +384,9 @@ class TagEditor extends React.PureComponent<Props, State> {
<select value={value} onChange={this._handleChange}>
{options.map(option => {
let label: string;
if (option.description) {
label = `${fnOrString(option.displayName, argDatas)} ${option.description}`;
const {description} = option;
if (description) {
label = `${fnOrString(option.displayName, argDatas)} ${description}`;
} else {
label = fnOrString(option.displayName, argDatas);
}

3
flow-typed/uuid.js vendored
View File

@@ -1,5 +1,6 @@
declare module 'uuid' {
declare module.exports: {
v4: () => string
v4: () => string,
v1: () => string
}
}