Skip to content
Merged
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
6 changes: 6 additions & 0 deletions src/commons/envutil.js
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,12 @@ export function imageRef() {
return envManager.get("FLY_IMAGE_REF") || "";
}

export function hostId() {
if (!envManager) return "";

return envManager.get("HOST_IDENTIFIER") || "";
}

export function secretb64() {
if (!envManager) return null;

Expand Down
14 changes: 13 additions & 1 deletion src/core/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,16 @@ export default class EnvManager {
return null;
}

// most relevant host id for this env
mostRelevantHostId(cloud) {
if (cloud === "local") return "localhost";
if (cloud === "fly") return this.get("FLY_MACHINE_ID") || "";
if (cloud === "deno-deploy") {
return this.get("DENO_REGION") + ":" + this.get("DENO_DEPLOYMENT_ID");
}
return "";
}

/**
* Makes default env values.
* @return {Map} Runtime environment defaults.
Expand All @@ -357,7 +367,9 @@ export default class EnvManager {
env.set(key, caststr(val, type));
}

env.set("CLOUD_PLATFORM", this.mostLikelyCloudPlatform());
const cloud = this.mostLikelyCloudPlatform();
env.set("CLOUD_PLATFORM", cloud);
env.set("HOST_IDENTIFIER", this.mostRelevantHostId(cloud)); // may be empty

return env;
}
Expand Down
9 changes: 8 additions & 1 deletion src/core/node/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
hmacsign,
sha512,
} from "../../commons/crypto.js";
import * as envutil from "../../commons/envutil.js";
import * as util from "../../commons/util.js";

const encctx = bufutil.fromStr("encryptcrossservice");
Expand Down Expand Up @@ -71,18 +72,21 @@ export async function replaceKeyCert(replacing) {
const now = Date.now();
const u = "https://redir.nile.workers.dev/x/crt/" + now;
const url = new URL(u);
// TODO: bind "who" to msg?
const msg = bufutil.fromStr(url.pathname);
const authz = await hmacsign(mackey, msg);
const who = envutil.hostId(); // never empty on fly
const req = new Request(url, {
method: "GET",
headers: {
"x-rethinkdns-xsvc-authz": bufutil.hex(authz),
"x-rethinkdns-xsvc-who": who,
},
});
const r = await fetch(req);

if (!r.ok) {
log.e("certfile: fetch failed", authz.length, r.status, r.statusText);
log.e("certfile: fetch err", who, authz.length, r.status, r.statusText);
return nokeycert;
}

Expand Down Expand Up @@ -150,6 +154,7 @@ export async function replaceKeyCert(replacing) {
export async function decryptText(req, ivciphertaghex) {
const now = new Date();
const u = new URL(req.url);
const authn = req.headers.get("x-rethinkdns-xsvc-who");
const ivciphertag = bufutil.hex2buf(ivciphertaghex);
if (bufutil.emptyBuf(ivciphertag)) {
log.e("decrypt: ivciphertag empty");
Expand All @@ -162,6 +167,8 @@ export async function decryptText(req, ivciphertaghex) {
// crypto.junod.info/posts/recursive-hash/#data-serialization
// 1 Aug 2025 => "5/7/2025" => Friday, 7th month (0-indexed), 2025
const aadstr =
authn +
"/" +
now.getUTCDay() +
"/" +
now.getUTCMonth() +
Expand Down
101 changes: 101 additions & 0 deletions src/plugins/rethinkdns/pre.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/**
* @fileoverview Prefetcher for remote blocklists using built-in Node.js 20+ fetch API.
* @module prefetcher
*/

import * as envutil from "../../commons/envutil.js";
import * as util from "../../commons/util.js";

const BASE_URL = envutil.blocklistUrl();
const DIR = "bc";
const CODEC = "u6";
const FILE_BASIC_CONFIG = "basicconfig.json";
const FILE_TAG = "filetag.json";
const MAX_RETRIES = 5;

/**
* @typedef {Object} DateInfo
* @property {number} day
* @property {number} week
* @property {number} month
* @property {number} year
* @property {number} timestamp
*/

/**
* Get the current UTC timestamp in secs.
* @returns {number}
*/
function currentEpoch() {
return Math.floor(Date.now() / 1000);
}

/**
* Get date details from a timestamp.
* @param {number} timestamp
* @returns {DateInfo}
*/
function getDateInfo(timestamp) {
const date = new Date(timestamp * 1000);
const day = date.getUTCDate();
const week = Math.ceil(day / 7);
const month = date.getUTCMonth() + 1;
const year = date.getUTCFullYear();
return { day, week, month, year, timestamp };
}

/**
* Main function to prefetch files based on week, month, and year.
*/
async function prefetch(codec = CODEC) {
const now = currentEpoch();
const { week: wk, month: mm, year: yyyy } = getDateInfo(now);

for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
const configUrl = `${BASE_URL}/${yyyy}/${DIR}/${mm}-${wk}/${codec}/${FILE_BASIC_CONFIG}`;
log.i(`attempt ${attempt}: fetching ${configUrl} at ${now}`);

// {
// "version":1,
// "nodecount":81551789,
// "inspect":false,
// "debug":false,
// "selectsearch":true,
// "useCodec6":true,
// "optflags":true,
// "tdpartsmaxmb":0,
// "timestamp":"2025/1740866164283",
// "tdparts":-1,
// "tdmd5":"000ed9638e8e0f12e450050997e84365",
// "rdmd5":"75e5eebc71be02d8bef47b93ea58c213",
// "ftmd5":"8c56effb0f3d73232f7090416bb2e7c1",
// "ftlmd5":"54b323eb653451ba8940acb00d20382a"
// }
const bconfig = await fileFetch(configUrl, "json");

if (bconfig) {
const fullTimestamp = util.bareTimestampFrom(bconfig.timestamp);
if (fullTimestamp) {
const tagUrl = `${BASE_URL}/${fullTimestamp}/${codec}/${FILE_TAG}`;
log.d(`attempt ${attempt}: fetching ${configUrl} at ${now}`);
const ft = await fetchFile(tagUrl, "json");
if (ft) return [bconfig, ft];
else log.w(`failed to fetch ${tagUrl}`);
}
}

// decr week, month, year; try again
wk--;
if (wk <= 0) {
wk = 5;
mm--;
}
if (mm <= 0) {
mm = 12;
yyyy--;
}
}

log.e("no new filetag or basicconfig: exceeded max retries");
return [null, null];
}
Loading