Skip to content

Commit

Permalink
Updatge
Browse files Browse the repository at this point in the history
  • Loading branch information
timonson committed Apr 24, 2024
1 parent 95ab87f commit d8c04cb
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 62 deletions.
3 changes: 3 additions & 0 deletions functions/crypto/hash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ export async function generateSecret(
password: string | Uint8Array,
salt: Uint8Array,
): Promise<string> {
if (password.length < 1) {
throw new Error("The password's length must be at least one.");
}
return appendSaltToHash(
await derivePasswordHashWithEncryption(password, salt),
salt,
Expand Down
15 changes: 8 additions & 7 deletions functions/deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ export {
join,
normalize,
resolve,
} from "https://deno.land/std@0.209.0/path/mod.ts";
export { ensureDir, ensureFile } from "https://deno.land/std@0.209.0/fs/mod.ts";
} from "https://deno.land/std@0.223.0/path/mod.ts";
export { ensureDir, ensureFile } from "https://deno.land/std@0.223.0/fs/mod.ts";
export {
decode as decodeFromHex,
encode as encodeToHex,
} from "https://deno.land/std@0.209.0/encoding/hex.ts";
export * as base64 from "https://deno.land/std@0.209.0/encoding/base64.ts";
export * as semver from "https://deno.land/std@0.209.0/semver/mod.ts";
} from "https://deno.land/std@0.223.0/encoding/hex.ts";
export * as base64 from "https://deno.land/std@0.223.0/encoding/base64.ts";
export * as semver from "https://deno.land/std@0.223.0/semver/mod.ts";

/**
* Zaubrik
Expand All @@ -29,11 +29,12 @@ export {
type Payload,
verify,
type VerifyOptions,
} from "https://deno.land/x/[email protected].1/mod.ts";
} from "https://deno.land/x/[email protected].2/mod.ts";
export {
isNumber,
isObject,
isPresent,
isString,
isUndefined,
isUrl,
} from "https://dev.zaubrik.com/[email protected].4/type.js";
} from "https://dev.zaubrik.com/[email protected].5/type.js";
27 changes: 10 additions & 17 deletions functions/env.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,4 @@
/**
* Removes falsey values. Copy/import it from sorcery?
* https://github.com/robertmassaioli/ts-is-present/blob/master/src/index.ts
* ```js
* const foo: = [2,3, null, 4];
* const bar = foo.filter(isPresent); // number[]
* ```
* @template T
* @param {T|undefined|null} input
* @returns {input is T}
*/
export function isPresent<T>(input: T | undefined | null): input is T {
return input !== undefined && input !== null;
}
import { isPresent } from "./deps.ts";

export function assertEnv(env: string[]): string[] {
const result = env.map((v) => Deno.env.get(v)).filter(isPresent);
Expand All @@ -24,6 +11,12 @@ export function assertEnv(env: string[]): string[] {
}
}

export const isProduction = JSON.parse(
Deno.env.get("IS_PRODUCTION") ?? "false",
);
export function isProduction() {
return JSON.parse(
Deno.env.get("IS_PRODUCTION") ?? "false",
);
}

export function getHomeDirectory() {
return Deno.env.get("HOME") || Deno.env.get("USERPROFILE");
}
6 changes: 6 additions & 0 deletions functions/jwt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ function isUpdateInput(input: any): input is UpdateInput {
}
}

export function isCryptoKeyOrUpdateInput(
input: unknown,
): input is CryptoKeyOrUpdateInput {
return isCryptoKey(input) || isUpdateInput(input);
}

