Skip to content

Commit df00380

Browse files
committed
ESM fix + docker support
1 parent 0dd78e9 commit df00380

17 files changed

+103
-79
lines changed

.dockerignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
*.crt
2+
Dockerfile.*
3+
.DS_Store
4+
.git
5+
.github
6+
.gitignore
7+
.editorconfig
8+
*.env*
9+
*.key
10+
*.log
11+
*.md
12+
node_modules
13+
*.pem
14+
*.sh
15+
*.tmp
16+
tmp*

Dockerfile

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,29 @@
1-
FROM node:current-stretch-slim as base
2-
RUN groupadd -r appuser && \
3-
useradd --create-home --gid appuser --home-dir /app --no-log-init --system appuser
1+
# syntax=docker/dockerfile:1.7-labs
2+
FROM node:22-bookworm AS build
3+
4+
RUN apt-get update && apt-get install -y \
5+
dumb-init
46

5-
FROM base AS build
67
WORKDIR /app
7-
USER appuser
8-
COPY --chown=appuser:appuser . .
8+
COPY . .
99
RUN npm install && \
1010
npm run build
1111

12-
FROM base AS run
12+
FROM gcr.io/distroless/nodejs22-debian12
13+
14+
ARG COMMIT="(not set)"
15+
ARG LASTMOD="(not set)"
16+
ENV COMMIT=$COMMIT
17+
ENV LASTMOD=$LASTMOD
18+
1319
WORKDIR /app
14-
USER appuser
15-
COPY --chown=appuser:appuser . .
16-
COPY --chown=appuser:appuser --from=build /app/dist /app/dist
17-
RUN npm install --production
20+
USER nonroot
21+
COPY --chown=nonroot:nonroot --exclude=src . .
22+
COPY --chown=nonroot:nonroot --from=build /app/node_modules /app/node_modules
23+
COPY --chown=nonroot:nonroot --from=build /app/dist /app/dist
24+
COPY --chown=nonroot:nonroot --from=build /usr/bin/dumb-init /usr/bin/dumb-init
1825
EXPOSE 4000
1926
ENV PORT 4000
20-
CMD ["npm", "start"]
27+
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
28+
CMD ["/nodejs/bin/node", "/app/dist/server.js"]
2129

docker-run.sh

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/bin/bash
2+
3+
set -o errexit
4+
set -o pipefail
5+
set -o nounset
6+
7+
APP_NAME=resolvers
8+
9+
docker build \
10+
--build-arg COMMIT=$(git rev-parse --short HEAD) \
11+
--build-arg LASTMOD=$(date -u +%Y-%m-%dT%H:%M:%SZ) \
12+
--progress plain \
13+
--tag "${APP_NAME}" \
14+
.
15+
16+
echo "INFO: running"
17+
docker run \
18+
--env-file .env \
19+
--env PORT=4000 \
20+
--expose 4000 \
21+
--interactive \
22+
--name "${APP_NAME}" \
23+
--publish 4000:4000 \
24+
--rm \
25+
--tty \
26+
"${APP_NAME}"
27+

package-lock.json

