feat: tunnel WireGuard vers le serveur familyd et mode propriétaire de l'appareil
- Firebase et le pare-feu local (trou noir, liste blanche par application, coupure cyclique locale) sont retirés - Client WireGuard officiel (GoBackend) : tout le trafic passe par le serveur familyd, qui filtre - Appairage par code ou lien familyd:// ; clé privée WireGuard et jeton chiffrés par l'Android Keystore - Remontées par le tunnel : état, temps d'écran, applications installées, évènements (file persistante) - Mode propriétaire (Device Owner) : VPN toujours actif avec blocage hors VPN, réglages verrouillés, garde-fou si le serveur ne répond plus pendant 15 min - Plan de la refonte : docs/PLAN-wireguard.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R9CBCVP5oDu2sfoYPisNCQ
This commit is contained in:
1 parent
f382eeb4fe
commit
33ea4ff947
40 files changed
+1680
-1635
No files matched your search
@@ -0,0 +1,56 @@
|
||||
package com.jttools.datacontrol.remote
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class FamilyLinkTest {
|
||||
|
||||
private val pairResponse = """
|
||||
{"device_id":"5b1f","token":"fd_secret","name":"Tél. Lilou","ready":true,
|
||||
"wireguard":{"address":"10.78.0.11/32","dns":"10.78.0.1","mtu":1280,
|
||||
"server_public_key":"JavjzwIltCzZB49zUDJCVrbUu9SGbxHH6gcfPB3Y81k=",
|
||||
"endpoint":"fam-vpn.tuxtech.fr:51721","allowed_ips":["0.0.0.0/0","::/0"],
|
||||
"persistent_keepalive":25},
|
||||
"api":"http://10.78.0.1:8100/"}
|
||||
""".trimIndent()
|
||||
|
||||
@Test fun `code seul, avec espaces ou tirets`() {
|
||||
assertEquals(PairingInput("https://family.tuxtech.fr", "ABCD2345"), PairingInput.parse("abcd 2345"))
|
||||
assertEquals("ABCD2345", PairingInput.parse("ABCD-2345")?.code)
|
||||
assertNull(PairingInput.parse("ABC"))
|
||||
assertNull(PairingInput.parse("ABCD234O")) // O et 0 exclus de l'alphabet
|
||||
}
|
||||
|
||||
@Test fun `lien familyd`() {
|
||||
val p = PairingInput.parse("familyd://pair?url=https%3A%2F%2Fautre.exemple.fr%2F&code=WXYZ2345")
|
||||
assertEquals(PairingInput("https://autre.exemple.fr", "WXYZ2345"), p)
|
||||
assertEquals("https://family.tuxtech.fr", PairingInput.parse("familyd://pair?url=https://family.tuxtech.fr&code=WXYZ2345")?.serverUrl)
|
||||
assertNull(PairingInput.parse("familyd://pair?url=http://non.chiffre.fr&code=WXYZ2345")) // HTTPS obligatoire
|
||||
assertNull(PairingInput.parse("familyd://pair?code=WXYZ2345"))
|
||||
}
|
||||
|
||||
@Test fun `reponse d appairage`() {
|
||||
val (link, token) = FamilyLink.fromPairResponse("https://family.tuxtech.fr", pairResponse)
|
||||
assertEquals("fd_secret", token)
|
||||
assertEquals("10.78.0.11", link.tunnelIp)
|
||||
assertEquals("http://10.78.0.1:8100", link.apiBase)
|
||||
assertEquals(listOf("0.0.0.0/0", "::/0"), link.allowedIps)
|
||||
}
|
||||
|
||||
@Test fun `configuration wg-quick`() {
|
||||
val (link, _) = FamilyLink.fromPairResponse("https://family.tuxtech.fr", pairResponse)
|
||||
val conf = link.wgQuickConfig("PRIVEE=")
|
||||
assertTrue(conf.startsWith("[Interface]\nPrivateKey = PRIVEE=\nAddress = 10.78.0.11/32\nDNS = 10.78.0.1\nMTU = 1280"))
|
||||
assertTrue("AllowedIPs = 0.0.0.0/0, ::/0" in conf && "Endpoint = fam-vpn.tuxtech.fr:51721" in conf)
|
||||
assertTrue("PersistentKeepalive = 25" in conf)
|
||||
}
|
||||
|
||||
@Test fun `sauvegarde et relecture`() {
|
||||
val (link, _) = FamilyLink.fromPairResponse("https://family.tuxtech.fr", pairResponse)
|
||||
assertEquals(link, FamilyLink.fromJson(link.toJson()))
|
||||
assertNull(FamilyLink.fromJson("{pas du json"))
|
||||
assertNull(FamilyLink.fromJson(null))
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package com.jttools.datacontrol.remote
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Test
|
||||
import java.util.Base64
|
||||
|
||||
class FirebaseConfigTest {
|
||||
private val expected = FirebaseConfig("AIzaTest", "1:123:android:abc", "mon-projet")
|
||||
|
||||
@Test fun `bloc firebaseConfig de la console`() {
|
||||
val js = """
|
||||
const firebaseConfig = {
|
||||
apiKey: "AIzaTest",
|
||||
authDomain: "mon-projet.firebaseapp.com",
|
||||
projectId: "mon-projet",
|
||||
appId: "1:123:android:abc"
|
||||
};
|
||||
""".trimIndent()
|
||||
assertEquals(expected, FirebaseConfig.parse(js))
|
||||
}
|
||||
|
||||
@Test fun `json`() {
|
||||
assertEquals(
|
||||
expected,
|
||||
FirebaseConfig.parse("""{"apiKey":"AIzaTest","appId":"1:123:android:abc","projectId":"mon-projet"}""")
|
||||
)
|
||||
}
|
||||
|
||||
@Test fun `chaine fc1 de FamilyControl`() {
|
||||
val b64 = Base64.getEncoder().encodeToString(
|
||||
"""{"apiKey":"AIzaTest","appId":"1:123:android:abc","projectId":"mon-projet"}""".toByteArray()
|
||||
)
|
||||
assertEquals(expected, FirebaseConfig.parse("fc1:$b64"))
|
||||
assertEquals(expected, FirebaseConfig.parse(" fc1:${b64.chunked(20).joinToString("\n")} "))
|
||||
}
|
||||
|
||||
@Test fun `guillemets typographiques`() {
|
||||
val js = "apiKey: “AIzaTest”, projectId: «mon-projet», appId: ‘1:123:android:abc’"
|
||||
assertEquals(expected, FirebaseConfig.parse(js))
|
||||
}
|
||||
|
||||
@Test fun `fichier google-services json`() {
|
||||
val gs = """
|
||||
{
|
||||
"project_info": { "project_number": "123", "project_id": "mon-projet", "storage_bucket": "mon-projet.appspot.com" },
|
||||
"client": [ {
|
||||
"client_info": { "mobilesdk_app_id": "1:123:android:abc",
|
||||
"android_client_info": { "package_name": "com.jttools.datacontrol" } },
|
||||
"api_key": [ { "current_key": "AIzaTest" } ]
|
||||
} ]
|
||||
}
|
||||
""".trimIndent()
|
||||
assertEquals(expected, FirebaseConfig.parse(gs))
|
||||
}
|
||||
|
||||
@Test fun `champ manquant ou illisible`() {
|
||||
assertNull(FirebaseConfig.parse("""{"apiKey":"AIzaTest","projectId":"mon-projet"}"""))
|
||||
assertNull(FirebaseConfig.parse("fc1:!!!"))
|
||||
assertNull(FirebaseConfig.parse(""))
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user