Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 10 additions & 19 deletions src/format.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ describe('format(credentials)', function () {
describe('arguments', function () {
describe('credentials', function () {
it('should be required', function () {
assert.throws(
() => (format as any)(),
/argument credentials is required/,
);
assert.throws(() => (format as any)(), /credentials is required/);
});

it('should accept credentials', function () {
Expand All @@ -19,63 +16,57 @@ describe('format(credentials)', function () {
it('should reject null', function () {
assert.throws(
format.bind(null, null as any),
/argument credentials is required/,
/credentials is required/,
);
});

it('should reject a number', function () {
assert.throws(
format.bind(null, 42 as any),
/argument credentials is required/,
);
assert.throws(format.bind(null, 42 as any), /credentials is required/);
});

it('should reject a string', function () {
assert.throws(
format.bind(null, '' as any),
/argument credentials is required/,
);
assert.throws(format.bind(null, '' as any), /credentials is required/);
});

it('should reject an object without name', function () {
assert.throws(
format.bind(null, { pass: 'bar' } as any),
/argument credentials is required to have name and pass properties/,
/credentials is required to have name and pass properties/,
);
});

it('should reject an object without pass', function () {
assert.throws(
format.bind(null, { name: 'foo' } as any),
/argument credentials is required to have name and pass properties/,
/credentials is required to have name and pass properties/,
);
});

it('should reject an object with non-string name', function () {
assert.throws(
format.bind(null, { name: 42, pass: 'bar' } as any),
/argument credentials is required to have name and pass properties/,
/credentials is required to have name and pass properties/,
);
});

it('should reject an object with non-string pass', function () {
assert.throws(
format.bind(null, { name: 'foo', pass: 42 } as any),
/argument credentials is required to have name and pass properties/,
/credentials is required to have name and pass properties/,
);
});

it('should reject userid containing colon', function () {
assert.throws(
format.bind(null, { name: 'foo:bar', pass: 'baz' }),
/must not contain a colon or control characters/,
/must not contain a colon/,
);
});

it('should reject control chars in userid', function () {
assert.throws(
format.bind(null, { name: 'foo\u0000bar', pass: 'baz' }),
/must not contain a colon or control characters/,
/must not contain control characters/,
);
});

Expand Down
28 changes: 11 additions & 17 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,39 +52,33 @@ export function parse(string: string): Credentials | undefined {
* @public
*/
export function format(credentials: Credentials): string {
if (!credentials) {
throw new TypeError('argument credentials is required');
}

if (typeof credentials !== 'object') {
throw new TypeError('argument credentials is required to be an object');
if (typeof credentials !== 'object' || credentials === null) {
throw new TypeError('credentials is required to be an object');
}

if (
typeof credentials.name !== 'string' ||
typeof credentials.pass !== 'string'
) {
throw new TypeError(
'argument credentials is required to have name and pass properties',
'credentials is required to have name and pass properties',
);
}

if (
credentials.name.includes(':') || // RFC 7617 disallows colon in username
CONTROL_CHARS_REGEXP.test(credentials.name)
) {
throw new TypeError(
'argument credentials.name must not contain a colon or control characters',
);
// RFC 7617 disallows colon in username
if (credentials.name.includes(':')) {
throw new TypeError('name must not contain a colon');
}

if (CONTROL_CHARS_REGEXP.test(credentials.pass)) {
const str = credentials.name + ':' + credentials.pass;

if (CONTROL_CHARS_REGEXP.test(str)) {
throw new TypeError(
'argument credentials.pass must not contain control characters',
'argument credentials must not contain control characters',
);
}

return 'Basic ' + base64.encode(credentials.name + ':' + credentials.pass);
return 'Basic ' + base64.encode(str);
}

/**
Expand Down
Loading