From a549077c1347eedf4c59c9c33fd673fbc7e07c68 Mon Sep 17 00:00:00 2001 From: Seb3thehacker Date: Thu, 8 Oct 2026 15:25:04 -0700 Subject: [PATCH] certificate: say where it comes from, offer import alongside download, keep cert files out of the repo --- .gitignore | 9 +++++- README.md | 11 +++++++ .../gearslip/ui/CertSetupScreen.kt | 30 ++++++++++--------- .../gearslip/ui/SettingsScreen.kt | 7 +++-- 4 files changed, 39 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index 1705c65..00a51a8 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,11 @@ CLAUDE.md # Other archive/ .wrangler/ -stats-worker/ \ No newline at end of file +stats-worker/ + +# Certificates and keys never go in the repo; the app downloads or imports them on the phone. +*.p12 +*.pfx +*.pem +*.crt +*.key diff --git a/README.md b/README.md index b496660..08dc2e5 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,17 @@ keystore. Without them, the debug build still works. [docs/BUILDING_APPS.md](docs/BUILDING_APPS.md) specifies how to write apps that Gearslip can render: templated apps, media apps, and the Gearslip app protocol. +## How Gearslip talks to cars + +Gearslip is an independent program, written to work with car head units. What it knows of +the protocol comes from public open-source projects such as +[aasdk](https://github.com/opencardev/aasdk) and open-android-auto, and it contains none +of Google's Android Auto code. + +Gearslip ships without a certificate. On first launch you choose where yours comes from: +download the one the aasdk project publishes, or import a file of your own. The +certificate stays on your phone. Gearslip never uploads, backs up, or logs it. + ## Trademarks Android, Android Auto, Google Messages, and Waze are trademarks of Google LLC. Spotify is diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/ui/CertSetupScreen.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/ui/CertSetupScreen.kt index 870d7b6..37a2ad2 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/ui/CertSetupScreen.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/ui/CertSetupScreen.kt @@ -60,7 +60,6 @@ fun CertSetupScreen(onDone: () -> Unit) { val scope = rememberCoroutineScope() var downloadState by remember { mutableStateOf(DownloadState.Idle) } - var showImport by remember { mutableStateOf(false) } var pendingUri by remember { mutableStateOf(null) } var manualProgress by remember { mutableStateOf(false) } @@ -91,7 +90,7 @@ fun CertSetupScreen(onDone: () -> Unit) { if (installed) { "Cars accept only Google-issued certificates, and you have one loaded." } else { - "Cars accept only Google-issued certificates. Download one to connect." + "Cars accept only Google-issued certificates. Gearslip doesn't include one, so choose where yours comes from." }, style = MaterialTheme.typography.bodyLarge, textAlign = TextAlign.Center, @@ -131,10 +130,11 @@ fun CertSetupScreen(onDone: () -> Unit) { }, modifier = Modifier.fillMaxWidth().height(56.dp), ) { - Text("Download certificate") + Text("Download from aasdk") } Text( - "Works with most cars built before 2020. Newer cars reject it.", + "The open-source aasdk project publishes this certificate at github.com/opencardev/aasdk. " + + "Most cars accept it; some from around 2020 on don't.", style = MaterialTheme.typography.bodySmall, textAlign = TextAlign.Center, color = MaterialTheme.colorScheme.onSurfaceVariant, @@ -177,16 +177,18 @@ fun CertSetupScreen(onDone: () -> Unit) { Spacer(Modifier.height(16.dp)) - if (showImport) { - OutlinedButton( - onClick = { importLauncher.launch(arrayOf("*/*")) }, - modifier = Modifier.fillMaxWidth().height(52.dp), - ) { Text("Import your own .p12 cert") } - Spacer(Modifier.height(16.dp)) - } else { - TextButton(onClick = { showImport = true }) { Text("Import your own certificate instead") } - Spacer(Modifier.height(8.dp)) - } + OutlinedButton( + onClick = { importLauncher.launch(arrayOf("*/*")) }, + modifier = Modifier.fillMaxWidth().height(52.dp), + ) { Text("Import my own file") } + Text( + "A .p12 file with its private key, from wherever you choose.", + style = MaterialTheme.typography.bodySmall, + textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(top = 8.dp), + ) + Spacer(Modifier.height(16.dp)) OutlinedButton( onClick = { diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/ui/SettingsScreen.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/ui/SettingsScreen.kt index f6bba10..815bf9d 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/ui/SettingsScreen.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/ui/SettingsScreen.kt @@ -208,7 +208,7 @@ private fun CertificateSection() { } SettingsDivider() SettingsRow( - if (downloading) "Downloading…" else "Download certificate", + if (downloading) "Downloading…" else "Download from aasdk", Modifier.clickable(enabled = !downloading) { downloading = true scope.launch { @@ -222,13 +222,14 @@ private fun CertificateSection() { } } }, + subtitle = "The certificate the open-source aasdk project publishes on GitHub. Gearslip doesn't include one", icon = Icons.Filled.Refresh, ) SettingsDivider() SettingsRow( - "Import a certificate", + "Import my own file", Modifier.clickable { picker.launch(arrayOf("*/*")) }, - subtitle = "A .p12 file with its private key", + subtitle = "A .p12 file with its private key, from wherever you choose", icon = Icons.Filled.Add, ) val removable = when (s?.kind) {