-
-
Notifications
You must be signed in to change notification settings - Fork 38
/
middleware.ts
75 lines (71 loc) · 2.18 KB
/
middleware.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// Copyright 2019-2020 Yusuke Sakurai. All rights reserved. MIT license.
import { RoutingError } from "./error.ts";
import { Sha1 } from "./vendor/https/deno.land/std/hash/sha1.ts";
import { assert } from "./vendor/https/deno.land/std/testing/asserts.ts";
import { ServeHandler } from "./server.ts";
/** Deny requests with 400 if content-type doesn't match */
export const contentTypeFilter = (
...types: (string | RegExp)[]
): ServeHandler =>
async (req) => {
if (types.some((v) => req.headers.get("content-type")?.match(v))) {
return;
}
throw new RoutingError(400);
};
function timeSafeCompare(secret: string, other: string): boolean {
const a = new Sha1();
const b = new Sha1();
a.update(secret);
b.update(other);
return a.toString() === b.toString();
}
export interface BasicAuthOption {
credentials: {
username: string;
password: string;
}[];
message?: string;
}
/** Basic Auth middleware */
export function basicAuth(
{ credentials, message }: BasicAuthOption,
): ServeHandler {
const users = new Map<string, string>();
for (const { username, password } of credentials) {
assert(username, "username must be defined and not be empty");
assert(password, "password must be defined and not be ampty");
users.set(username, password);
}
// WWW-Authenticate: Basic realm="SECRET AREA"
return async function basicAuth(req) {
const authorization = req.headers.get("authorization");
if (!authorization) {
return req.respond({
status: 401,
headers: new Headers({
"www-authenticate": 'Basic realm="RECRET AREA"',
}),
body: message ?? "Authentication Required",
});
} else {
const unauthorized = () =>
req.respond({ status: 401, body: "Unauthorized" });
let m = authorization.match(/^Basic (.+?)$/);
if (!m) {
return unauthorized();
}
const [u, p] = atob(m[1]).split(":");
if (u == null || p == null) {
return unauthorized();
}
const password = users.get(u);
if (password == null) {
return unauthorized();
}
if (!timeSafeCompare(password, p)) {
return unauthorized();
}
}
};
}