diff --git a/src/auth.spec.ts b/src/auth.spec.ts deleted file mode 100644 index f5ee907..0000000 --- a/src/auth.spec.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { describe, it, assert } from 'vitest'; -import auth from './index'; - -function request(authorization?: string) { - return { - headers: { - authorization: authorization, - }, - }; -} - -describe('auth(req)', function () { - describe('arguments', function () { - describe('req', function () { - it('should be required', function () { - assert.throws(auth as any, /argument req is required/); - }); - - it('should accept a request', function () { - var req = request('basic Zm9vOmJhcg=='); - var creds = auth(req); - assert.strictEqual(creds?.name, 'foo'); - assert.strictEqual(creds?.pass, 'bar'); - }); - - it('should reject null', function () { - assert.throws(auth.bind(null, null as any), /argument req is required/); - }); - - it('should reject a number', function () { - assert.throws(auth.bind(null, 42 as any), /argument req is required/); - }); - - it('should reject an object without headers', function () { - assert.throws(auth.bind(null, {}), /argument req is required/); - }); - }); - }); - - describe('with no Authorization field', function () { - it('should return undefined', function () { - var req = request(); - assert.strictEqual(auth(req), undefined); - }); - }); - - describe('with malformed Authorization field', function () { - it('should return undefined', function () { - var req = request('Something'); - assert.strictEqual(auth(req), undefined); - }); - }); - - describe('with malformed Authorization scheme', function () { - it('should return undefined', function () { - var req = request('basic_Zm9vOmJhcg=='); - assert.strictEqual(auth(req), undefined); - }); - }); - - describe('with malformed credentials', function () { - it('should return undefined', function () { - var req = request('basic Zm9vcgo='); - assert.strictEqual(auth(req), undefined); - }); - }); - - describe('with valid credentials', function () { - it('should return .name and .pass', function () { - var req = request('basic Zm9vOmJhcg=='); - var creds = auth(req); - assert.strictEqual(creds?.name, 'foo'); - assert.strictEqual(creds?.pass, 'bar'); - }); - }); - - describe('with empty password', function () { - it('should return .name and .pass', function () { - var req = request('basic Zm9vOg=='); - var creds = auth(req); - assert.strictEqual(creds?.name, 'foo'); - assert.strictEqual(creds?.pass, ''); - }); - }); - - describe('with empty userid', function () { - it('should return .name and .pass', function () { - var req = request('basic OnBhc3M='); - var creds = auth(req); - assert.strictEqual(creds?.name, ''); - assert.strictEqual(creds?.pass, 'pass'); - }); - }); - - describe('with empty userid and pass', function () { - it('should return .name and .pass', function () { - var req = request('basic Og=='); - var creds = auth(req); - assert.strictEqual(creds?.name, ''); - assert.strictEqual(creds?.pass, ''); - }); - }); - - describe('with colon in pass', function () { - it('should return .name and .pass', function () { - var req = request('basic Zm9vOnBhc3M6d29yZA=='); - var creds = auth(req); - assert.strictEqual(creds?.name, 'foo'); - assert.strictEqual(creds?.pass, 'pass:word'); - }); - }); - - describe('with scheme "Basic"', function () { - it('should return .name and .pass', function () { - var req = request('Basic Zm9vOmJhcg=='); - var creds = auth(req); - assert.strictEqual(creds?.name, 'foo'); - assert.strictEqual(creds?.pass, 'bar'); - }); - }); - - describe('with scheme "BASIC"', function () { - it('should return .name and .pass', function () { - var req = request('BASIC Zm9vOmJhcg=='); - var creds = auth(req); - assert.strictEqual(creds?.name, 'foo'); - assert.strictEqual(creds?.pass, 'bar'); - }); - }); - - describe('with scheme "BaSiC"', function () { - it('should return .name and .pass', function () { - var req = request('BaSiC Zm9vOmJhcg=='); - var creds = auth(req); - assert.strictEqual(creds?.name, 'foo'); - assert.strictEqual(creds?.pass, 'bar'); - }); - }); -}); diff --git a/src/index.ts b/src/index.ts index 98bc6c4..6576a46 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,74 +8,43 @@ import { Buffer } from 'node:buffer'; -export = auth; +/** + * Object to represent user credentials. + */ +export interface Credentials { + name: string; + pass: string; +} /** - * Parse the Authorization header field of a request + * Parse basic auth to object. + * + * @param {string} string + * @return {object} * @public */ -function auth(req: auth.IncomingMessageLike): auth.Credentials | undefined { - if (!req) { - throw new TypeError('argument req is required'); +export function parse(string: string): Credentials | undefined { + if (typeof string !== 'string') { + return undefined; } - if (typeof req !== 'object') { - throw new TypeError('argument req is required to be an object'); - } - - // get header - const header = getAuthorization(req); - // parse header - return auth.parse(header ?? ''); -} + const match = CREDENTIALS_REGEXP.exec(string); -namespace auth { - /** - * Object to represent user credentials. - */ - export interface Credentials { - name: string; - pass: string; + if (!match) { + return undefined; } - export interface IncomingMessageLike { - headers?: { - authorization?: string; - }; - } - - /** - * Parse basic auth to object. - * - * @param {string} string - * @return {object} - * @public - */ - - export function parse(string: string): auth.Credentials | undefined { - if (typeof string !== 'string') { - return undefined; - } + // decode user pass + const userPass = USER_PASS_REGEXP.exec(decodeBase64(match[1])); - // parse header - const match = CREDENTIALS_REGEXP.exec(string); - - if (!match) { - return undefined; - } - - // decode user pass - const userPass = USER_PASS_REGEXP.exec(decodeBase64(match[1])); - - if (!userPass) { - return undefined; - } - - // return credentials object - return new CredentialsImpl(userPass[1], userPass[2]); + if (!userPass) { + return undefined; } + + // return credentials object + return new CredentialsImpl(userPass[1], userPass[2]); } /** @@ -110,20 +79,7 @@ function decodeBase64(str: string): string { return Buffer.from(str, 'base64').toString(); } -/** - * Get the Authorization header from request object. - * @private - */ - -function getAuthorization(req: auth.IncomingMessageLike) { - if (!req.headers || typeof req.headers !== 'object') { - throw new TypeError('argument req is required to have headers property'); - } - - return req.headers.authorization; -} - -class CredentialsImpl implements auth.Credentials { +class CredentialsImpl implements Credentials { name: string; pass: string; diff --git a/src/parse.spec.ts b/src/parse.spec.ts index 06edfbf..4f3f692 100644 --- a/src/parse.spec.ts +++ b/src/parse.spec.ts @@ -1,42 +1,34 @@ import { describe, it, assert } from 'vitest'; -import auth from './index'; +import { parse } from './index'; -function request(authorization: string) { - return { - headers: { - authorization: authorization, - }, - }; -} - -describe('auth.parse(string)', function () { +describe('parse(string)', function () { describe('with undefined string', function () { it('should return undefined', function () { - assert.strictEqual((auth as any).parse(), undefined); + assert.strictEqual((parse as any)(), undefined); }); }); describe('with malformed string', function () { it('should return undefined', function () { - assert.strictEqual(auth.parse('Something'), undefined); + assert.strictEqual(parse('Something'), undefined); }); }); describe('with malformed scheme', function () { it('should return undefined', function () { - assert.strictEqual(auth.parse('basic_Zm9vOmJhcg=='), undefined); + assert.strictEqual(parse('basic_Zm9vOmJhcg=='), undefined); }); }); describe('with malformed credentials', function () { it('should return undefined', function () { - assert.strictEqual(auth.parse('basic Zm9vcgo='), undefined); + assert.strictEqual(parse('basic Zm9vcgo='), undefined); }); }); describe('with valid credentials', function () { it('should return .name and .pass', function () { - var creds = auth.parse('basic Zm9vOmJhcg=='); + var creds = parse('basic Zm9vOmJhcg=='); assert.strictEqual(creds?.name, 'foo'); assert.strictEqual(creds?.pass, 'bar'); }); @@ -44,7 +36,7 @@ describe('auth.parse(string)', function () { describe('with empty password', function () { it('should return .name and .pass', function () { - var creds = auth.parse('basic Zm9vOg=='); + var creds = parse('basic Zm9vOg=='); assert.strictEqual(creds?.name, 'foo'); assert.strictEqual(creds?.pass, ''); }); @@ -52,7 +44,7 @@ describe('auth.parse(string)', function () { describe('with empty userid', function () { it('should return .name and .pass', function () { - var creds = auth.parse('basic OnBhc3M='); + var creds = parse('basic OnBhc3M='); assert.strictEqual(creds?.name, ''); assert.strictEqual(creds?.pass, 'pass'); }); @@ -60,7 +52,7 @@ describe('auth.parse(string)', function () { describe('with empty userid and pass', function () { it('should return .name and .pass', function () { - var creds = auth.parse('basic Og=='); + var creds = parse('basic Og=='); assert.strictEqual(creds?.name, ''); assert.strictEqual(creds?.pass, ''); }); @@ -68,7 +60,7 @@ describe('auth.parse(string)', function () { describe('with colon in pass', function () { it('should return .name and .pass', function () { - var creds = auth.parse('basic Zm9vOnBhc3M6d29yZA=='); + var creds = parse('basic Zm9vOnBhc3M6d29yZA=='); assert.strictEqual(creds?.name, 'foo'); assert.strictEqual(creds?.pass, 'pass:word'); }); @@ -76,8 +68,7 @@ describe('auth.parse(string)', function () { describe('with scheme "Basic"', function () { it('should return .name and .pass', function () { - var req = request('Basic Zm9vOmJhcg=='); - var creds = auth(req); + var creds = parse('Basic Zm9vOmJhcg=='); assert.strictEqual(creds?.name, 'foo'); assert.strictEqual(creds?.pass, 'bar'); }); @@ -85,8 +76,7 @@ describe('auth.parse(string)', function () { describe('with scheme "BASIC"', function () { it('should return .name and .pass', function () { - var req = request('BASIC Zm9vOmJhcg=='); - var creds = auth(req); + var creds = parse('BASIC Zm9vOmJhcg=='); assert.strictEqual(creds?.name, 'foo'); assert.strictEqual(creds?.pass, 'bar'); }); @@ -94,8 +84,7 @@ describe('auth.parse(string)', function () { describe('with scheme "BaSiC"', function () { it('should return .name and .pass', function () { - var req = request('BaSiC Zm9vOmJhcg=='); - var creds = auth(req); + var creds = parse('BaSiC Zm9vOmJhcg=='); assert.strictEqual(creds?.name, 'foo'); assert.strictEqual(creds?.pass, 'bar'); });