Lines changed: 10 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@
3939
"@types/koa-session": "^6.4.2",
4040
"@types/koa-static": "^4.0.1",
4141
"@types/luxon": "^3.3.2",
42-
"@types/node": "^20.16.10",
42+
"@types/node": "^20.16.11",
4343
"@types/psl": "^1.1.0",
4444
"@types/punycode": "^2.1.0",
4545
"@types/tmp": "^0.2.0",
4646
"@types/urijs": "^1.19.3",
4747
"@types/uuid": "^10.0.0",
4848
"pino-pretty": "^11.2.2",
49-
"typescript": "^5.6.2"
49+
"typescript": "^5.6.3"
5050
},
5151
"engines": {
5252
"node": ">=20",

src/ChangeLogUI.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Handlebars from 'handlebars';
1+
import handlebars from 'handlebars';
22
import Router from '@koa/router';
33
import { DateTime } from 'luxon';
44

@@ -30,7 +30,7 @@ class ChangeLogUI {
3030
aplink: this.aplink,
3131
count: this.changeLog.getKeys().length,
3232
data: this.changeLog.getAll(),
33-
h1: new Handlebars.SafeString(`<a href="../index.html">${Handlebars.escapeExpression(this.title)}</a> Change Log`),
33+
h1: new handlebars.SafeString(`<a href="../index.html">${handlebars.escapeExpression(this.title)}</a> Change Log`),
3434
rssUrl: `https://resolve.rs${this.mount}/rss.xml`,
3535
title: `${this.title} Change Log`,
3636
});
@@ -44,7 +44,7 @@ class ChangeLogUI {
4444
ctx.body = await ctx.render('_changelog/_index.hbs', {
4545
data,
4646
date,
47-
h1: new Handlebars.SafeString(`<a href="../index.html">${Handlebars.escapeExpression(this.title)}</a> Changes on ${date}`),
47+
h1: new handlebars.SafeString(`<a href="../index.html">${handlebars.escapeExpression(this.title)}</a> Changes on ${date}`),
4848
next: this.changeLog.getNext(date),
4949
previous: this.changeLog.getPrevious(date),
5050
title: `${this.title} Changes on ${date}`,

src/actions/asnlookup.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Handlebars from 'handlebars';
1+
import handlebars from 'handlebars';
22
import * as net from 'net';
33

44
import * as asn from "../data/maxmindData.js";
@@ -50,7 +50,7 @@ async function asnLookupGet(ctx: any) {
5050
const ip = ctx.query.ip || util.getCurrentIP(ctx);
5151

5252
if (net.isIP(ip) == 0) {
53-
ctx.flash('error', `${Handlebars.escapeExpression(ip)} is not a valid IP address!`);
53+
ctx.flash('error', `${handlebars.escapeExpression(ip)} is not a valid IP address!`);
5454
}
5555

5656
const asndata = asn.asnLookup(ip);

src/actions/certcheck.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as crypto from 'crypto';
2-
import Handlebars from 'handlebars';
2+
import handlebars from 'handlebars';
33
import * as http from 'http';
44
import * as https from 'https';
55
import * as tls from 'tls';
@@ -42,7 +42,7 @@ async function tlsCertCheckPost(ctx:any) {
4242
}
4343

4444
if (!util.hasValidPublicSuffix(hostname)) {
45-
ctx.flash('error', `${Handlebars.escapeExpression(hostname)} is not a valid hostname!`);
45+
ctx.flash('error', `${handlebars.escapeExpression(hostname)} is not a valid hostname!`);
4646
ctx.redirect(`tls-cert-check.html?hostname=${encodeURIComponent(hostname)}`);
4747
return;
4848
}
@@ -281,14 +281,14 @@ async function httpsCertCheckPost(ctx:any) {
281281
const url = new URL(hostname);
282282
hostname = url.host;
283283
} catch (err) {
284-
ctx.flash('error', `Unable to parse: ${Handlebars.escapeExpression(err.message)}`);
284+
ctx.flash('error', `Unable to parse: ${handlebars.escapeExpression(err.message)}`);
285285
ctx.redirect(`cert-check.html?hostname=${encodeURIComponent(hostname)}`);
286286
return;
287287
}
288288
}
289289

290290
if (!util.hasValidPublicSuffix(hostname)) {
291-
ctx.flash('error', `${Handlebars.escapeExpression(hostname)} is not a valid hostname!`);
291+
ctx.flash('error', `${handlebars.escapeExpression(hostname)} is not a valid hostname!`);
292292
ctx.redirect(`cert-check.html?hostname=${encodeURIComponent(hostname)}`);
293293
return;
294294
}

src/actions/domainfinder.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { promises as dnsPromises } from 'dns';
2-
import Handlebars from 'handlebars';
2+
import handlebars from 'handlebars';
33

44
import { niceTlds as tlds } from "../data/domainData.js";
55
import * as streamer from "../streamer.js";
@@ -23,7 +23,7 @@ async function domainFinderPost(ctx:any) {
2323
word = word.toLowerCase().trim();
2424

2525
if (!word.match(/^[a-z0-9]+/)) {
26-
ctx.flash('error', `${Handlebars.escapeExpression(word)} is not a valid word: it can only contain a-z and 0-9!`);
26+
ctx.flash('error', `${handlebars.escapeExpression(word)} is not a valid word: it can only contain a-z and 0-9!`);
2727
ctx.redirect(`finder.html?word=${encodeURIComponent(word)}`);
2828
return;
2929
}

src/actions/headers.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
//import Handlebars from 'handlebars';
21
import axios from 'axios';
32

43
import * as util from "../util.js";

src/actions/reverselookup.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { promises as dnsPromises } from 'dns';
2-
import Handlebars from 'handlebars';
2+
import handlebars from 'handlebars';
33
import * as net from 'net';
44

55
import * as asn from "../data/maxmindData.js";
@@ -71,7 +71,7 @@ async function reverseLookupPost(ctx: any) {
7171
}
7272

7373
if (net.isIP(ip) == 0) {
74-
ctx.flash('error', `${Handlebars.escapeExpression(ip)} is not a valid IP address!`);
74+
ctx.flash('error', `${handlebars.escapeExpression(ip)} is not a valid IP address!`);
7575
ctx.redirect(`/dns/reverse-lookup.html?ip=${encodeURIComponent(ip)}`);
7676
return;
7777
}

src/routers/cryptoRouter.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import crypto from 'crypto';
22
import { promises as fsPromises } from 'fs';
3-
import Handlebars from 'handlebars';
3+
import handlebars from 'handlebars';
44
import Koa from 'koa';
55
import Router from '@koa/router';
66

@@ -33,10 +33,10 @@ function toHexSeparated(bytes:Buffer):string {
3333
return dest.join(' ');
3434
}
3535

36-
function toHexPretty(bytes:Buffer):Handlebars.SafeString|string {
36+
function toHexPretty(bytes:Buffer):handlebars.SafeString|string {
3737

3838
if (bytes.length == 0) {
39-
return new Handlebars.SafeString("<i>(none)</i>");
39+
return new handlebars.SafeString("<i>(none)</i>");
4040
}
4141
if (bytes.length < 32) {
4242
return toHexSeparated(bytes);

src/routers/datagenRouter.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//import { promises as fsPromises } from 'fs';
22
import HaikunatorImpl from "haikunator";
33
const Haikunator = HaikunatorImpl as unknown as typeof HaikunatorImpl.default;
4-
//import Handlebars from 'handlebars';
54
import Koa from 'koa';
65
import Router from '@koa/router';
76

src/routers/dnsRouter.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { promises as dnsPromises } from 'dns';
2-
import Handlebars from 'handlebars';
2+
import handlebars from 'handlebars';
33
import Router from '@koa/router';
44

55
import * as dnssec from '../actions/dnssec.js';
@@ -41,12 +41,12 @@ dnsRouter.post('/dns/lookup.html', async (ctx:any) => {
4141
const url = new URL(hostname);
4242
hostname = url.hostname;
4343
} catch (err) {
44-
ctx.flash('error', `Unable to extract a hostname from "${Handlebars.escapeExpression(hostname)}"!`);
44+
ctx.flash('error', `Unable to extract a hostname from "${handlebars.escapeExpression(hostname)}"!`);
4545
ctx.redirect(`/dns/lookup.html?hostname=${encodeURIComponent(hostname)}`);
4646
return;
4747
}
4848
if (!util.hasValidPublicSuffix(hostname)) {
49-
ctx.flash('error', `${Handlebars.escapeExpression(hostname)} is not a valid hostname!`);
49+
ctx.flash('error', `${handlebars.escapeExpression(hostname)} is not a valid hostname!`);
5050
ctx.redirect(`/dns/lookup.html?hostname=${encodeURIComponent(hostname)}`);
5151
return;
5252
}

src/routers/pslRouter.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Handlebars from 'handlebars';
1+
import handlebars from 'handlebars';
22
import Router from '@koa/router';
33
import path from 'path';
44
import * as tldts from 'tldts';
@@ -35,7 +35,7 @@ pslRouter.get('/psl/test.html', async (ctx: any) => {
3535
let parsed: any;
3636
if (hostname) {
3737
if (!util.hasValidPublicSuffix(hostname)) {
38-
ctx.flash('error', `${Handlebars.escapeExpression(hostname)} is not a valid public domain!`);
38+
ctx.flash('error', `${handlebars.escapeExpression(hostname)} is not a valid public domain!`);
3939
} else {
4040
parsed = tldts.parse(hostname);
4141
}

src/routers/rootRouter.ts

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
import Router from '@koa/router';
2-
import * as os from 'os';
3-
import * as url from 'url';
4-
const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
52

63
import * as asn from "../data/maxmindData.js";
74
import * as resolvers from "../data/resolverData.js";
@@ -54,30 +51,6 @@ rootRouter.get('/status.json', async (ctx) => {
5451
retVal["tech"] = "NodeJS " + process.version;
5552
retVal["lastmod"] = process.env.LASTMOD || '(not set)';
5653
retVal["commit"] = process.env.COMMIT || '(not set)';
57-
retVal["__dirname"] = __dirname;
58-
retVal["__filename"] = __filename;
59-
retVal["os.hostname"] = os.hostname();
60-
retVal["os.type"] = os.type();
61-
retVal["os.platform"] = os.platform();
62-
retVal["os.arch"] = os.arch();
63-
retVal["os.release"] = os.release();
64-
retVal["os.uptime"] = os.uptime();
65-
retVal["os.loadavg"] = os.loadavg();
66-
retVal["os.totalmem"] = os.totalmem();
67-
retVal["os.freemem"] = os.freemem();
68-
retVal["os.cpus.length"] = os.cpus().length;
69-
// too much junk: retVal["os.networkInterfaces"] = os.networkInterfaces();
70-
71-
retVal["process.arch"] = process.arch;
72-
retVal["process.cwd"] = process.cwd();
73-
retVal["process.execPath"] = process.execPath;
74-
retVal["process.memoryUsage"] = process.memoryUsage();
75-
retVal["process.platform"] = process.platform;
76-
retVal["process.release"] = process.release;
77-
retVal["process.title"] = process.title;
78-
retVal["process.uptime"] = process.uptime();
79-
retVal["process.version"] = process.version;
80-
retVal["process.versions"] = process.versions;
8154

8255
retVal["resolvers"] = resolvers.getAll().length;
8356

0 commit comments

Comments
 (0)