Hexdump CDN hashes

This commit is contained in:
Rory&
2026-04-21 21:11:02 +02:00
parent 5cb017ba1c
commit 7905fc9f5f
4 changed files with 145 additions and 0 deletions
+53
View File
@@ -19,6 +19,9 @@
import { Config } from "@spacebar/util";
import { createHmac, timingSafeEqual } from "node:crypto";
import ms, { StringValue } from "ms";
import { TextDecoder } from "node:util";
import { ConsoleUtils } from "./util/ConsoleUtils";
import { ColorUtils } from "./util/ColorUtils";
export class NewUrlUserSignatureData {
ip?: string;
@@ -132,11 +135,14 @@ export const getUrlSignature = (data: NewUrlSignatureData): UrlSignResult => {
function calculateHash(request: UrlSignatureData): UrlSignResult {
const { cdnSignatureKey } = Config.get().security;
const newData = createHmac("sha256", cdnSignatureKey as string);
const data = createHmac("sha256", cdnSignatureKey as string)
.update(request.path!)
.update(request.issuedAt)
.update(request.expiresAt);
let ipData = new Int8Array();
if (Config.get().security.cdnSignatureIncludeIp) {
if (!request.ip)
console.log(
@@ -145,9 +151,11 @@ function calculateHash(request: UrlSignatureData): UrlSignResult {
else {
if (process.env["LOG_CDN_SIGNATURES"]) console.log("[Signing] CDN Signature IP is enabled, adding IP to hash:", request.ip);
data.update(request.ip!);
ipData = new Int8Array(new TextEncoder().encode(request.ip!));
}
}
let userAgentData = new Int8Array();
if (Config.get().security.cdnSignatureIncludeUserAgent) {
if (!request.userAgent)
console.log(
@@ -156,10 +164,29 @@ function calculateHash(request: UrlSignatureData): UrlSignResult {
else {
if (process.env["LOG_CDN_SIGNATURES"]) console.log("[Signing] CDN Signature User-Agent is enabled, adding User-Agent to hash:", request.userAgent);
data.update(request.userAgent!);
userAgentData = new Int8Array(new TextEncoder().encode(request.userAgent!));
}
}
const rawData = new Int8Array([
...new TextEncoder().encode(request.path!),
...new TextEncoder().encode(request.issuedAt),
...new TextEncoder().encode(request.expiresAt),
...ipData,
...userAgentData,
]);
if (process.env["LOG_CDN_SIGNATURES"]) {
console.log("[Signing] Signature data for ", request.path!);
hexdump(rawData);
}
newData.update(rawData);
const hash = data.digest("hex");
const newHash = newData.digest("hex");
if (process.env["LOG_CDN_SIGNATURES"]) {
console.log(hash);
console.log(newHash);
}
const result = new UrlSignResult({
path: request.path,
issuedAt: request.issuedAt,
@@ -257,3 +284,29 @@ export const hasValidSignature = (req: NewUrlUserSignatureData, sig: UrlSignResu
return isHashValid;
};
// port of https://github.com/TheArcaneBrony/ArcaneLibs/blob/master/ArcaneLibs/Extensions/DictionaryExtensions.cs#L80
function hexdump(arr: Int8Array, width: number = 32, colorize: boolean = true) {
const colorizeFunc = colorize ? (val: number, str: string) => ConsoleUtils.ColoredString(str, ColorUtils.cnv8To24(val)) : (val: number, str: string) => str;
for (let i = 0; i < arr.length; i += width) {
const end = Math.min(i + width, arr.length);
const section = arr.slice(i, end);
console.log(
Array.from(section)
.map((x) => colorizeFunc(x, x.toString(16).toUpperCase()))
.join(" ")
.padEnd(3 * section.length),
"|",
new TextDecoder("utf-8")
.decode(section)
.replaceAll("\n", ".")
.replaceAll("\r", ".")
.replaceAll("\0", ".")
.replaceAll("\t", ".")
.replaceAll("\v", ".")
.replaceAll("\b", ".")
.replaceAll("\x07", ".") // \a
.replaceAll("\f", "."),
);
}
}
+42
View File
@@ -0,0 +1,42 @@
/*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2023 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
export class RgbValue {
r: number;
g: number;
b: number;
constructor(r: number, g: number, b: number) {
this.r = r;
this.g = g;
this.b = b;
}
public asHex(withSigil: boolean = true) {
return `${withSigil ? "#" : ""}${this.r.toString(16).toUpperCase()}${this.g.toString(16).toUpperCase()}${this.b.toString(16).toUpperCase()}`;
}
public asAnsiEscapeSequence() {
return `\x1b[38;2;${this.r};${this.g};${this.b}m`;
}
}
export class ColorUtils {
public static cnv8To24(val: number): RgbValue {
return new RgbValue((val >> 5) * 32, ((val & 28) >> 2) * 32, (val & 3) * 64);
}
}
+32
View File
@@ -0,0 +1,32 @@
/*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2026 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// Minor port of https://github.com/TheArcaneBrony/ArcaneLibs/blob/master/ArcaneLibs/ConsoleUtils.cs
import { RgbValue } from "./ColorUtils";
export class ConsoleUtils {
public static ColorSequence(rgb: RgbValue) {
return rgb.asAnsiEscapeSequence();
}
public static SetConsoleColor(rgb: RgbValue) {
console.log(rgb.asAnsiEscapeSequence());
}
public static ColoredString(text: string, rgb: RgbValue) {
return rgb.asAnsiEscapeSequence() + text + "\x1b[0m";
}
}
+18
View File
@@ -1,3 +1,21 @@
/*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2023 Spacebar and Spacebar Contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { KittyLogo } from ".";
import { blueBright } from "picocolors";