Files
Password-Manager/AndroidManifest.template.xml
T
r-zakarya 68df2dd7e7 feat(android): read the snapshot from a Gitea repo, and close cleartext
PMA.SyncClient now speaks two transports, told apart by the URL:
/api/v1/repos/ means the Gitea contents API, anything else the old PHP
endpoint. The PHP path stays until the Windows side publishes to the repo
too - without it the migration would need both ends flipped at once, with
no way back.

Three things differ on the Gitea side and nothing else: the header is
"token <PAT>" not "Bearer" (swapping them gives a silent 401), the body is
JSON carrying base64 content, and the fingerprint comparison happens in the
client since the API has no If-None-Match. The body is re-downloaded, which
is cheap; the four-second key derivation is still avoided. The result's
ETag field carries the sha, so the caller cannot tell which transport
answered.

usesCleartextTraffic is replaced by a network config that permits cleartext
to 127.0.0.1 and localhost BY NAME and forbids it everywhere else. The
attribute drew no such line: a mistyped URL sent the bearer token over the
network in the clear with nothing to signal it. Now it fails immediately,
which is the behaviour worth having.

Verified in the built APK: res/xml/network_security_config.xml is present
and the manifest attribute resolves to a real resource id. NOT verified
against a real repo - that needs a private repo, a published
vault-sync.json and a token, none of which exist yet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 11:55:24 +01:00

101 lines
5.0 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="%package%"
android:versionCode="%versionCode%"
android:versionName="%versionName%"
android:installLocation="%installLocation%">
<uses-sdk android:minSdkVersion="%minSdkVersion%" android:targetSdkVersion="%targetSdkVersion%" />
<%uses-permission%>
<!-- Absente de la liste par defaut de Delphi, et sans elle BiometricPrompt
leve java.lang.SecurityException a la premiere invite - pas au
demarrage, donc le defaut ne se voit qu'en essayant d'ouvrir le coffre.
USE_FINGERPRINT couvre les versions anterieures a Android 9, ou
BiometricPrompt n'existe pas encore. -->
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>
<queries>
<%queries-child-elements%>
</queries>
<!-- networkSecurityConfig REMPLACE usesCleartextTraffic="true", qui
autorisait le clair vers n'importe quel hote pour la seule raison que
l'essai local via "adb reverse" parle HTTP. La configuration ne
l'autorise plus que vers la boucle locale, nommement : le jeton ne
peut plus sortir qu'en TLS, et une URL http:// vers un vrai hote
echoue bruyamment au lieu de le laisser passer en clair.
Voir android-client/android-res/xml/network_security_config.xml. -->
<!-- allowBackup=false : le repertoire prive contient vault.bin, c'est-a-dire
le coffre entier. Il est chiffre par une cle qui ne quitte pas la puce,
donc ce qui sortirait serait inexploitable - mais il sortirait, et une
sauvegarde cloud n'a rien a faire dans le chemin d'un gestionnaire de
mots de passe. fullBackupContent et dataExtractionRules ne sont pas
necessaires une fois la sauvegarde refusee en bloc. -->
<application
android:allowBackup="false"
android:networkSecurityConfig="@xml/network_security_config"
android:persistent="%persistent%"
android:restoreAnyVersion="%restoreAnyVersion%"
android:label="%label%"
android:debuggable="%debuggable%"
android:largeHeap="%largeHeap%"
android:icon="%icon%"
android:theme="%theme%"
android:hardwareAccelerated="%hardwareAccelerated%"
android:resizeableActivity="true"
android:requestLegacyExternalStorage="true">
<%provider%>
<%application-meta-data%>
<%uses-libraries%>
<!-- Trigger Google Play services to install the backported photo picker module. -->
<service
android:name="com.google.android.gms.metadata.ModuleDependencies"
android:enabled="false"
android:exported="false"
tools:ignore="MissingClass">
<intent-filter>
<action android:name="com.google.android.gms.metadata.MODULE_DEPENDENCIES" />
</intent-filter>
<meta-data android:name="photopicker_activity:0:required" android:value="" />
</service>
<%services%>
<!-- Our activity is a subclass of the built-in NativeActivity framework class.
This will take care of integrating with our NDK code. -->
<activity
android:name="com.embarcadero.firemonkey.FMXNativeActivity"
android:exported="true"
android:label="%activityLabel%"
android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout|uiMode"
android:launchMode="singleTask">
<!-- Tell NativeActivity the name of our .so -->
<meta-data android:name="android.app.lib_name" android:value="%libNameValue%" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- FMX n'affiche pas BiometricPrompt depuis notre NativeActivity : il
lance SA PROPRE activite, qui heberge le fragment androidx. Elle
vit dans fmx.dex.jar, mais Android exige qu'elle soit declaree ici
- sinon android.content.ActivityNotFoundException a la premiere
invite, et nulle part avant.
Theme translucide du framework : cette activite ne dessine rien
d'elle-meme, elle ne fait qu'heberger le dialogue systeme. Sans
cela elle recouvrirait l'ecran d'une surface opaque le temps de
l'authentification. On prend un theme @android: et non AppCompat,
absent des ressources generees. -->
<activity
android:name="com.embarcadero.firemonkey.biometricauth.BiometricFragmentActivity"
android:exported="false"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
<%activity%>
<%receivers%>
</application>
</manifest>
<!-- END_INCLUDE(manifest) -->