POST /admin/enroll-tokens now returns the whole link, not just the token: echolot://enroll?v=1&u=<control URL>&p=pin-sha256:<b64>&t=<token> The server is the only party that knows all three parts at once, and the part an operator gets wrong by hand is the base64 pin — which does not fail loudly, it just never matches, surfacing days later as an inscrutable TLS error. The app takes the link from a paste or from an echolot:// deep link (QR scan), and writes URL, pin and credential together or not at all. One trap the tests pin: an unencoded "+" in a query string decodes to a space, so a hand-assembled link arrives with a pin wrong by one character. Base64 has no spaces, so they are restored — unambiguous, and it cannot damage a correctly encoded pin. Also fixes a spec divergence: §2.1 names the field device_credential and the first implementation shipped "credential". Both are sent now and the client prefers the spec's; the alias goes once nothing reads it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
31 lines
1.1 KiB
Kotlin
31 lines
1.1 KiB
Kotlin
// SPDX-FileCopyrightText: 2026 Echolot contributors
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
plugins {
|
|
alias(libs.plugins.kotlin.jvm)
|
|
alias(libs.plugins.kotlin.serialization)
|
|
}
|
|
|
|
// The measurement run engine: composes core-protocol probes into
|
|
// core-measurement documents. Pure Kotlin/JVM, so it is unit-testable and can
|
|
// run a full server-facing measurement against a live server.
|
|
dependencies {
|
|
implementation(project(":core-protocol"))
|
|
implementation(project(":core-measurement"))
|
|
implementation(project(":core-privacy"))
|
|
implementation(libs.kotlinx.serialization.json)
|
|
testImplementation(kotlin("test"))
|
|
}
|
|
|
|
kotlin {
|
|
jvmToolchain(21)
|
|
compilerOptions { jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17) }
|
|
}
|
|
java { sourceCompatibility = JavaVersion.VERSION_17; targetCompatibility = JavaVersion.VERSION_17 }
|
|
|
|
tasks.test {
|
|
useJUnitPlatform()
|
|
listOf("ECHOLOT_LIVE_URL","ECHOLOT_LIVE_PIN","ECHOLOT_LIVE_CRED","ECHOLOT_LIVE_UDP","ECHOLOT_LIVE_TARGET","ECHOLOT_ENROLL_URI")
|
|
.forEach { k -> System.getenv(k)?.let { environment(k, it) } }
|
|
}
|