A small helpdesk system: an office Pixel running a patched GrapheneOS Dialer answers technician calls, records both call legs as separate channels, and a Ruby backend transcribes them through Whisper and files an AI summary against the caller. Squashed to a single commit for sharing. No credentials are included; secrets live outside the repo in /etc/helpdesk/env on the server or a gitignored .claude/env.local locally. See .claude/env.local.example for the shape. Start at README.md, then docs/architecture.md.
41 lines
2.3 KiB
Java
41 lines
2.3 KiB
Java
package com.android.dialer.helpdesk.http;
|
|
|
|
import java.util.Map;
|
|
|
|
/** Standalone off-device test for {@link DeviceAuthSigner} (plain JDK, no Android, no JUnit). */
|
|
public class DeviceAuthSignerTest {
|
|
static int pass = 0, fail = 0;
|
|
static void ok(String d) { pass++; System.out.println(" ok " + d); }
|
|
static void bad(String d, Object got) { fail++; System.out.println(" FAIL " + d + " (got: " + got + ")"); }
|
|
static void eq(Object a, Object b, String d) { if (a == null ? b == null : a.equals(b)) ok(d); else bad(d, a); }
|
|
static void truthy(boolean x, String d) { if (x) ok(d); else bad(d, x); }
|
|
|
|
public static void main(String[] args) {
|
|
DeviceAuthSigner s = new DeviceAuthSigner("dev-device-token", "dev-device-secret");
|
|
String body = "{\"call_id\":\"c1\"}";
|
|
long ts = 1751932800L;
|
|
String nonce = "n0nce123";
|
|
Map<String, String> h = s.headers(body, ts, nonce);
|
|
|
|
eq(h.get("Authorization"), "Bearer dev-device-token", "Authorization: Bearer <token>");
|
|
eq(h.get("X-Request-Ts"), "1751932800", "X-Request-Ts is unix seconds");
|
|
eq(h.get("X-Request-Nonce"), "n0nce123", "X-Request-Nonce echoed");
|
|
String sig = h.get("X-Signature");
|
|
truthy(sig != null && sig.matches("[0-9a-f]{64}"), "X-Signature is 64 lowercase hex");
|
|
truthy(s.headers((String) null, ts, nonce).get("X-Signature") != null, "null body signs as empty (server sees \"\")");
|
|
truthy(!s.newNonce().equals(s.newNonce()), "newNonce() is random");
|
|
truthy(s.newNonce().matches("[0-9a-f]{32}"), "newNonce() is 128-bit hex");
|
|
// String and byte[] overloads agree for an ASCII body
|
|
String sigBytes = s.headers(body.getBytes(java.nio.charset.StandardCharsets.UTF_8), ts, nonce).get("X-Signature");
|
|
eq(sigBytes, sig, "byte[] overload == String overload for ASCII body");
|
|
|
|
// UTF-8 Czech body via the byte[] path (ě = ě) — emitted for the harness's Ruby cross-check
|
|
String cz = "{\"notes\":\"Děkujeme\"}";
|
|
String sigCz = s.headers(cz.getBytes(java.nio.charset.StandardCharsets.UTF_8), ts, nonce).get("X-Signature");
|
|
|
|
System.out.println("SIG=" + sig); // ASCII body cross-check
|
|
System.out.println("SIG_CZ=" + sigCz); // UTF-8 body cross-check
|
|
System.out.println("\n" + pass + " passed, " + fail + " failed");
|
|
System.exit(fail == 0 ? 0 : 1);
|
|
}
|
|
}
|