export function getJwtFromBearer(headers: Headers): string {
const authHeader = headers.get("Authorization");
if (authHeader === null) {
Expand Down
14 changes: 13 additions & 1 deletion functions/path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,19 @@ export function getPathnameFs(urlOrPath: URL | string): string {
* @return {string}
*/
export function resolveMainModule(relativePath: string): string {
return getPathnameFs(new URL(relativePath, Deno.mainModule));
return getPathnameFs(resolveMainModuleToUrl(relativePath));
}

/**
* Takes a `string` a pathname to the main module.
* ```ts
* resolveMainModuleToUrl("./home/foo");
* ```
* @param {string} relativePath
* @return {URL}
*/
export function resolveMainModuleToUrl(relativePath: string): URL {
return new URL(relativePath, Deno.mainModule);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions functions/subprocess.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ensureFile } from "./deps.ts";
import { decode } from "./util.ts";
import { getPathnameFs } from "./path.ts";
import { getPathnameFs, resolveMainModule } from "./path.ts";

type CommandOptions = ConstructorParameters<typeof Deno.Command>[1];

Expand Down Expand Up @@ -38,7 +38,7 @@ export async function spawnSubprocess(
} else {
const err = decode(stderr) ? decode(stderr) : decode(stdout);
if (options?.debug) {
const path = getPathnameFs(new URL(options.debug, Deno.mainModule));
const path = getPathnameFs(resolveMainModule(options.debug));
await ensureFile(path);
await Deno.writeTextFile(path, `${JSON.stringify([err])},`, {
append: true,
Expand Down
30 changes: 19 additions & 11 deletions middlewares/deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ export {
isAbsolute,
join,
normalize,
} from "https://deno.land/std@0.209.0/path/mod.ts";
} from "https://deno.land/std@0.223.0/path/mod.ts";
export {
ensureFile,
ensureFileSync,
} from "https://deno.land/std@0.209.0/fs/mod.ts";
} from "https://deno.land/std@0.223.0/fs/mod.ts";
export * from "https://deno.land/[email protected]/http/http_errors.ts";
export * as semver from "https://deno.land/[email protected]/semver/mod.ts";
export * from "https://deno.land/[email protected]/http/http_status.ts";
export { serveFile } from "https://deno.land/[email protected]/http/file_server.ts";
export { serveFile } from "https://deno.land/[email protected]/http/file_server.ts";
export * as semver from "https://deno.land/[email protected]/semver/mod.ts";

/**
* mixed
Expand All @@ -27,7 +27,7 @@ export {
type Payload,
verify,
type VerifyOptions,
} from "https://deno.land/x/[email protected].1/mod.ts";
} from "https://deno.land/x/[email protected].2/mod.ts";
export {
type ClientOptions,
type SendConfig,
Expand All @@ -43,24 +43,32 @@ export {
Context,
createHandler,
type Middleware,
type ServerHandlerOptions,
} from "https://dev.zaubrik.com/[email protected]/mod.ts";
export {
type AuthInput,
type Methods,
type Options,
respond,
} from "https://dev.zaubrik.com/[email protected]/server/response.ts";

export {
mergeUrl,
type UrlProperties,
} from "https://dev.zaubrik.com/[email protected].4/path.js";
export { copyResponse } from "https://dev.zaubrik.com/[email protected].4/response.js";
} from "https://dev.zaubrik.com/[email protected].5/url.js";
export { copyResponse } from "https://dev.zaubrik.com/[email protected].5/response.js";
export {
isEmpty,
} from "https://dev.zaubrik.com/[email protected].4/collections/length.js";
} from "https://dev.zaubrik.com/[email protected].5/collections/length.js";
export {
equals,
isFalse,
} from "https://dev.zaubrik.com/[email protected].4/booleans/equality.js";
} from "https://dev.zaubrik.com/[email protected].5/booleans/equality.js";
export {
hasNotProperty,
hasProperty,
hasPropertyOf,
} from "https://dev.zaubrik.com/[email protected].4/objects/membership.js";
} from "https://dev.zaubrik.com/[email protected].5/objects/membership.js";
export {
isDefined,
isError,
Expand All @@ -72,4 +80,4 @@ export {
isString,
isUndefined,
isUrl,
} from "https://dev.zaubrik.com/[email protected].4/type.js";
} from "https://dev.zaubrik.com/[email protected].5/type.js";
12 changes: 6 additions & 6 deletions middlewares/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@ import { getSubdomainPath } from "./subdomain.ts";

type Options = {
hasSubdomainDirectory?: boolean;
disableCopying?: boolean;
isCopy?: boolean;
};

/**
* A curried middleware which fetches and returns a `Response` from another or
* partial `URL` object. The option `disableCopying` returns the original and
* partial `URL` object. The option `isCopy` returns a copy and not the original,
* unmutable `Response`. The option `hasSubdomainDirectory` moves subdomains to
* the pathname.
*/
export function fetchResponse(
urlOrProps?: UrlProperties,
{ hasSubdomainDirectory, disableCopying }: Options = {},
{ hasSubdomainDirectory, isCopy = true }: Options = {},
) {
return async <C extends Context>(ctx: C): Promise<C> => {
try {
Expand All @@ -32,10 +32,10 @@ export function fetchResponse(
}
const newRequest = new Request(url.href, ctx.request);
const response = await fetch(newRequest);
if (disableCopying) {
ctx.response = response;
if (isCopy) {
ctx.response = copyResponse(response);
} else {
ctx.response = copyResponse(ctx.response);
ctx.response = response;
}
return ctx;
} catch (error) {
Expand Down
21 changes: 15 additions & 6 deletions middlewares/log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ function logWithOptions(path: string, options: LoggerOptions) {
};
}

type LoggerOptions = {
export type LoggerOptions = {
print?: boolean;
file?: boolean;
debug?: boolean;
Expand All @@ -83,17 +83,26 @@ type LoggerOptions = {
* ```
*/
export function logger(
url: string | URL = "access.log",
path: string | URL = "access.log",
{ print = true, file = true, debug = false }: LoggerOptions = {},
) {
const path = isUrl(url) || isAbsolute(url)
? getPathnameFs(url)
: resolveMainModule("./" + join(".log/", url));
const log = logWithOptions(path, { print, file, debug });
const absolutePath = isUrl(path) || isAbsolute(path)
? getPathnameFs(path)
: resolveMainModule("./" + join(".log/", path));
const log = logWithOptions(absolutePath, { print, file, debug });
const generator = queue(log);
return <C extends Context>(ctx: C): C => {
const logObject = createLog(ctx);
generator.next({ logObject, error: ctx.error });
return ctx;
};
}

export function logCtx(property?: keyof Context) {
return <C extends Context>(ctx: C): C => {
const value = property ? ctx[property] : ctx;
const prefix = property ? `ctx["${property}"]:` : "ctx:";
console.log(prefix, value);
return ctx;
};
}
1 change: 1 addition & 0 deletions middlewares/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from "./fetch.ts";
export * from "./jwt.ts";
export * from "./log.ts";
export * from "./repository.ts";
export * from "./rpc.ts";
export * from "./smtp.ts";
export * from "./static.ts";
export * from "./subdomain.ts";
Expand Down
36 changes: 36 additions & 0 deletions middlewares/rpc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {
type AuthInput,
type Context,
isFunction,
type Methods,
type Options,
respond,
} from "./deps.ts";
import { isCryptoKeyOrUpdateInput, verifyJwt } from "../functions/jwt.ts";

export function rpcRespond(
methods: Methods,
options: Options & { methodsUrl?: URL } = {},
authInput?: AuthInput,
) {
const verificationInputOrUndefined = authInput?.verification;
const verify = isFunction(verificationInputOrUndefined)
? verificationInputOrUndefined
: isCryptoKeyOrUpdateInput(verificationInputOrUndefined)
? verifyJwt(verificationInputOrUndefined)
: undefined;
return async <C extends Context>(ctx: C) => {
const rpcMethods = options.methodsUrl
? { ...methods, ...await import(options.methodsUrl.pathname) }
: methods;
const newAuthInput = authInput
? verify ? { ...authInput, verification: verify } : authInput
: undefined;
ctx.response = await respond(
rpcMethods,
options,
newAuthInput,
)(ctx.request);
return ctx;
};
}
38 changes: 26 additions & 12 deletions mod.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
export * from "./functions/mod.ts";
export * from "./middlewares/mod.ts";

import { Context, createHandler, type Middleware } from "./middlewares/deps.ts";
import { fallBack, logger } from "./middlewares/mod.ts";
import {
Context,
createHandler,
type Middleware,
type ServerHandlerOptions,
} from "./middlewares/deps.ts";
import { fallBack, logger, type LoggerOptions } from "./middlewares/mod.ts";
import { resolveMainModule } from "./functions/path.ts";

type Options =
& { serveOptions?: Deno.ServeOptions & Deno.ServeTlsOptions }
& { logFile?: Parameters<typeof logger>[0] };
export type DefaultHandlerOptions =
& { handlerOptions?: ServerHandlerOptions<Record<string, any>> }
& { loggerOptions?: LoggerOptions }
& { hostname: string };

/**
* Starts a default HTTP server and handles incoming requests using
Expand All @@ -17,17 +24,24 @@ type Options =
* @example
* ```ts
* import { serveStatic } from "./middlewares/mod.ts";
* serve(serveStatic("./examples/static/"));
* createDefaultHandler(serveStatic("./examples/static/"), { hostname: "zaurbik.de" });
* ```
*/
export function serve(
export function createDefaultHandler(
tryMiddleware: Middleware<Context>,
options: Options = {},
options: DefaultHandlerOptions,
) {
const pid = {
path: resolveMainModule("./.pid"),
name: options.hostname,
append: true,
...options.handlerOptions?.pid,
};
const handlerOptions = { ...options.handlerOptions, pid };
const loggerOptions = { debug: true, ...options.loggerOptions };

const handler = createHandler(Context)(tryMiddleware)(fallBack)(
logger(options.logFile),
logger(options.hostname, loggerOptions),
);
return options.serveOptions
? Deno.serve(options.serveOptions, handler)
: Deno.serve(handler);
return handler;
}

0 comments on commit d8c04cb

Please sign in to comment.