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
1 change: 1 addition & 0 deletions mapsync-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"better-sqlite3": "12.8.0",
"kysely": "0.28.14",
"source-map-support": "0.5.21",
"uuid": "^14.0.0",
"ws": "8.20.0",
"zod": "3.25.76",
"zod-validation-error": "1.5.0"
Expand Down
9 changes: 9 additions & 0 deletions mapsync-server/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions mapsync-server/src/auth.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { isValidUuid } from "./deps/uuid.ts";

export abstract class AuthState {
protected constructor(public readonly logName: string | null) {}
}
Expand All @@ -20,6 +22,9 @@ export class Welcomed extends AuthState {
public readonly uuid: string,
public readonly authed: boolean,
) {
if (!isValidUuid(uuid)) {
throw new Error(`Invalid UUID: ${uuid}`);
}
super(name + (authed ? "" : "?"));
}
}
24 changes: 24 additions & 0 deletions mapsync-server/src/deps/uuid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import node_crypto from "crypto";
import { stringify as parseUuidBytes } from "uuid";
import { v5 as _uuidv5 } from "uuid";
export { validate as isValidUuid } from "uuid";

export const uuidv5 = _uuidv5;

// https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/UUID.html#nameUUIDFromBytes(byte[])
export function nameUuidFromBytes(bytes: Buffer): string {
const hash = node_crypto.createHash("md5").update(bytes).digest();
hash[6] &= 0x0f; // Clears the version
hash[6] |= 0x30; // Sets version to 3
hash[8] &= 0x3f; // Clears the variant
hash[8] |= 0x80; // Sets variant to IETF
return parseUuidBytes(hash);
}

export const UUID_NAMESPACE = nameUuidFromBytes(
Buffer.from("mapsync:server", "utf8"),
);

export function createOfflineUuid(name: string) {
return uuidv5(`Offline:${name}`, UUID_NAMESPACE);
}
18 changes: 18 additions & 0 deletions mapsync-server/src/deps/zod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export * from "zod";
export { fromZodError } from "zod-validation-error";

import * as z from "zod";
import { createOfflineUuid } from "./uuid.ts";

export function offlineUuid() {
return z.preprocess((val) => {
if (typeof val !== "string") {
return val;
}
const match = /^AUTH-DISABLED-(.+)/.exec(val) ?? null;
if (match === null) {
return val;
}
return createOfflineUuid(match[1]);
}, z.string().uuid());
}
3 changes: 2 additions & 1 deletion mapsync-server/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
Welcomed,
} from "./auth.ts";
import { SUPPORTED_VERSIONS } from "./constants.ts";
import { createOfflineUuid } from "./deps/uuid.ts";

let config: metadata.Config = null!;
let main: ProtocolHandler = null!;
Expand Down Expand Up @@ -150,7 +151,7 @@ export class ProtocolHandler {
}
client.auth = new Welcomed(
packet.claimedUsername,
`AUTH-DISABLED-${packet.claimedUsername}`,
createOfflineUuid(packet.claimedUsername),
false,
);
}
Expand Down
13 changes: 4 additions & 9 deletions mapsync-server/src/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import node_path from "node:path";
import { Mutex } from "async-mutex";
import * as errors from "./deps/errors.ts";
import * as json from "./deps/json.ts";
import * as z from "zod";
import { fromZodError } from "zod-validation-error";
import * as z from "./deps/zod.ts";

export const DATA_FOLDER = process.env["MAPSYNC_DATA_DIR"] ?? "./mapsync";
try {
Expand Down Expand Up @@ -49,7 +48,7 @@ function parseConfigFile<T>(
return parser(json.parse(fileContents));
} catch (e) {
if (e instanceof z.ZodError) {
throw "Could not parse " + file + ": " + fromZodError(e);
throw "Could not parse " + file + ": " + z.fromZodError(e);
}
throw e;
}
Expand Down Expand Up @@ -96,9 +95,7 @@ export function getConfig(): Config {

const WHITELIST_FILE = "whitelist.json";
const WHITELIST_MUTEX = new Mutex();
const WHITELIST_SCHEMA = z.array(
z.union([z.string().uuid(), z.string().regex(/^AUTH-DISABLED-.+/)]),
);
const WHITELIST_SCHEMA = z.array(z.offlineUuid());
export const whitelist = new Set<string>();

export async function loadWhitelist() {
Expand Down Expand Up @@ -130,9 +127,7 @@ export async function saveWhitelist() {

const UUID_CACHE_FILE = "uuid_cache.json";
const UUID_CACHE_MUTEX = new Mutex();
const UUID_CACHE_SCHEMA = z.record(
z.union([z.string().uuid(), z.string().regex(/^AUTH-DISABLED-.+/)]),
);
const UUID_CACHE_SCHEMA = z.record(z.offlineUuid());
// IGN UUID
const uuid_cache = new Map<string, string>();

Expand Down