Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • develop
  • feat/force-migration-check
  • feat/improve-network-scan
  • feature/android_api_19
  • feature/cordova-android-13
  • feature/encrypted_comment
  • feature/migrate-cordova-13
  • gitlab_migration_1
  • master
  • rml8
  • 0.0.1.ES.alpha1
  • 0.0.2
  • 0.1.13
  • 0.1.14
  • 0.1.15
  • 0.1.16
  • 0.1.17
  • 0.1.18
  • 0.1.19
  • 0.1.20
  • 0.1.21
  • 0.1.22
  • 0.1.23
  • 0.1.24
  • 0.1.25
  • 0.1.26
  • 0.1.27
  • 0.1.28
  • 0.1.4
  • 0.1.7
  • 0.1.8
  • 0.2.0
  • 0.2.1
  • v0.10.0
  • v0.10.1
  • v0.10.2
  • v0.11.0
  • v0.11.1
  • v0.11.2
  • v0.11.3
  • v0.11.4
  • v0.11.5
  • v0.11.6
  • v0.11.7
  • v0.11.8
  • v0.12.0
  • v0.12.1
  • v0.12.2
  • v0.12.3
  • v0.12.4
  • v0.12.5
  • v0.12.6
  • v0.12.7
  • v0.12.8
  • v0.12.9
  • v0.13.0
  • v0.14.0
  • v0.14.1
  • v0.15.0
  • v0.15.1
  • v0.15.2
  • v0.15.3
  • v0.15.4
  • v0.15.5
  • v0.15.6
  • v0.15.7
  • v0.16.0
  • v0.16.1
  • v0.17.0
  • v0.17.1
  • v0.17.2
  • v0.17.3
  • v0.17.4
  • v0.17.5
  • v0.17.6
  • v0.18.0
  • v0.18.1
  • v0.18.2
  • v0.18.3
  • v0.19.0
  • v0.19.1
  • v0.19.2
  • v0.19.3
  • v0.19.4
  • v0.19.5
  • v0.19.6
  • v0.2.10
  • v0.2.12
  • v0.2.13
  • v0.2.14
  • v0.2.3
  • v0.2.4
  • v0.2.5
  • v0.2.6
  • v0.2.7
  • v0.2.8
  • v0.2.9
  • v0.3.0
  • v0.3.1
  • v0.3.10
  • v0.3.11
  • v0.3.12
  • v0.3.13
  • v0.3.14
  • v0.3.15
  • v0.3.16
  • v0.3.17
  • v0.3.2
  • v0.3.3
  • v0.3.4
110 results

Target

Select target project
No results found
Select Git revision
  • develop
  • feat/force-migration-check
  • feat/improve-network-scan
  • feature/android_api_19
  • feature/encrypted_comment
  • feature/migrate-cordova-13
  • gitlab_migration_1
  • master
  • patch-1
  • rml8
  • 0.0.1.ES.alpha1
  • 0.0.2
  • 0.1.13
  • 0.1.14
  • 0.1.15
  • 0.1.16
  • 0.1.17
  • 0.1.18
  • 0.1.19
  • 0.1.20
  • 0.1.21
  • 0.1.22
  • 0.1.23
  • 0.1.24
  • 0.1.25
  • 0.1.26
  • 0.1.27
  • 0.1.28
  • 0.1.4
  • 0.1.7
  • 0.1.8
  • 0.2.0
  • 0.2.1
  • v0.10.0
  • v0.10.1
  • v0.10.2
  • v0.11.0
  • v0.11.1
  • v0.11.2
  • v0.11.3
  • v0.11.4
  • v0.11.5
  • v0.11.6
  • v0.11.7
  • v0.11.8
  • v0.12.0
  • v0.12.1
  • v0.12.2
  • v0.12.3
  • v0.12.4
  • v0.12.5
  • v0.12.6
  • v0.12.7
  • v0.12.8
  • v0.12.9
  • v0.13.0
  • v0.14.0
  • v0.14.1
  • v0.15.0
  • v0.15.1
  • v0.15.2
  • v0.15.3
  • v0.15.4
  • v0.15.5
  • v0.15.6
  • v0.15.7
  • v0.16.0
  • v0.16.1
  • v0.17.0
  • v0.17.1
  • v0.17.2
  • v0.17.3
  • v0.17.4
  • v0.17.5
  • v0.17.6
  • v0.18.0
  • v0.18.1
  • v0.18.2
  • v0.18.3
  • v0.19.0
  • v0.19.1
  • v0.19.2
  • v0.19.3
  • v0.19.4
  • v0.19.5
  • v0.19.6
  • v0.2.10
  • v0.2.12
  • v0.2.13
  • v0.2.14
  • v0.2.3
  • v0.2.4
  • v0.2.5
  • v0.2.6
  • v0.2.7
  • v0.2.8
  • v0.2.9
  • v0.3.0
  • v0.3.1
  • v0.3.10
  • v0.3.11
  • v0.3.12
  • v0.3.13
  • v0.3.14
  • v0.3.15
  • v0.3.16
  • v0.3.17
  • v0.3.2
  • v0.3.3
  • v0.3.4
110 results
Show changes

Commits on Source 32

46 files
+ 2544
1704
Compare changes
  • Side-by-side
  • Inline

Files

+12 −0
Original line number Diff line number Diff line
@@ -76,6 +76,18 @@
      {
        "host": "g1.le-sou.org",
        "port": 443
      },
      {
        "host": "duniter.pini.fr",
        "port": 443
      },
      {
        "host": "g1.moul.re",
        "port": 443
      },
      {
        "host": "duniter-v1.comunes.net",
        "port": 443
      }
    ],
    "developers": [
+23 −13
Original line number Diff line number Diff line
<?xml version='1.0' encoding='utf-8'?>
<widget android-versionCode="107130" id="fr.duniter.cesium" ios-CFBundleIdentifier="org.duniter.cesium" version="1.7.13" xmlns="http://www.w3.org/ns/widgets" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:cdv="http://cordova.apache.org/ns/1.0">
<widget android-versionCode="107160" id="fr.duniter.cesium" ios-CFBundleIdentifier="org.duniter.cesium" version="1.7.16" xmlns="http://www.w3.org/ns/widgets" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:cdv="http://cordova.apache.org/ns/1.0">
    <name>Cesium</name>
    <description>
    An simple App for Duniter wallet
      Cesium Wallet for Ğ1 libre currency
    </description>
    <author email="contact@e-is.pro">
      E-IS PRO
@@ -27,7 +27,7 @@
    <preference name="UIWebViewBounce" value="false" />
    <preference name="DisallowOverscroll" value="true" />
    <preference name="SplashScreen" value="screen" />
    <preference name="SplashScreenDelay" value="4000" />
    <preference name="SplashScreenDelay" value="2500" />
    <preference name="KeyboardDisplayRequiresUserAction" value="false" />
    <preference name="KeyboardResizeMode" value="ionic" />
    <preference name="xwalkVersion" value="19" />
@@ -54,8 +54,13 @@
        <preference name="AndroidLaunchMode" value="singleTask" />
        <preference name="AndroidInsecureFileModeEnabled" value="true" />
        <preference name="android-minSdkVersion" value="22" />
        <preference name="android-targetSdkVersion" value="33" />
        <preference name="android-compileSdkVersion" value="33" />
        <preference name="android-targetSdkVersion" value="35" />
        <preference name="android-compileSdkVersion" value="35" />
        <preference name="AndroidJavaSourceCompatibility" value="8" />
        <preference name="AndroidTargetSourceCompatibility" value="8" />
        <preference name="GradlePluginKotlinEnabled" value="true" />
        <preference name="GradleVersion" value="8.7" />
        <preference name="AndroidKotlinJVMTarget" value="8" />
        <preference name="AndroidPersistentFileLocation" value="Compatibility" />
        <icon density="ldpi" src="resources/android/icon/drawable-ldpi-icon.png" />
        <icon density="mdpi" src="resources/android/icon/drawable-mdpi-icon.png" />
@@ -63,6 +68,8 @@
        <icon density="xhdpi" src="resources/android/icon/drawable-xhdpi-icon.png" />
        <icon density="xxhdpi" src="resources/android/icon/drawable-xxhdpi-icon.png" />
        <icon density="xxxhdpi" src="resources/android/icon/drawable-xxxhdpi-icon.png" />
        <preference name="AndroidWindowSplashScreenAnimatedIcon" value="resources/android/splash/splashscreen.xml" />
        <preference name="AndroidWindowSplashScreenBackground" value="#1A237E" />
        <splash density="land-ldpi" src="resources/android/splash/drawable-land-ldpi-screen.png" />
        <splash density="land-mdpi" src="resources/android/splash/drawable-land-mdpi-screen.png" />
        <splash density="land-hdpi" src="resources/android/splash/drawable-land-hdpi-screen.png" />
@@ -75,6 +82,9 @@
        <splash density="port-xhdpi" src="resources/android/splash/drawable-port-xhdpi-screen.png" />
        <splash density="port-xxhdpi" src="resources/android/splash/drawable-port-xxhdpi-screen.png" />
        <splash density="port-xxxhdpi" src="resources/android/splash/drawable-port-xxxhdpi-screen.png" />
        <edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application">
            <application android:networkSecurityConfig="@xml/network_security_config" />
        </edit-config>
    </platform>
    <platform name="ios">
        <preference name="BackupWebStorage" value="local" />
@@ -134,21 +144,21 @@
        <variable name="PHOTOLIBRARY_USAGE_DESCRIPTION" value="Take a picture for the user profile" />
        <variable name="ANDROID_SUPPORT_V4_VERSION" value="28.+" />
    </plugin>
    <plugin name="cordova-plugin-ionic-webview" spec="^4.2.1">
    <plugin name="cordova-plugin-ionic-webview" spec="^5.0.1">
        <variable name="ANDROID_SUPPORT_ANNOTATIONS_VERSION" value="28.+" />
    </plugin>
    <plugin name="cordova-plugin-device" spec="^2.1.0" />
    <plugin name="cordova-plugin-device" spec="^3.0.0" />
    <plugin name="cordova-plugin-dialogs" spec="^2.0.2" />
    <plugin name="cordova-clipboard" spec="^1.3.0" />
    <plugin name="cordova-plugin-splashscreen" spec="^6.0.2" />
    <plugin name="cordova-plugin-statusbar" spec="^3.0.0" />
    <plugin name="cordova-plugin-file" spec="^6.0.2" />
    <plugin name="cordova-plugin-statusbar" spec="^4.0.0" />
    <plugin name="cordova-plugin-file" spec="^8.1.3" />
    <plugin name="cordova-plugin-vibration" spec="^3.1.1" />
    <plugin name="cordova-plugin-websocket" spec="^0.12.2" />
    <plugin name="cordova-plugin-ionic-keyboard" spec="^2.2.0" />
    <plugin name="cordova-plugin-androidx-adapter" spec="^1.1.3" />
    <plugin name="cordova-plugin-x-toast" spec="^2.7.3" />
    <plugin name="phonegap-plugin-barcodescanner" spec="^8.1.0">
    <plugin name="@red-mobile/cordova-plugin-barcodescanner" spec="^9.1.0">
        <variable name="CAMERA_USAGE_DESCRIPTION" value="To scan QRCode" />
        <variable name="ANDROID_SUPPORT_V4_VERSION" value="28.+" />
    </plugin>
+1 −1
Original line number Diff line number Diff line
Subproject commit 4b5e3aef13e93c507fbf24c8aef832ada65f64ef
Subproject commit 7f899bf2139dd7238840019d4365377341171f6d
Original line number Diff line number Diff line
@@ -60,7 +60,7 @@ sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
## Install Node JS

1. Install NVM (node.js version manager) :
2. Install node.js v5  
2. Install node.js 16
3. Install common node.js dependencies
 
```bash
@@ -70,7 +70,7 @@ export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm

# Node.js
nvm install 6
nvm install 16

# node-pre-gyp
npm install -g nw-gyp node-pre-gyp
Original line number Diff line number Diff line
@@ -4,6 +4,6 @@
  "user_comment": "Ce fichier redirige vers le forum Duniter (via 'next_url')",
  "feed_url": "https://raw.githubusercontent.com/duniter/cesium/master/doc/feed/1.1/feed-fr-FR.json",

  "home_page_url": "https://forum.duniter.org/t/nouvelle-version-de-cesium-fr/11458/2",
  "next_url": "https://forum.duniter.org/t/nouvelle-version-de-cesium-fr/11458/2.json"
  "home_page_url": "https://forum.monnaie-libre.fr/t/actu-generale-la-1-bouge/31318",
  "next_url": "https://forum.monnaie-libre.fr/t/actu-generale-la-1-bouge/31318.json"
}
Original line number Diff line number Diff line
@@ -4,6 +4,6 @@
  "user_comment": "Ce fichier redirige vers le forum Duniter (via 'next_url')",
  "feed_url": "https://raw.githubusercontent.com/duniter/cesium/master/doc/feed/1.1/feed-fr-FR.json",

  "home_page_url": "https://forum.duniter.org/t/nouvelle-version-de-cesium-fr/11458/2",
  "next_url": "https://forum.duniter.org/t/nouvelle-version-de-cesium-fr/11458/2.json"
  "home_page_url": "https://forum.monnaie-libre.fr/t/actu-generale-la-1-bouge/31318",
  "next_url": "https://forum.monnaie-libre.fr/t/actu-generale-la-1-bouge/31318.json"
}
Original line number Diff line number Diff line
@@ -21,6 +21,18 @@
      "id": "https://forum.duniter.org/t/nouvelle-version-de-cesium/11458",
      "url": "https://forum.duniter.org/t/nouvelle-version-de-cesium/11458",
      "content_html": "<p>Une nouvelle version de Cesium <a href=\"https://cesium.app\">est disponible</a> !</p><blockquote><p>La mise jour du site et des Play Store est en cours.\nSoyez patient !</p></blockquote><p>Ces derniers mois, beaucoup d’entre vous ont rencontré des difficultés multiples : transactions qui disparaissent ou sont carrément perdues, erreur “délai d’attente dépassé”, nœud désynchronisé, etc.</p><p>Nous sommes bien conscients de ces problèmes. Ils sont liés à plusieurs facteurs :</p><ul><li>d’une part, à la nouvelle version 1.7 de Cesium, qui introduit la sélection automatique du nœud Duniter, par tirage au sort parmi les nœuds synchronisés ;</li><li>d’autre part, à l’état du réseau des nœuds Duniter, dont certains nœuds se sont révélés mal configurés pour fonctionner avec Cesium, ou utilisant des versions de Duniter non stables.</li></ul><h2><a name=\"nouveauts-1\" class=\"anchor\" href=\"#nouveauts-1\"></a>Nouveautés</h2><h3><a name=\"au-dmarrage-2\" class=\"anchor\" href=\"#au-dmarrage-2\"></a>Au démarrage</h3><p>La sélection des nœuds au démarrage a été revue, pour ne sélectionner que ceux compatibles avec les fonctionnalités de Cesium. Ceci devrait corriger les problèmes précédemment expliqués.</p><h3><a name=\"mes-oprations-3\" class=\"anchor\" href=\"#mes-oprations-3\"></a>Mes opérations</h3><p>Dans “Mes opérations”, les longs commentaires sont mieux visibles, que ce soit sur téléphone :<br><img src=\"https://forum.duniter.org/uploads/default/original/2X/4/4fa5d83286441e6689d93b6d636a46771fcb543d.png\" alt=\"image\" data-base62-sha1=\"bmB2vlwdnBe1zK86r7RGiQpJesl\" width=\"594\" height=\"357\"></p><p>…ou dans un navigateur web :</p><p><div class=\"lightbox-wrapper\"><a class=\"lightbox\" href=\"https://forum.duniter.org/uploads/default/original/2X/7/7d081473f9398e237425c96c8b9d55ef81e5662e.png\" data-download-href=\"https://forum.duniter.org/uploads/default/7d081473f9398e237425c96c8b9d55ef81e5662e\" title=\"image\"><img src=\"https://forum.duniter.org/uploads/default/optimized/2X/7/7d081473f9398e237425c96c8b9d55ef81e5662e_2_690x192.png\" alt=\"image\" data-base62-sha1=\"hQ4ZGoEbNyaKoAMxEGc1d0Ksby6\" width=\"690\" height=\"192\" srcset=\"https://forum.duniter.org/uploads/default/optimized/2X/7/7d081473f9398e237425c96c8b9d55ef81e5662e_2_690x192.png, https://forum.duniter.org/uploads/default/original/2X/7/7d081473f9398e237425c96c8b9d55ef81e5662e.png 1.5x, https://forum.duniter.org/uploads/default/original/2X/7/7d081473f9398e237425c96c8b9d55ef81e5662e.png 2x\" data-dominant-color=\"F2F6F8\"><div class=\"meta\"><svg class=\"fa d-icon d-icon-far-image svg-icon\" aria-hidden=\"true\"><use href=\"#far-image\"></use></svg><span class=\"filename\">image</span><span class=\"informations\">819×229 36.5 KB</span><svg class=\"fa d-icon d-icon-discourse-expand svg-icon\" aria-hidden=\"true\"><use href=\"#discourse-expand\"></use></svg></div></a></div></p><p>Autres petites améliorations sur cette page :</p><ul><li>Le fait de rafraîchir la liste ne provoque plus de clignotement des opérations déjà existantes. Seules les nouvelles opérations sont animées ;</li><li>le chargement des opérations plus anciennes (en bas de page) se fait directement par défilement vers le bas. Plus besoin de cliquer sur “Afficher plus” ou “Afficher tout” ! Au-delà de 6 mois d’historique, ces boutons apparaissent, pour limiter le nombre de requêtes au réseau.<br><div class=\"lightbox-wrapper\"><a class=\"lightbox\" href=\"https://forum.duniter.org/uploads/default/original/2X/8/8617ad8aa899debbc16bd92f38f1eefe68ed4699.png\" data-download-href=\"https://forum.duniter.org/uploads/default/8617ad8aa899debbc16bd92f38f1eefe68ed4699\" title=\"image\"><img src=\"https://forum.duniter.org/uploads/default/optimized/2X/8/8617ad8aa899debbc16bd92f38f1eefe68ed4699_2_690x211.png\" alt=\"image\" data-base62-sha1=\"j8eI3VQg2QseXemuowxFVl8qFlf\" width=\"690\" height=\"211\" srcset=\"https://forum.duniter.org/uploads/default/optimized/2X/8/8617ad8aa899debbc16bd92f38f1eefe68ed4699_2_690x211.png, https://forum.duniter.org/uploads/default/optimized/2X/8/8617ad8aa899debbc16bd92f38f1eefe68ed4699_2_1035x316.png 1.5x, https://forum.duniter.org/uploads/default/original/2X/8/8617ad8aa899debbc16bd92f38f1eefe68ed4699.png 2x\" data-dominant-color=\"F7F9FA\"><div class=\"meta\"><svg class=\"fa d-icon d-icon-far-image svg-icon\" aria-hidden=\"true\"><use href=\"#far-image\"></use></svg><span class=\"filename\">image</span><span class=\"informations\">1094×335 36.1 KB</span><svg class=\"fa d-icon d-icon-discourse-expand svg-icon\" aria-hidden=\"true\"><use href=\"#discourse-expand\"></use></svg></div></a></div></li></ul><h3><a name=\"rseaux-en-mode-expert-4\" class=\"anchor\" href=\"#rseaux-en-mode-expert-4\"></a>Réseaux (en mode expert)</h3><p>La vue réseau permet maintenant de voir l’état des files d’attente (ou piscines) contenant les documents en attente (transactions et demandes d’adhésion).</p><blockquote><p>Uniquement si vous avez activé le “mode expert” dans les paramètres,<br>et pour les nœuds ayant activé l’API BMA</p></blockquote><p><div class=\"lightbox-wrapper\"><a class=\"lightbox\" href=\"https://forum.duniter.org/uploads/default/original/2X/f/f475de5c8c5f2e8efa21e33a387c3262a33eded5.png\" data-download-href=\"https://forum.duniter.org/uploads/default/f475de5c8c5f2e8efa21e33a387c3262a33eded5\" title=\"image\"><img src=\"https://forum.duniter.org/uploads/default/optimized/2X/f/f475de5c8c5f2e8efa21e33a387c3262a33eded5_2_690x258.png\" alt=\"image\" data-base62-sha1=\"ySB2aVf3V1kcQ5aWwasCVNCX9kN\" width=\"690\" height=\"258\" srcset=\"https://forum.duniter.org/uploads/default/optimized/2X/f/f475de5c8c5f2e8efa21e33a387c3262a33eded5_2_690x258.png, https://forum.duniter.org/uploads/default/original/2X/f/f475de5c8c5f2e8efa21e33a387c3262a33eded5.png 1.5x, https://forum.duniter.org/uploads/default/original/2X/f/f475de5c8c5f2e8efa21e33a387c3262a33eded5.png 2x\" data-dominant-color=\"F3F7F4\"><div class=\"meta\"><svg class=\"fa d-icon d-icon-far-image svg-icon\" aria-hidden=\"true\"><use href=\"#far-image\"></use></svg><span class=\"filename\">image</span><span class=\"informations\">781×293 36.4 KB</span><svg class=\"fa d-icon d-icon-discourse-expand svg-icon\" aria-hidden=\"true\"><use href=\"#discourse-expand\"></use></svg></div></a></div></p><p>Autre petite nouveauté : vous pouvez voir si un nœud (BMA) archive bien l’historique des transactions. Le symbole <strong><img src=\"https://forum.duniter.org/images/emoji/twitter/credit_card.png?v=12\" title=\":credit_card:\" class=\"emoji\" alt=\":credit_card:\" loading=\"lazy\" width=\"20\" height=\"20\"> <code>TX</code></strong> s’affiche maintenant, dans la colonne <code>API</code>.</p><blockquote><p>Visible uniquement en mode expert, en <strong>décompactant l’affichage</strong> des lignes</p></blockquote><p><div class=\"lightbox-wrapper\"><a class=\"lightbox\" href=\"https://forum.duniter.org/uploads/default/original/2X/f/f6c5abe0063f927df3b6a1814f3265d611c4ac4c.png\" data-download-href=\"https://forum.duniter.org/uploads/default/f6c5abe0063f927df3b6a1814f3265d611c4ac4c\" title=\"image\"><img src=\"https://forum.duniter.org/uploads/default/optimized/2X/f/f6c5abe0063f927df3b6a1814f3265d611c4ac4c_2_690x40.png\" alt=\"image\" data-base62-sha1=\"zd2XW5qedxuZ7gjgSiRiYV6K2D2\" width=\"690\" height=\"40\" srcset=\"https://forum.duniter.org/uploads/default/optimized/2X/f/f6c5abe0063f927df3b6a1814f3265d611c4ac4c_2_690x40.png, https://forum.duniter.org/uploads/default/original/2X/f/f6c5abe0063f927df3b6a1814f3265d611c4ac4c.png 1.5x, https://forum.duniter.org/uploads/default/original/2X/f/f6c5abe0063f927df3b6a1814f3265d611c4ac4c.png 2x\" data-dominant-color=\"EFF3F1\"><div class=\"meta\"><svg class=\"fa d-icon d-icon-far-image svg-icon\" aria-hidden=\"true\"><use href=\"#far-image\"></use></svg><span class=\"filename\">image</span><span class=\"informations\">787×46 8.14 KB</span><svg class=\"fa d-icon d-icon-discourse-expand svg-icon\" aria-hidden=\"true\"><use href=\"#discourse-expand\"></use></svg></div></a></div></p><h3><a name=\"autres-correctifs-5\" class=\"anchor\" href=\"#autres-correctifs-5\"></a>Autres correctifs</h3><ul><li>Android / iOS : le téléchargement de fichier fonctionne ! Pour le fichier de révocation notamment, mais aussi pour la liste des opérations, la sauvegarde des identifiants, etc.<blockquote><p>Vous trouverez le fichier téléchargé dans le répertoire “Téléchargements” (sous Android) ou “Documents” (sous iOS) ;</p></blockquote></li><li>Mes opérations : la liste des DU s’affiche maintenant correctement (sans passer par les nœuds Duniter pour contourner une limitation, mais par le pod Cesium+ s’il est activé) ;</li><li>Notifications : le nombre de messages ou de notifications est maintenant correct lorsque vous vous connectez pour la première fois sur un compte.</li></ul><br/> (...)"
    },
    {
      "title": "Actu générale : La Ǧ1 bouge !",
      "author": {
        "name": "Collectif MaJ V2",
        "url": "@LeForum",
        "avatar": "https://forum.monnaie-libre.fr/user_avatar/forum.monnaie-libre.fr/leforum/48/8260_2.png"
      },
      "date_published": "2025-02-25T12:09:00+02:00",
      "id": "https://forum.monnaie-libre.fr/t/actu-generale-la-1-bouge/31318",
      "url": "https://forum.monnaie-libre.fr/t/actu-generale-la-1-bouge/31318",
      "content_html": "<p>La Ǧ1 bouge, plusieurs chantiers importants sont en cours :</p>\n<ul>\n<li>Son écosystème technique qui approche de sa <a href=\"https://monnaie-libre.fr/maj-v2/\">mise à jour (V2) </a> sur laquelle nous travaillons depuis plusieurs années.</li>\n<li>Organisation et prises des décisions (gouvernance) dont un <a href=\"https://forum.monnaie-libre.fr/t/proposition-licence-g1-v0-3-0/31234\">vote pour faire évoluer la licence Ǧ1</a> auquel vous pouvez prendre part avant le 13 mars.</li>\n</ul>\n<p><strong>Pour la dernière ligne droite, la Ǧ1 a besoin de vous :</strong></p>\n<ul>\n<li>Pour accélérer les développements restants par un <a href=\"https://www.helloasso.com/associations/axiom-team/collectes/finalisation-de-cesium-v2-et-duniter-v2\">financement participatif</a> pour rémunérer quelques mois un développeur afin de finaliser Cesium².</li>\n<li>Pour tester les logiciels et nous dire ce qui ne marche pas sur votre appareil (ordi, tablette ou smartphone).</li>\n</ul>\n<p>Pour être tenu au courant d’un ou plusieurs des sujets évoqués, <a href=\"https://s.42l.fr/form-g1v2\">laissez-nous votre email</a>.</p>"
    }
  ]
}
+81 −3
Original line number Diff line number Diff line
@@ -792,7 +792,13 @@ function webZip() {

function webExtClean() {
  return del([
    './dist/web/ext'
    './dist/web/ext',
  ]);
}

function chromeExtClean() {
  return del([
    './dist/web/chrome-ext'
  ]);
}

@@ -836,7 +842,47 @@ function webExtCopyFiles() {
  .pipe(gulp.dest('./dist/web/ext'));
}

function webExtensionZip() {
function chromeExtCopyFiles() {
  const wwwPath = './dist/web/www';
  const resourcesPath = './resources/chrome-ext';
  log(colors.green('Copy chrome extension files...'));

  const version = JSON.parse(fs.readFileSync('./package.json', 'utf8')).version;
  const manifestFilter = filter(["**/manifest.json"], { restore: true });
  const txtFilter = filter(["**/*.txt"], { restore: true });

  // Copy files
  return gulp.src([
    wwwPath + '/**/*',

    // Skip API files
    '!' + wwwPath + '/api',
    '!' + wwwPath + '/dist_js/*-api.js',
    '!' + wwwPath + '/dist_css/*-api.css',
    '!' + wwwPath + '/maps/dist_js/*-api.js.map',
    '!' + wwwPath + '/maps/dist_css/*-api.css.map',

    // Skip web manifest
    '!' + wwwPath + '/manifest.json',

    // Add specific resources (and overwrite the default 'manifest.json')
    resourcesPath + '/**/*.*'
  ])

  // Process TXT files: Add the UTF-8 BOM character
  .pipe(txtFilter)
  .pipe(header('\ufeff'))
  .pipe(txtFilter.restore)

  // Replace version in 'manifest.json' file
  .pipe(manifestFilter)
  .pipe(replace(/\"version\": \"[^\"]*\"/, '"version": "' + version + '"'))
  .pipe(manifestFilter.restore)

  .pipe(gulp.dest('./dist/web/chrome-ext'));
}

function webExtZip() {
  const srcPath = './dist/web/ext';
  const distPath = './dist/web/build';
  const version = JSON.parse(fs.readFileSync('./package.json', 'utf8')).version;
@@ -846,6 +892,16 @@ function webExtensionZip() {
    .pipe(gulp.dest(distPath));
}

function chromeExtZip() {
  const srcPath = './dist/web/chrome-ext';
  const distPath = './dist/web/build';
  const version = JSON.parse(fs.readFileSync('./package.json', 'utf8')).version;

  return gulp.src(srcPath + '/**/*.*')
    .pipe(zip('cesium-v'+version+'-extension-chrome.zip'))
    .pipe(gulp.dest(distPath));
}

function webBuildSuccess(done) {
  var version = JSON.parse(fs.readFileSync('./package.json', 'utf8')).version;
  log(colors.green("Web artifact created at: 'dist/web/build/cesium-v" + version + "-web.zip'"));
@@ -858,6 +914,12 @@ function webExtBuildSuccess(done) {
  if (done) done();
}

function chromeExtBuildSuccess(done) {
  var version = JSON.parse(fs.readFileSync('./package.json', 'utf8')).version;
  log(colors.green("Web extension artifact created at: 'dist/web/build/cesium-v" + version + "-extension-chrome.zip'"));
  if (done) done();
}

function cdvAddPlatformToBodyTag() {
  log(colors.green('Add platform CSS class to <body>... '));

@@ -1398,13 +1460,25 @@ const webExtCompile = gulp.series(
  webExtCopyFiles
);

const chromeExtCompile = gulp.series(
  chromeExtClean,
  webCompile,
  chromeExtCopyFiles
);

// note : Do not call config, to keep same config between web and webExt artifacts
const webExtBuild = gulp.series(
  webExtCompile,
  webExtensionZip,
  webExtZip,
  webExtBuildSuccess
);

const chromeExtBuild = gulp.series(
  chromeExtCompile,
  chromeExtZip,
  chromeExtBuildSuccess
);



/* --------------------------------------------------------------------------
@@ -1436,6 +1510,10 @@ exports.webExtBuild = webExtBuild;
exports.webExtCopyFiles = webExtCopyFiles;
exports['build:webExt'] = exports.webExtBuild; // Alias

// Chrome extension
exports.chromeExtBuild = chromeExtBuild;
exports['build:chromeExt'] = exports.chromeExtBuild; // Alias

// Cordova (hooks)
const cdvAfterPrepare = gulp.series(
  gulp.parallel(cdvNgAnnotate, cdvAddPlatformToBodyTag),
+1 −1
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@ is_installed() {
CESIUM_DIR=${1:-$(pwd)/cesium}

latest_version() {
  echo "v1.7.13" # lastest
  echo "v1.7.16" # lastest
}

api_release_url() {
+22 −20
Original line number Diff line number Diff line
{
  "name": "cesium",
  "version": "1.7.13",
  "version": "1.7.16.2",
  "description": "Cesium Wallet for G1 libre currency",
  "author": "Benoit Lavenier <benoit.lavenier@e-is.pro>",
  "license": "AGPL-3.0",
@@ -12,19 +12,20 @@
  "scripts": {
    "clean": "gulp clean webClean webExtClean && rm -rf dist/web dist/android && rm -f desktop/**/cesium-*.deb desktop/**/cesium-*.exe platforms/android/**/*.apk",
    "postinstall": "node scripts/node/postinstall.js",
    "gulp": "gulp",
    "lint": "gulp lint",
    "gulp": "npx gulp",
    "lint": "npx gulp lint",
    "install-platforms": "ionic cordova prepare",
    "start": "ionic serve",
    "start:webExt": "gulp webExtCompile && web-ext run --source-dir ./dist/web/ext/ --devtools",
    "start:webExt": "npx gulp webExtCompile && web-ext run --source-dir ./dist/web/ext/ --devtools",
    "start:android": "ionic cordova run android --color",
    "docker:build": "sudo docker build . -t cesium/release",
    "docker:run": "sudo docker run -ti --rm -p 8100:8100 -p 35729:35729 -v .:/cesium:rw cesium/release",
    "build": "gulp build",
    "build:web": "gulp config --env default && gulp webBuild --release",
    "build:webExt": "gulp config --env default && gulp webExtBuild --release",
    "build": "npx gulp build",
    "build:web": "npx gulp config --env default && npx gulp webBuild --release",
    "build:webExt": "npx gulp config --env default && npx gulp webExtBuild --release",
    "build:android": "ionic cordova build android --warning-mode=none --color --release -- -- --packageType=apk",
    "build:ios": "ionic cordova build ios --warning-mode=none --color --release"
    "build:ios": "ionic cordova build ios --warning-mode=none --color --release",
    "build:chromeExt": "npx gulp config --env default && npx gulp chromeExtBuild --release"
  },
  "keywords": [
    "duniter",
@@ -93,23 +94,24 @@
    "@ionic/v1-toolkit": "^3.2.20",
    "@prantlf/gulp-jsonlint": "^2.4.0",
    "ansi-colors": "^4.1.1",
    "cordova": "^11.1.0",
    "cordova-android": "^10.1.2",
    "cordova": "^12.0.0",
    "cordova-android": "^13.0.0",
    "cordova-clipboard": "^1.3.0",
    "cordova-fetch": "^4.0.0",
    "cordova-ios": "^6.3.0",
    "cordova-fetch": "^5.0.0",
    "cordova-ios": "^7.1.1",
    "cordova-plugin-androidx-adapter": "^1.1.3",
    "cordova-plugin-camera": "^5.0.3",
    "cordova-plugin-inappbrowser": "^6.0.0",
    "cordova-plugin-camera": "^8.0.0",
    "cordova-plugin-customurlscheme": "^5.0.2",
    "cordova-plugin-device": "^2.1.0",
    "cordova-plugin-device": "^3.0.0",
    "cordova-plugin-dialogs": "^2.0.2",
    "cordova-plugin-file": "^8.0.0",
    "cordova-plugin-file": "^8.1.3",
    "cordova-plugin-ionic-keyboard": "^2.2.0",
    "cordova-plugin-ionic-webview": "^5.0.0",
    "cordova-plugin-ionic-webview": "^5.0.1",
    "cordova-plugin-network-information": "~3.0.0",
    "cordova-plugin-secure-storage-android10": "~6.0.7",
    "cordova-plugin-splashscreen": "^6.0.2",
    "cordova-plugin-statusbar": "^3.0.0",
    "cordova-plugin-statusbar": "^4.0.0",
    "cordova-plugin-vibration": "^3.1.1",
    "cordova-plugin-websocket": "^0.12.2",
    "cordova-plugin-x-toast": "^2.7.3",
@@ -157,10 +159,10 @@
    "merge2": "^1.3.0",
    "mv": "^2.1.1",
    "node-sass": "^9.0.0",
    "phonegap-plugin-barcodescanner": "^8.1.0",
    "@red-mobile/cordova-plugin-barcodescanner": "^9.1.0",
    "playup": "^1.1.0",
    "vinyl-fs": "^3.0.3",
    "web-ext": "^7.9.0",
    "web-ext": "^8.9.0",
    "yargs": "^5.0.0"
  },
  "peerDependencies": {
@@ -189,7 +191,7 @@
      "cordova-plugin-websocket": {},
      "cordova-plugin-x-toast": {},
      "cordova-plugin-ionic-keyboard": {},
      "phonegap-plugin-barcodescanner": {
      "@red-mobile/cordova-plugin-barcodescanner": {
        "CAMERA_USAGE_DESCRIPTION": "To scan QRCode",
        "ANDROID_SUPPORT_V4_VERSION": "28.+"
      },
Original line number Diff line number Diff line
@@ -2,16 +2,16 @@ FROM ubuntu:18.04
LABEL maintainer="benoit [dot] lavenier [at] e-is [dot] pro"

ENV DEBIAN_FRONTEND=noninteractive \
    ANDROID_HOME=/opt/android-sdk-linux \
    NODE_VERSION=10.20.0 \
    NPM_VERSION=6.14.4 \
    YARN_VERSION=1.22.4 \
    IONIC_CLI_VERSION=6.5.0 \
    CORDOVA_VERSION=8.1.2 \
    CORDOVA_RES_VERSION=0.11.0 \
    NATIVE_RUN_VERSION=1.0.0 \
    GRADLE_VERSION=4.10.3 \
    GULP_VERSION=2.2.0 \
    ANDROID_SDK_ROOT=/opt/android-sdk-linux \
    NODE_VERSION=16.20.2 \
    NPM_VERSION=8.19.4 \
    YARN_VERSION=1.22.22 \
    IONIC_CLI_VERSION=6.20.9 \
    CORDOVA_VERSION=12.0.0 \
    CORDOVA_RES_VERSION=0.15.4 \
    NATIVE_RUN_VERSION=2.0.0 \
    GRADLE_VERSION=8.7 \
    GULP_VERSION=4.0.2 \
    ANDROID_NDK_VERSION=r19c \
    ANDROID_SDK_VERSION=r29.0.2

@@ -33,7 +33,7 @@ RUN npm install -g cordova@"$CORDOVA_VERSION" cordova-res@"$CORDOVA_RES_VERSION"
    npm cache clear --force

# Install Android prerequisites
RUN echo ANDROID_HOME="${ANDROID_HOME}" >> /etc/environment && \
RUN echo ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT}" >> /etc/environment && \
    dpkg --add-architecture i386 && \
    apt-get update && \
    apt-get -y install openjdk-11-jdk-headless && \
@@ -65,13 +65,13 @@ RUN echo ANDROID_HOME="${ANDROID_HOME}" >> /etc/environment && \

# Setup environment

#ENV PATH ${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:/opt/tools:/opt/gradle/gradle-"$GRADLE_VERSION"/bin
#ENV PATH ${PATH}:${ANDROID_SDK_ROOT}/tools:${ANDROID_SDK_ROOT}/platform-tools:/opt/tools:/opt/gradle/gradle-"$GRADLE_VERSION"/bin

# Install sdk elements
#COPY resources/android/build/tools /opt/tools
#RUN chmod u+x /opt/tools/*.sh
#RUN ["/opt/tools/android-accept-licenses.sh", "android update sdk --all --no-ui --filter platform-tools,tools,build-tools-29.0.0,android-29,build-tools-26.0.0,android-26,build-tools-25.0.0,android-25,extra-android-support,extra-android-m2repository,extra-google-m2repository"]
#RUN unzip ${ANDROID_HOME}/temp/*.zip -d ${ANDROID_HOME}
#RUN unzip ${ANDROID_SDK_ROOT}/temp/*.zip -d ${ANDROID_SDK_ROOT}


# Install source code
Original line number Diff line number Diff line
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https://services.gradle.org/distributions/gradle-6.7.1-all.zip
Original line number Diff line number Diff line
# Manifest V3 migration
# Chrome Extension (Manifest V3)

This folder `chrome-ext` has been created in order to prepare to Manifest V3 format.
This folder contains the specific files for the Chrome Extension, which uses the Manifest V3 format.

This is working well for Chrome, but not yet for Firefox.
## Build

To build the Chrome extension, run the following command from the root of the project:

```bash
npm run build:chromeExt
```

This will generate a zip file in the `dist/web/build` directory, which can then be uploaded to the Chrome Web Store.
Original line number Diff line number Diff line
@@ -10,9 +10,62 @@ var browser, chrome;
browser = browser || chrome;

var action = browser.browserAction || (chrome && chrome.action);
var alarms = browser.alarms || (chrome && chrome.alarms);
var storage = browser.storage || (chrome && chrome.storage);

function promiseAll(promises) {
  if (!promises || !promises.length) throw new Error('Expected an array of urls');

  var results = [];
  var counter = 0;
  return new Promise(function(resolve, reject) {
    promises.reduce(function(res, promise, index) {
      res.push();
      promise
        .then(function(json) {
          res[index] = json;
          counter++;
        })
        .catch(function(err) {
          console.error(err);
          res[index] = undefined;
          counter++;
        })
        .then(function() {
          if (counter === promises.length) {
            resolve(res);
          }
        });
      return res;
    }, []);
  })
}

function fetchAll(urls, type) {
  if (!urls || !urls.length) throw new Error('Expected an array of urls');
  type = type || 'json';
  return promiseAll(urls.map(function(url) {
    return fetch(url)
      .then(function(response) {
        if (!response.ok) {
          throw new Error('HTTP error (status: ' + response.status + ')');
        }
        if (type === 'json') {
          return response.json();
        }
        return response.text();
      })
  }));
}

var browserExtensionRequirements = browser.tabs && action && action.onClicked;

// Storage object selection: use local storage if available, otherwise session storage
var storageObj = storage.local && storage.local.get ? storage.local :
  (storage.session && storage.session.get ? storage.session : null);

var notificationReadTime = undefined;

// If integrated as a browser extension
if (browserExtensionRequirements) {
  console.debug("[extension] Initializing...");
@@ -25,28 +78,243 @@ if (browserExtensionRequirements) {
    browser.tabs.create({
      url: "index.html"
    });

    // Reset last notification check
    if (notificationReadTime > 0) {
      setStorageValue('lastNotificationCheck', notificationReadTime);
    }

    resetNotifications();
  }

  // Adding browser action
  action.onClicked.addListener(openInTab);

  // FIXME: finish this code
  function getConfig() {
    // Read then parse the file config.js file to get config as an JSON object (instead of a angular v1 constant)
    // then read the csConfig service
    return fetch('config.js')
      .then(response => response.text())
      .then(configText => {
        // Extract the csConfig object from the Angular v1 constant
        // Find the .constant("csConfig", { ... }) part
        const constantMatch = configText.match(/\.constant\s*\(\s*["']csConfig["']\s*,\s*(\{[\s\S]*?\})\s*\)/);
        if (constantMatch && constantMatch[1]) {
          try {
            // Parse the JSON object from the constant
            const configObject = JSON.parse(constantMatch[1]);
            console.debug("[extension] Config loaded:", configObject);
            return configObject;
          } catch (error) {
            console.error("[extension] Error parsing config:", error);
            return null;
          }
        } else {
          console.error("[extension] Could not find csConfig constant in config.js");
          return null;
        }
      })
      .catch(error => {
        console.error("[extension] Error loading config.js:", error);
        return null;
      });
  }

  function getStorageValue(key) {
    console.debug("[extension] Reading storage from key: " + key);
    if (!storageObj) {
      console.warn("[extension] No storage API available");
      return Promise.resolve(undefined);
    }
    return storageObj.get(key).then(function(res) {
      return res && res[key] || undefined;
    });
  }

  function setStorageValue(key, value) {
    console.debug("[extension] Saving storage from key: " + key, value);
    if (!storageObj) {
      console.warn("[extension] No storage API available");
      return Promise.resolve(undefined);
    }
    var entry = {};
    entry[key] = value;
    return storageObj.set(entry);
  }

  function getStorageValueObject(key) {
    return getStorageValue(key)
      .then(function(strValue) {
        return JSON.parse(strValue || 'null');
      })
  }

  function getWalletPubkey() {
    return getStorageValue('pubkey')
  }

  function getSettings() {
    return getStorageValueObject('settings');
  }

  function getData() {
    return promiseAll([
      getWalletPubkey(),
      getConfig(),
      getSettings(),
      getStorageValue('lastNotificationCheck')
    ])
      .then(function(res) {
        var data = {};
        data.pubkey = res[0];
        data.config = res[1];
        data.settings = res[2];
        data.lastNotificationCheck = res[3];
        console.debug("[extension] Data loaded:", data);
        return data;
      });
  }

  function getNotificationCount() {
    var startTime = Date.now();

    return getData()
      .then(function(data) {
        var pubkey = data.pubkey;
        var config = data.config;
        var settings = data.settings;
        var lastNotificationCheck = data.lastNotificationCheck;
        const esEnable = config && config.plugins && config.plugins.es && config.plugins.es.enable === true
          && (settings && settings.plugins && settings.plugins.es && settings.plugins.es.enable) !== false;

        // No wallet defined
        if (!data.pubkey || typeof data.pubkey !== 'string') {
          console.warn("[extension] No pubkey defined in local storage. Cannot checking for notificaiton");
          return;
        }

        if (!esEnable) {
          console.warn("[extension] ES plugin disabled. Cannot checking for notificaiton");
          return;
        }

        var peers = settings && settings.plugins && settings.plugins.es && settings.plugins.es.host ?
          [{host: settings.plugins.es.host, port: settings.plugins.es.port}] :
          (config.plugins.es.host ? [{host: config.plugins.es.host, port: config.plugins.es.port}] : config.plugins.es.fallbackNodes);
        if (!peers || !peers.length) {
          console.warn('[extension] No ES peers found, in config and settings');
          return;
        }



        if (lastNotificationCheck > 0 && lastNotificationCheck < Date.now()) {
          console.info('[extension] Checking for notifications... since: ' + new Date(lastNotificationCheck));
        } else {
          console.info('[extension] Checking for notifications... (first check)');
        }

        // Path
        var path = '/user/event/_count'
          + '?q=recipient:' + pubkey
          + " AND NOT _exists_:read_signature";
        if (lastNotificationCheck > 0) {
          var lastTime = Math.round(lastNotificationCheck / 1000);
          path += " AND time > " + lastTime;
        }

        // Create count url for each peers
        var urls = [];
        var peerUrls = [];
        for (var i = 0; i < peers.length; i++) {
          var peer = peers[i];
          var host = peer && peer.host;
          var port = peer && peer.port || 80;
          var protocol = (peer && peer.useSsl || port === 443) ? 'https' : 'http';
          if (host) {
            if (protocol === 'https' && port === 443) port = undefined;
            var peerUrl = protocol + '://' + host + (port ? (':' + port) : '');
            peerUrls.push(peerUrl);
            urls.push(peerUrl + path);
          }
        }

        console.debug('[extension] Using ES peers: ' + peerUrls.join(', '));

        var startTime = Date.now();

        // Fetch count queries
        return fetchAll(urls)
          .then(function(results) {
            if (!results || !results.length) return; // Skip if not count results

            console.debug('[extension] ' + results.length + ' fetch result(s), from ' + peers.length +' peer(s)', results);

            // Get min count
            var count = results.reduce(function(min, result) {
              if (result && result.count >= 0) {
                if (min < 0) return result.count;
                return Math.min(min, result.count);
              }
              return min;
            }, -1);


            console.info('[extension] Checking for notifications [OK] - ' + (count || 0) + ' notification(s) found, in ' + (Date.now() - startTime) + 'ms');

            // Update the check time
            if (count !== -1) {
              notificationReadTime = Date.now();
            }

            return count;
          });
      });
  }

  // FIXME: This code has been updated to use the chrome.alarms API for Manifest V3 compatibility.
  function checkNotifications() {
    console.debug("[extension] Checking for notifications...");
    return getNotificationCount()
      .then(function(count) {

        if (count > 0) {
          var badgeText = count > 99 ? '99+' : ('' + count);
          action.setBadgeText({
      text: '0'
            text: badgeText
          });
        }
        else {
          action.setBadgeText({text: ''});
        }
        action.setBadgeBackgroundColor({
      color: '#387EF5' // = $positive color - see the SCSS theme
          color: '#11c1f3' // = $calm color - see the SCSS theme
        });

      })
  }

  function resetNotifications() {
    action.setBadgeText({text: ''});
  }

  // If browser allow alarms
  if (alarms && alarms.create && alarms.onAlarm) {
    // Create an alarm to run the notification check periodically.
    // The minimum period for Manifest V3 is 1 minute.
    alarms.create('notificationTimer', {
      periodInMinutes: 1
    });

    // Add a listener for when the alarm goes off.
    alarms.onAlarm.addListener(alarm => {
      if (alarm.name === 'notificationTimer') {
        checkNotifications();
      }
    });

    // Loop, after a delay
    setTimeout(function() {
    // Check for notification
    checkNotifications();
    }, 60 * 1000 /*1min*/);
  }
  //checkNotifications();
}
else {
  console.error("[extension] Cannot init extension: missing some API requirements (action or tabs");
Original line number Diff line number Diff line
{
  "manifest_version": 2,
  "manifest_version": 3,
  "name": "Cesium",
  "version": "1.7.12",
  "version": "1.7.16.2",
  "description": "Cesium Wallet for Ğ1 libre currency",
  "icons": {
    "32": "img/logo_32px.png",
    "60": "img/logo_60px.png",
    "96": "img/logo_96px.png",
    "128": "img/logo_128px.png",
    "144": "img/logo_144px.png",
    "192": "img/logo.svg"
    "200": "img/logo_200px.png",
    "256": "img/logo_256px.png",
    "512": "img/logo_512px.png"
  },
  "permissions": [
    "storage"
    "storage",
    "alarms"
  ],
  "host_permissions": [
    "file:///*",
    "*://*/*"
  ],
  "background": {
    "service_worker": "background.js",
    "scripts": ["background.js"]
  },
  "browser_action" : {
    "default_icon": {
      "32": "img/logo_32px.png",
      "60": "img/logo_60px.png",
      "96": "img/logo_96px.png",
      "128": "img/logo_128px.png"
    }
    "service_worker": "background.js"
  },
  "action": {
    "default_title": "Cesium",
    "default_icon": {
      "32": "img/logo_32px.png",
      "60": "img/logo_60px.png",
      "96": "img/logo_96px.png",
      "128": "img/logo_128px.png",
      "144": "img/logo_144px.png",
      "192": "img/logo.svg"
      "200": "img/logo_200px.png",
      "256": "img/logo_256px.png",
      "512": "img/logo_512px.png"
    }
  },
  "content_security_policy": {
    "extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';"
  }
}
+13 −0
Original line number Diff line number Diff line
# Firefox Extension

This folder contains the specific files for the Firefox Extension.

## Build

To build the Firefox extension, run the following command from the root of the project:

```bash
npm run build:webExt
```

This will generate a zip file in the `dist/web/build` directory, which can then be uploaded to the Mozilla catalog.
Original line number Diff line number Diff line
@@ -10,9 +10,62 @@ var browser, chrome;
browser = browser || chrome;

var action = browser.browserAction || (chrome && chrome.action);
var alarms = browser.alarms || (chrome && chrome.alarms);
var storage = browser.storage || (chrome && chrome.storage);

function promiseAll(promises) {
  if (!promises || !promises.length) throw new Error('Expected an array of urls');

  var results = [];
  var counter = 0;
  return new Promise(function(resolve, reject) {
    promises.reduce(function(res, promise, index) {
      res.push();
      promise
        .then(function(json) {
          res[index] = json;
          counter++;
        })
        .catch(function(err) {
          console.error(err);
          res[index] = undefined;
          counter++;
        })
        .then(function() {
          if (counter === promises.length) {
            resolve(res);
          }
        });
      return res;
    }, []);
  })
}

function fetchAll(urls, type) {
  if (!urls || !urls.length) throw new Error('Expected an array of urls');
  type = type || 'json';
  return promiseAll(urls.map(function(url) {
    return fetch(url)
      .then(function(response) {
        if (!response.ok) {
          throw new Error('HTTP error (status: ' + response.status + ')');
        }
        if (type === 'json') {
          return response.json();
        }
        return response.text();
      })
  }));
}

var browserExtensionRequirements = browser.tabs && action && action.onClicked;

// Storage object selection: use local storage if available, otherwise session storage
var storageObj = storage.local && storage.local.get ? storage.local :
  (storage.session && storage.session.get ? storage.session : null);

var notificationReadTime = undefined;

// If integrated as a browser extension
if (browserExtensionRequirements) {
  console.debug("[extension] Initializing...");
@@ -25,28 +78,241 @@ if (browserExtensionRequirements) {
    browser.tabs.create({
      url: "index.html"
    });

    // Reset last notification check
    if (notificationReadTime > 0) {
      setStorageValue('lastNotificationCheck', notificationReadTime);
    }

    resetNotifications();
  }

  // Adding browser action
  action.onClicked.addListener(openInTab);

  // FIXME: finish this code
  function getConfig() {
    // Read then parse the file config.js file to get config as an JSON object (instead of a angular v1 constant)
    // then read the csConfig service
    return fetch('config.js')
      .then(response => response.text())
      .then(configText => {
        // Extract the csConfig object from the Angular v1 constant
        // Find the .constant("csConfig", { ... }) part
        const constantMatch = configText.match(/\.constant\s*\(\s*["']csConfig["']\s*,\s*(\{[\s\S]*?\})\s*\)/);
        if (constantMatch && constantMatch[1]) {
          try {
            // Parse the JSON object from the constant
            const configObject = JSON.parse(constantMatch[1]);
            console.debug("[extension] Config loaded:", configObject);
            return configObject;
          } catch (error) {
            console.error("[extension] Error parsing config:", error);
            return null;
          }
        } else {
          console.error("[extension] Could not find csConfig constant in config.js");
          return null;
        }
      })
      .catch(error => {
        console.error("[extension] Error loading config.js:", error);
        return null;
      });
  }

  function getStorageValue(key) {
    console.debug("[extension] Reading storage from key: " + key);
    if (!storageObj) {
      console.warn("[extension] No storage API available");
      return Promise.resolve(undefined);
    }
    return storageObj.get(key).then(function(res) {
      return res && res[key] || undefined;
    });
  }

  function setStorageValue(key, value) {
    console.debug("[extension] Saving storage from key: " + key, value);
    if (!storageObj) {
      console.warn("[extension] No storage API available");
      return Promise.resolve(undefined);
    }
    var entry = {};
    entry[key] = value;
    return storageObj.set(entry);
  }

  function getStorageValueObject(key) {
    return getStorageValue(key)
      .then(function(strValue) {
        return JSON.parse(strValue || 'null');
      })
  }

  function getWalletPubkey() {
    return getStorageValue('pubkey')
  }

  function getSettings() {
    return getStorageValueObject('settings');
  }

  function getData() {
    return promiseAll([
      getWalletPubkey(),
      getConfig(),
      getSettings(),
      getStorageValue('lastNotificationCheck')
    ])
      .then(function(res) {
        var data = {};
        data.pubkey = res[0];
        data.config = res[1];
        data.settings = res[2];
        data.lastNotificationCheck = res[3];
        console.debug("[extension] Data loaded:", data);
        return data;
      });
  }

  function getNotificationCount() {
    var startTime = Date.now();

    return getData()
      .then(function(data) {
        var pubkey = data.pubkey;
        var config = data.config;
        var settings = data.settings;
        var lastNotificationCheck = data.lastNotificationCheck;
        const esEnable = config && config.plugins && config.plugins.es && config.plugins.es.enable === true
          && (settings && settings.plugins && settings.plugins.es && settings.plugins.es.enable) !== false;

        // No wallet defined
        if (!data.pubkey || typeof data.pubkey !== 'string') {
          console.warn("[extension] No pubkey defined in local storage. Cannot checking for notificaiton");
          return;
        }

        if (!esEnable) {
          console.warn("[extension] ES plugin disabled. Cannot checking for notificaiton");
          return;
        }

        var peers = settings && settings.plugins && settings.plugins.es && settings.plugins.es.host ?
          [{host: settings.plugins.es.host, port: settings.plugins.es.port}] :
          (config.plugins.es.host ? [{host: config.plugins.es.host, port: config.plugins.es.port}] : config.plugins.es.fallbackNodes);
        if (!peers || !peers.length) {
          console.warn('[extension] No ES peers found, in config and settings');
          return;
        }

        if (lastNotificationCheck > 0 && lastNotificationCheck < Date.now()) {
          console.info('[extension] Checking for notifications... since: ' + new Date(lastNotificationCheck));
        } else {
          console.info('[extension] Checking for notifications... (first check)');
        }

        // Path
        var path = '/user/event/_count'
          + '?q=recipient:' + pubkey
          + " AND NOT _exists_:read_signature";
        if (lastNotificationCheck > 0) {
          var lastTime = Math.round(lastNotificationCheck / 1000);
          path += " AND time > " + lastTime;
        }

        // Create count url for each peers
        var urls = [];
        var peerUrls = [];
        for (var i = 0; i < peers.length; i++) {
          var peer = peers[i];
          var host = peer && peer.host;
          var port = peer && peer.port || 80;
          var protocol = (peer && peer.useSsl || port === 443) ? 'https' : 'http';
          if (host) {
            if (protocol === 'https' && port === 443) port = undefined;
            var peerUrl = protocol + '://' + host + (port ? (':' + port) : '');
            peerUrls.push(peerUrl);
            urls.push(peerUrl + path);
          }
        }

        console.debug('[extension] Using ES peers: ' + peerUrls.join(', '));

        var startTime = Date.now();

        // Fetch count queries
        return fetchAll(urls)
          .then(function(results) {
            if (!results || !results.length) return; // Skip if not count results

            console.debug('[extension] ' + results.length + ' fetch result(s), from ' + peers.length +' peer(s)', results);

            // Get min count
            var count = results.reduce(function(min, result) {
              if (result && result.count >= 0) {
                if (min < 0) return result.count;
                return Math.min(min, result.count);
              }
              return min;
            }, -1);


            console.info('[extension] Checking for notifications [OK] - ' + (count || 0) + ' notification(s) found, in ' + (Date.now() - startTime) + 'ms');

            // Update the check time
            if (count !== -1) {
              notificationReadTime = Date.now();
            }

            return count;
          });
      });
  }

  // FIXME: This code has been updated to use the chrome.alarms API for Manifest V3 compatibility.
  function checkNotifications() {
    console.debug("[extension] Checking for notifications...");
    return getNotificationCount()
      .then(function(count) {

        if (count > 0) {
          var badgeText = count > 99 ? '99+' : ('' + count);
          action.setBadgeText({
      text: '0'
            text: badgeText
          });
        }
        else {
          action.setBadgeText({text: ''});
        }
        action.setBadgeBackgroundColor({
      color: '#387EF5' // = $positive color - see the SCSS theme
          color: '#11c1f3' // = $calm color - see the SCSS theme
        });

      })
  }

  function resetNotifications() {
    action.setBadgeText({text: ''});
  }

  // If browser allow alarms
  if (alarms && alarms.create && alarms.onAlarm) {
    // Create an alarm to run the notification check periodically.
    // The minimum period for Manifest V3 is 1 minute.
    alarms.create('notificationTimer', {
      periodInMinutes: 1
    });

    // Add a listener for when the alarm goes off.
    alarms.onAlarm.addListener(alarm => {
      if (alarm.name === 'notificationTimer') {
        checkNotifications();
      }
    });

    // Loop, after a delay
    setTimeout(function() {
    // Check for notification
    checkNotifications();
    }, 60 * 1000 /*1min*/);
  }
  //checkNotifications();
}
else {
  console.error("[extension] Cannot init extension: missing some API requirements (action or tabs");
Original line number Diff line number Diff line
{
  "name": "Cesium",
  "short_name": "Cesium",
  "version": "1.7.13",
  "description": "Manage your Duniter Wallet on a libre currency, like Ğ1",
  "version": "1.7.16.2",
  "description": "Cesium Wallet for Ğ1 libre currency",
  "background": {
    "scripts": ["background.js"]
  },
  "permissions": ["storage"],
  "permissions": ["storage", "alarms"],
  "browser_action" : {
    "default_title": "Cesium",
    "default_icon": {
@@ -14,7 +14,15 @@
      "60": "img/logo_60px.png",
      "96": "img/logo_96px.png",
      "128": "img/logo_128px.png",
      "192": "img/logo.svg"
      "144": "img/logo_144px.png",
      "200": "img/logo_200.png",
      "256": "img/logo_256px.png",
      "512": "img/logo_512px.png"
    }
  },
  "browser_specific_settings": {
    "gecko": {
      "id": "{6f9922f7-a054-4609-94ce-d269993246a5}"
    }
  },
  "icons": {
@@ -22,7 +30,10 @@
    "60": "img/logo_60px.png",
    "96": "img/logo_96px.png",
    "128": "img/logo_128px.png",
    "192": "img/logo.svg"
    "144": "img/logo_144px.png",
    "200": "img/logo_200.png",
    "256": "img/logo_256px.png",
    "512": "img/logo_512px.png"
  },
  "protocol_handlers": [
    {
Original line number Diff line number Diff line
@@ -27,4 +27,4 @@ rm -f ${ANDROID_OUTPUT_APK_RELEASE}/*.apk*

echo "Running cordova build android..."
ionic cordova build android --warning-mode=none --color $* -- -- --packageType=apk
#ionic cordova build android --warning-mode=none --color --verbose -- -- --packageType=apk
#ionic cordova build android --warning-mode=none --color --verbose -- -- --packageType=apk --stacktrace --debug
Original line number Diff line number Diff line
#!/bin/sh

# Get to the root project
if [[ "_" == "_${PROJECT_DIR}" ]]; then
  SCRIPT_DIR=$(dirname "$(readlink "$BASH_SOURCE" || echo "$BASH_SOURCE")")
  PROJECT_DIR=$(cd "${SCRIPT_DIR}/.." && pwd -P)
  export PROJECT_DIR

fi;

# Preparing environment
. "${PROJECT_DIR}/scripts/env-global.sh"
@@ -74,6 +75,7 @@ fi
# Copy local files
ANDROID_OVERWRITE_DIR=${PROJECT_DIR}/.local/android
if test -d "${ANDROID_OVERWRITE_DIR}"; then
  echo ""
  echo "Copying files from directory '${ANDROID_OVERWRITE_DIR}' into '${PROJECT_DIR}/platforms/android'..."
  cp -rf ${ANDROID_OVERWRITE_DIR}/* ${PROJECT_DIR}/platforms/android
  if test $? -ne 0; then
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ NODE_VERSION=16
IONIC_CLI_VERSION=6.20.9

ANDROID_NDK_VERSION=21.0.6113669 # Should be compatible with 'cordova-sqlite-storage' plugin
ANDROID_SDK_VERSION=33.0.2
ANDROID_SDK_VERSION=35.0.0
ANDROID_SDK_CLI_VERSION=8512546 # See https://developer.android.com/studio#command-tools
ANDROID_SDK_ROOT="${HOME}/Android/Sdk"
ANDROID_ALTERNATIVE_SDK_ROOT=/usr/lib/android-sdk
@@ -48,7 +48,7 @@ WEB_EXT_ID=${WEB_EXT_ID:-"{6f9922f7-a054-4609-94ce-d269993246a5}"}
# /!\ WARN can be define in your <project>/.local/env.sh file
#JAVA_HOME=

GRADLE_VERSION=6.7.1
GRADLE_VERSION=8.7
GRADLE_HOME=${HOME}/.gradle/${GRADLE_VERSION}
CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL=https://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-all.zip
GRADLE_OPTS=-Dorg.gradle.jvmargs=-Xmx512m
@@ -72,14 +72,13 @@ if test -d "${JAVA_HOME}"; then
  # Check the Java version
  JAVA_VERSION=$(java -version 2>&1 | egrep "(java|openjdk) version" | awk '{print $3}' | tr -d \")
  if test $? -ne 0 || test -z "${JAVA_VERSION}"; then
    echo "No Java JRE 1.8 found in machine. This is required for Android artifacts."
    echo "No Java JDK 17 found in machine. This is required for Android artifacts."
  else
    if ! test "${JAVA_VERSION}" -eq "11"; then
    JAVA_MAJOR_VERSION=$(echo ${JAVA_VERSION} | awk '{split($0, array, ".")} END{print array[1]}')
    JAVA_MINOR_VERSION=$(echo ${JAVA_VERSION} | awk '{split($0, array, ".")} END{print array[2]}')
      if ! test "${JAVA_MAJOR_VERSION}" -eq "11" || ! test "${JAVA_MINOR_VERSION}" -eq "0"; then
        echo "ERROR: Require a Java SDK in version 11, but found ${JAVA_VERSION}. You can override your default JAVA_HOME in '.local/env.sh'."
      fi
    if test ${JAVA_MAJOR_VERSION} -ne 17; then
      echo "ERROR: Require a Java JDK in version 17.0, but found ${JAVA_MAJOR_VERSION}.${JAVA_MINOR_VERSION} - You can override your default JAVA_HOME in '.local/env.sh'."
      #exit 1
    fi
  fi
fi
@@ -183,7 +182,7 @@ export PATH \
  NODE_VERSION \
  JAVA_HOME \
  ANDROID_NDK_VERSION ANDROID_SDK_VERSION ANDROID_SDK_CLI_VERSION \
  ANDROID_HOME ANDROID_SDK_ROOT ANDROID_ALTERNATIVE_SDK_ROOT ANDROID_SDK_CLI_ROOT \
  ANDROID_SDK_ROOT ANDROID_SDK_ROOT ANDROID_ALTERNATIVE_SDK_ROOT ANDROID_SDK_CLI_ROOT \
  ANDROID_OUTPUT_APK ANDROID_OUTPUT_APK_DEBUG ANDROID_OUTPUT_APK_RELEASE \
  CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL \
  GRADLE_HOME GRADLE_OPTS \
Original line number Diff line number Diff line
@@ -53,7 +53,7 @@ echo y | sdkmanager "build-tools;${ANDROID_SDK_VERSION}" --sdk_root=${ANDROID_SD
[[ $? -ne 0 ]] && exit 1

# Install platforms
TARGET_VERSIONS="22 23 24 25 26 27 28 29 30 31 32 33"
TARGET_VERSIONS="22 23 24 25 26 27 28 29 30 31 32 33 34 35"
for TARGET_VERSION in $TARGET_VERSIONS
do
  echo "-------------------------------------------"
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@ async function lintFolder(dir) {

function lintFile(file) {
  return new Promise((resolve, reject) => {
    log(colors.grey('Processing file ./' + file + '...'));
    log(colors.grey('Processing file ' + file + '...'));
    fs.readFile(file, (err, data) => {
      if(err) {
        log(colors.red('Error: ' + err));
Original line number Diff line number Diff line
@@ -40,11 +40,17 @@ if [[ "_" == "_${AMO_JWT_ISSUER}" || "_" == "_${AMO_JWT_SECRET}" ]]; then
    exit 1
fi

nvm use 20

webExtVersion=$(web-ext --version)
echo "Web-Ext version: ${webExtVersion}"

### Sign extension
case "$1" in
  pre)
      echo "web-ext sign \"--api-key=${AMO_JWT_ISSUER}\" \"--api-secret=${AMO_JWT_SECRET}\" \"--source-dir=${PROJECT_DIR}/dist/web/ext\" \"--artifacts-dir=${PROJECT_DIR}/dist/web/build\"  --id=${WEB_EXT_ID} --channel=unlisted"
      web-ext sign "--api-key=${AMO_JWT_ISSUER}" "--api-secret=${AMO_JWT_SECRET}" "--source-dir=${PROJECT_DIR}/dist/web/ext" "--artifacts-dir=${PROJECT_DIR}/dist/web/build"  --id=${WEB_EXT_ID} --channel=unlisted
      #echo "web-ext sign \"--api-key=${AMO_JWT_ISSUER}\" \"--api-secret=${AMO_JWT_SECRET}\" \"--source-dir=${PROJECT_DIR}/dist/web/ext\" \"--artifacts-dir=${PROJECT_DIR}/dist/web/build\" --channel=unlisted"
      npx web-ext sign --upload-source-code "--api-key=${AMO_JWT_ISSUER}" "--api-secret=${AMO_JWT_SECRET}" "--source-dir=${PROJECT_DIR}/dist/web/ext" "--artifacts-dir=${PROJECT_DIR}/dist/web/build" --channel=unlisted

      if [[ $? -ne 0 ]]; then
        if [[ -f "${XPI_FILE}" || -f "${XPI_FINAL_FILE}" ]]; then
          echo "WARN: web-ext failed! Continue anyway, because output file exists"
@@ -54,7 +60,8 @@ case "$1" in
      fi
    ;;
  rel)
      web-ext sign "--api-key=${AMO_JWT_ISSUER}" "--api-secret=${AMO_JWT_SECRET}" "--source-dir=${PROJECT_DIR}/dist/web/ext" "--artifacts-dir=${PROJECT_DIR}/dist/web/build"  --id=${WEB_EXT_ID} --channel=listed
      web-ext sign --no-config-discovery --upload-source-code "--api-key=${AMO_JWT_ISSUER}" "--api-secret=${AMO_JWT_SECRET}" "--source-dir=${PROJECT_DIR}/dist/web/ext" "--artifacts-dir=${PROJECT_DIR}/dist/web/build" --channel=listed

      # Comment out, because always failed with message:
      #   "Your add-on has been submitted for review. It passed validation but could not be automatically signed because this is a listed add-on."
      #if [[ $? -ne 0 ]]; then
Original line number Diff line number Diff line
@@ -158,6 +158,22 @@ else
  missing_file=true
fi


# Upload chrome extension (XPI) file
CHROME_EXT_BASENAME="${PROJECT_NAME}-v$current-extension-chrome.zip"
CHROME_EXT_FILE="${DIST_WEB}/${CHROME_EXT_BASENAME}"
if [[ -f "${CHROME_EXT_FILE}" ]]; then
  result=$(curl -s -H ''"$GITHUT_AUTH"'' -H 'Content-Type: application/zip' -T "${CHROME_EXT_FILE}" "${upload_url}?name=${CHROME_EXT_BASENAME}")
  browser_download_url=$(echo "$result" | grep -P "\"browser_download_url\":[ ]?\"[^\"]+" | grep -oP "\"browser_download_url\":[ ]?\"[^\"]+"  | grep -oP "https://[A-Za-z0-9/.-]+")
  CHROME_EXT_SHA256=$(cd ${DIST_WEB} && sha256sum "${CHROME_EXT_BASENAME}")
  echo " - ${browser_download_url}  | Checksum: ${CHROME_EXT_SHA256}"
  echo "${CHROME_EXT_SHA256}  ${CHROME_EXT_BASENAME}" > "${CHROME_EXT_FILE}.sha256"
  result=$(curl -s -H ''"$GITHUT_AUTH"'' -H 'Content-Type: text/plain' -T "${CHROME_EXT_FILE}.sha256" "${upload_url}?name=${CHROME_EXT_BASENAME}.sha256")
else
  echo " - ERROR: Chrome signed extension artifact not found! Skipping."
  missing_file=true
fi

# Upload Android APK file
APK_BASENAME="${PROJECT_NAME}-v${current}-android.apk"
APK_FILE="${DIST_ANDROID}/${APK_BASENAME}"
Original line number Diff line number Diff line
@@ -91,7 +91,7 @@ echo "- Building Android artifact..."
echo "----------------------------------"
cd ${PROJECT_DIR}/scripts || exit 1
./release-android.sh
#[[ $? -ne 0 ]] && exit 1
[[ $? -ne 0 ]] && exit 1


echo "----------------------------------"
@@ -109,6 +109,9 @@ gulp webBuild --release
gulp webExtBuild --release
[[ $? -ne 0 ]] && exit 1

gulp chromeExtBuild --release
[[ $? -ne 0 ]] && exit 1

# check files exists
DIST_WEB_FILE="${DIST_WEB}/${PROJECT_NAME}-v$2-web.zip"
if [[ ! -f "${DIST_WEB_FILE}" ]]; then
@@ -120,6 +123,11 @@ if [[ ! -f "${DIST_WEB_EXT_FILE}" ]]; then
  echo "ERROR: Missing web-ext artifact at ${DIST_WEB_EXT_FILE}"
  exit 1
fi;
DIST_CHROME_EXT_FILE="${DIST_WEB}/${PROJECT_NAME}-v$2-extension-chrome.zip"
if [[ ! -f "${DIST_CHROME_EXT_FILE}" ]]; then
  echo "ERROR: Missing chrome-ext artifact at ${DIST_CHROME_EXT_FILE}"
  exit 1
fi;

echo "----------------------------------"
echo "- Executing git push, with tag: v$2"

web-ext-config.js

deleted100644 → 0
+0 −4
Original line number Diff line number Diff line
module.exports = {
  "sourceDir": "dist/web/ext/",
  "artifactsDir": "dist/web/build/"
};
Original line number Diff line number Diff line
@@ -80,8 +80,8 @@ angular.module("cesium.config", [])
			"defaultCountry": "France"
		}
	},
	"version": "1.7.13",
	"build": "2024-01-03T17:45:14.686Z",
	"version": "1.7.16.2",
	"build": "2025-09-05T16:31:41.957Z",
	"newIssueUrl": "https://git.duniter.org/clients/cesium-grp/cesium/issues/new"
})

+14 −2
Original line number Diff line number Diff line
@@ -85,6 +85,18 @@ angular.module("cesium.config", [])
		{
			"host": "g1.le-sou.org",
			"port": 443
		},
		{
			"host": "duniter.pini.fr",
			"port": 443
		},
		{
			"host": "g1.moul.re",
			"port": 443
		},
		{
			"host": "duniter-v1.comunes.net",
			"port": 443
		}
	],
	"developers": [
@@ -147,8 +159,8 @@ angular.module("cesium.config", [])
			"defaultCountry": "France"
		}
	},
	"version": "1.7.13",
	"build": "2024-01-03T17:45:14.673Z",
	"version": "1.7.16.2",
	"build": "2025-09-05T16:31:41.947Z",
	"newIssueUrl": "https://git.duniter.org/clients/cesium-grp/cesium/issues/new"
})

Original line number Diff line number Diff line
@@ -367,12 +367,13 @@ function AppController($scope, $rootScope, $state, $ionicSideMenuDelegate, $q, $

  // WARN: publish to root scope, to make sure popover (with new scope) can use it
  $rootScope.openLink = function($event, uri, options) {
    if ($event.defaultPrevented) return false;
    $event.stopPropagation();
    $event.preventDefault();

    // Read URL like '@UID' (Used by home page, in feed's author url)
    if (uri && uri.startsWith('@')) {
      var uid = uri.substr(1);
      var uid = uri.substring(1);
      if (BMA.regexp.USER_ID.test(uid)) {
        $state.go('app.wot_identity_uid', {uid: uid});
        return false;
@@ -529,9 +530,14 @@ function AppController($scope, $rootScope, $state, $ionicSideMenuDelegate, $q, $
  };

  $scope.registerProtocolHandlers = function() {
    if (csConfig.demo) return; // Skip if demo
    // Protocol handlers are not supported in Chrome extensions
    if (window.chrome && chrome.runtime && chrome.runtime.id) {
      console.debug("Running as a browser extension, skipping protocol handler registration.");
      return;
    }

    var protocols = ['web+june'];
    var protocolHandlers = csConfig.protocolHandlers || {};
    var protocols = Object.keys(protocolHandlers);

    _.each(protocols, function(protocol) {
      console.debug("[app] Registering protocol '{0}'...".format(protocol));
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@ var App;

angular.module('cesium.device.services', ['cesium.utils.services', 'cesium.settings.services'])

  .factory('Device', function ($rootScope, $translate, $timeout, $ionicPopup, $q, Api, csConfig,
  .factory('Device', function ($rootScope, $translate, $timeout, $ionicPopup, $q, $window, Api, csConfig,
                               // removeIf(no-device)
                               $cordovaClipboard, $cordovaBarcodeScanner, $cordovaCamera, $cordovaNetwork,
                               // endRemoveIf(no-device)
@@ -514,6 +514,22 @@ angular.module('cesium.device.services', ['cesium.utils.services', 'cesium.setti
      return !!navigator.userAgent.match(/Macintosh/i) || ionic.Platform.is("osx");
    };

    exports.isMobile = function () {
      return exports.isAndroid() || exports.isIOS();
    };

    exports.isChromeExtension = function () {
      return window.location.protocol === 'chrome-extension:' && chrome && chrome.storage && chrome.storage.local;
    };

    exports.isMozillaExtension = function () {
      return window.location.protocol === 'moz-extension:';
    };

    exports.isWebExtension = function () {
      return exports.isChromeExtension() || exports.isMozillaExtension();
    };

    exports.isIOS = function () {
      return !!navigator.userAgent.match(/iPhone | iPad | iPod/i) || (!!navigator.userAgent.match(/Mobile/i) && !!navigator.userAgent.match(/Macintosh/i)) || ionic.Platform.isIOS();
    };
@@ -589,6 +605,7 @@ angular.module('cesium.device.services', ['cesium.utils.services', 'cesium.setti
            if (cordova.InAppBrowser) {
              console.debug('[device] Enabling InAppBrowser');
              window.open = cordova.InAppBrowser.open;
              $window.open = cordova.InAppBrowser.open;
            }

            // Add network listeners, using cordova network plugin
Original line number Diff line number Diff line
@@ -476,29 +476,26 @@ angular.module('cesium.http.services', ['cesium.cache.services'])
    var openTarget = (options.target || (Device.enable ? '_system' : '_blank'));

    // If desktop, try to open into external browser
    if (openTarget === '_blank' || openTarget === '_system'  && Device.isDesktop()) {
    if ((openTarget === '_blank' || openTarget === '_system') && Device.isDesktop()) {
      try {
        nw.Shell.openExternal(uri);
        return;
        return false;
      }
      catch(err) {
        console.error("[http] Failed not open URI into external browser.");
      }
    }

    // If desktop, should always open in new window (no tabs)
    var openOptions;
    if (openTarget === '_blank' && Device.isDesktop()) {

      if (nw && nw.Shell) {
        nw.Shell.openExternal(uri);
        return false;
      }
    var centerWindow = false;
    var openOptions = typeof options === 'string' ? options : undefined;
    if (!openOptions && openTarget === '_blank' && Device.isDesktop()) {
      // Override default options
      openOptions = "location=1,titlebar=1,status=1,menubar=1,toolbar=1,resizable=1,scrollbars=1";

      // Add width/height
      if ($window.screen && $window.screen.width && $window.screen.height) {
        openOptions += ",width={0},height={1}".format(Math.trunc($window.screen.width/2), Math.trunc($window.screen.height/2));
        centerWindow = true;
      }
    }

@@ -507,7 +504,7 @@ angular.module('cesium.http.services', ['cesium.cache.services'])
      openOptions);

    // Center the opened window
    if (openOptions && $window.screen && $window.screen.width && $window.screen.height) {
    if (win && centerWindow && $window.screen && $window.screen.width && $window.screen.height) {
      win.moveTo($window.screen.width/2/2, $window.screen.height/2/2);
      win.focus();
    }
Original line number Diff line number Diff line
@@ -395,6 +395,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services',
      var peers = createPeerEntities(json);
      var hasUpdates = false;
      var pid = data.pid;
      var running = true;

      var jobs = peers.reduce(function(jobs, peer) {
          var existingPeer = _.findWhere(data.peers, {id: peer.id});
@@ -404,6 +405,9 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services',
          return jobs.concat(
            refreshPeer(peer)
              .then(function (refreshedPeer) {
                running = running && data.listeners && data.listeners.length > 0;
                if (!running) return; // Skip if stopped

                var api = refreshedPeer &&
                  refreshedPeer.bma && (
                    (refreshedPeer.bma.useBma && 'BMA') ||
@@ -416,7 +420,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services',
                  if (!refreshedPeer || (refreshedPeer.online !== data.filter.online && data.filter.online !== 'all')) {
                    var existingIndex = data.peers.indexOf(existingPeer);
                    if (existingIndex !== -1) {
                      console.debug('[network] [#{0}] Peer [{1}] removed (cause: {2})'.format(pid, peer.server, !refreshedPeer ? 'filtered' : (refreshedPeer.online ? 'UP' : 'DOWN')));
                      if (!stop) console.debug('[network] [#{0}] Peer [{1}] removed (cause: {2})'.format(pid, peer.server, !refreshedPeer ? 'filtered' : (refreshedPeer.online ? 'UP' : 'DOWN')));
                      data.peers.splice(existingIndex, 1);
                      hasUpdates = true;
                    }
@@ -458,7 +462,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services',
      }, []);
      return (jobs.length === 1 ? jobs[0] : $q.all(jobs))
        .then(function() {
          return hasUpdates;
          return !stop && hasUpdates;
        });
    },

@@ -1034,7 +1038,10 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services',
              checkEnoughListener();
              checkEnoughListener = null;

              console.debug('[network] [#{0}] Found enough peers on main consensus - in {1}ms (timeout {2}ms) '.format(pid, Date.now() - data.startTime, options.timeout));
              console.debug('[network] [#{0}] Found enough peers on main consensus ({1} peers)- in {2}ms (timeout {3}ms) '.format(pid,
                consensusPeerCount,
                Date.now() - data.startTime,
                options.timeout));
              deferred.resolve(peers);
            }
          }
Original line number Diff line number Diff line

angular.module('cesium.settings.services', ['ngApi', 'cesium.config'])

.factory('csSettings', function($rootScope, $q, $window, $timeout, Api, localStorage, $translate, csConfig) {
.factory('csSettings', function($rootScope, $q, $window, $timeout, Api, localStorage, extensionStorage, $translate, csConfig, Device) {
  'ngInject';

  // Define app locales
@@ -206,24 +206,35 @@ angular.module('cesium.settings.services', ['ngApi', 'cesium.config'])

    var promise;
    if (data.useLocalStorage) {
      var savedData = data;
      // When node is temporary (fallback node): keep previous node address - issue #476
      if (data.node && data.node.temporary === true) {
        promise = localStorage.getObject(constants.STORAGE_KEY)
          .then(function(previousSettings) {
            var savedData = angular.copy(data);
            savedData = angular.copy(data);
            savedData.node = previousSettings && previousSettings.node || {};
            delete savedData.temporary; // never store temporary flag

            return localStorage.setObject(constants.STORAGE_KEY, savedData);
          });
      }
      else {
        promise = localStorage.setObject(constants.STORAGE_KEY, data);
        promise = localStorage.setObject(constants.STORAGE_KEY, savedData);
      }
    }
    else {
      savedData = null;
      promise  = localStorage.setObject(constants.STORAGE_KEY, null);
    }

    // If web extension: store in the extension storage (need by the service worker - see background.js)
    if (Device.isWebExtension()) {
      promise = $q.all([
        promise,
        extensionStorage.setObject(constants.STORAGE_KEY, savedData)
      ]);
    }

    return promise
      .then(function() {
        if (data.useLocalStorage) {
Original line number Diff line number Diff line
@@ -280,4 +280,29 @@ angular.module('cesium.storage.services', [ 'cesium.config'])
  })


  .factory('extensionStorage', function($window, $q, $log, Device) {
    'ngInject';

    var exports = {};

    exports.put = function(key, value) {
      var entry = {};
      entry[key] = value;
      if (Device.isChromeExtension()) {
        return new Promise(function(resolve, reject) {
          chrome.storage.local.set(entry, resolve);
        })
      } else if (Device.isMozillaExtension()) {
        $log.debug('[extension-storage] Add storage into Mozilla storage');
      }
      return $q.when();
    }

    exports.setObject = function(key, obj) {
      var strValue = obj ? JSON.stringify(obj) : null;
      return exports.put(key, strValue);
    }

    return exports;
  })
;
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se


.factory('csWallet', function($q, $rootScope, $timeout, $translate, $filter, $ionicHistory, UIUtils,
                              Api, Idle, localStorage, sessionStorage, Modals, Device,
                              Api, Idle, localStorage, sessionStorage, extensionStorage, Modals, Device,
                              CryptoUtils, csCrypto, BMA, csConfig, csSettings, FileSaver, csWot, csTx, csCurrency) {
  'ngInject';

@@ -417,6 +417,11 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
          // Use local storage for pubkey
          jobs.push(localStorage.put(constants.STORAGE_PUBKEY, data.pubkey));

          // If web extension: store in the extension storage (need by the service worker - see background.js)
          if (Device.isWebExtension()) {
            jobs.push(extensionStorage.put(constants.STORAGE_PUBKEY, data.pubkey));
          }

          // Use local storage for uid - fix #625
          if (data.uid) {
            jobs.push(localStorage.put(constants.STORAGE_UID, data.uid));
@@ -435,6 +440,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
          return $q.all([
            sessionStorage.put(constants.STORAGE_SECKEY, null),
            localStorage.put(constants.STORAGE_PUBKEY, null),
            extensionStorage.put(constants.STORAGE_PUBKEY, null),
            localStorage.put(constants.STORAGE_UID, null),
            // Clean data (only in the session storage - keep local)
            pubkey ? sessionStorage.put(constants.STORAGE_DATA_PREFIX + pubkey, null) : $q.when()
Original line number Diff line number Diff line
Licence Ğ1 - v0.2.9
Licence Ğ1 - v0.3.0
===================

:Date: 2017-04-04 12:59
:Modified: 2021-04-20 21:00
:Modified: 2025-02-11 21:30

**Licence de la monnaie et engagement de responsabilité.**

@@ -95,3 +95,33 @@ Les logiciels Ğ1 permettant aux utilisateurs de gérer leur utilisation de Ğ1
Pour plus de précisions dans les détails techniques il est possible de consulter directement le code de Duniter qui est un logiciel libre ainsi que les données de la blockchain Ğ1 en les récupérant via une instance (ou nœud) Duniter Ğ1.

Plus d'informations sur le site de l'équipe Duniter https://www.duniter.org

Règles de modifications du présent document
-------------------------------------------

**Note introductive :**

Les personnes qui émettent des propositions, qui les soutiennent ou qui les votent doivent être membres de la TDC.

**Processus :**

1. Étape optionelle : Il est possible de partager son processus d'élaboration d'une proposition sur les plateformes de communication de la Ǧ1 (forum Monnaie Libre, forum Duniter, Télégram monnaie libre...).

2. Quand une proposition est considérée comme finalisée, il faut :

   - Créer un compte portefeuille pour chaque option : un "pour", un "contre".
   - Créer dans la catégorie dédiée du forum monnaie libre un sujet reprenant la proposition finale suivie des clefs publiques associées à chaque option.
   - Toute modification (réédition) du texte de la proposition finale entraine l'annulation du vote.

3. Les personnes votantes sont invitées à se prononcer par virement depuis leur compte membre vers le compte associé à leur choix de vote (le montant est ignoré). Si un compte membre émet plusieurs virements vers un même compte, un seul vote sera comptabilisé. Des virements du même compte membre vers les deux comptes ("pour" et "contre") sont considérés comme nuls.

4. 30 jours après publication de la proposition finale sur le forum les résultats du vote sont dépouillés :

   - Si la proposition a récolté au moins 20 votes/virements "pour" et aucun vote "contre", elle est adoptée.
   - Pour chaque vote "contre", 5 votes "pour" supplémentaires sont nécessaires pour que la proposition puisse être adoptée. (25 "pour" si 1 "contre", 30 "pour" si 2 "contre"...)
   - Si les conditions d'adoption ne sont pas réunies, la proposition est rejetée.

Une fois le vote clos, les Ǧ1 versées à l'occasion des votes peuvent être reversées ou non à une caisse (Mégadon, soutiens aux devs, remuniter...). Cela n'impacte pas la validité du vote.

Si vous avez besoin d'aide pour suivre ce processus de mise au vote, rendez-vous sur :
[Comment mettre au vote une proposition d'évolution ?](https://forum.monnaie-libre.fr/t/a-propos-de-la-categorie-modifications-de-la-licence/31065)
 No newline at end of file
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
  "short_name": "Cesium",
  "name": "Cesium",
  "manifest_version": 1,
  "version": "1.7.13",
  "version": "1.7.16",
  "default_locale": "fr",
  "description": "Cesium Wallet for Ğ1 libre currency",
  "icons": [
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic
 * Elastic Search Http
 */
.factory('esHttp', function($q, $timeout, $rootScope, $state, $sce, $translate, $window, $filter,
                            CryptoUtils, UIUtils, csHttp, csConfig, csSettings, csCache, BMA, csWallet, csPlatform, Api) {
                            CryptoUtils, UIUtils, Device, csHttp, csConfig, csSettings, csCache, BMA, csWallet, csPlatform, Api) {
  'ngInject';

  // Allow to force SSL connection with port different from 443
@@ -471,9 +471,9 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic
        var urls = parseUrlsFromText(content);
        _.forEach(urls, function(url){
          // Make sure protocol is defined
          var href = (url.startsWith('http://') || url.startsWith('https://')) ? url : ('http://' + url);
          var href = (url.startsWith('http://') || url.startsWith('https://')) ? url : ('https://' + url);
          // Redirect URL to the function 'openLink', to open a new window if need (e.g. desktop app)
          var link = '<a on-tap=\"openLink($event, \'{0}\')\" href=\"{1}\" target="_blank">{2}</a>'.format(href, href, truncUrlFilter(url));
          var link = '<a ng-click=\"openLink($event, \'{0}\')\" href=\"{1}\" target="_blank">{2}</a>'.format(href, href, truncUrlFilter(url));
          content = content.replace(url, link);
        });

Original line number Diff line number Diff line
@@ -99,7 +99,7 @@
        <ion-item>
          <h4 ng-if="formData.address">
            <span class="gray" translate>REGISTRY.VIEW.LOCATION</span>
            <a class="positive" target='_blank' href="https://www.google.fr/maps/?q={{formData.address}},%20{{formData.city}}">
            <a class="positive" target='_system' href="https://www.google.fr/maps/?q={{formData.address}},%20{{formData.city}}">
              <span ng-bind-html="formData.address"></span>
              <span ng-if="formData.city"> - </span>
              <span ng-bind-html="formData.city"></span>
@@ -117,7 +117,7 @@
               ng-class="{'ion-bookmark': social.type == 'other', 'ion-link': social.type == 'web', 'ion-email': social.type == 'email'}"></i>
            <p ng-if="social.type && social.type != 'web'">{{social.type}}</p>
            <h2>
              <a href="{{social.url}}" ng-if="social.type != 'email'" target="_blank">{{social.url}}</a>
              <a href="{{social.url}}" ng-if="social.type != 'email'" target="_system">{{social.url}}</a>
              <a href="mailto:{{social.url}}" ng-if="social.type == 'email'">{{social.url}}</a>
            </h2>
          </ion-item>
Original line number Diff line number Diff line
@@ -133,13 +133,18 @@
        <div class="item" ng-if="formData.category || formData.address">
          <h4 ng-if="formData.category">
            <span class="gray" translate>REGISTRY.VIEW.CATEGORY</span>
            <a class="positive" ng-if="formData.category" ui-sref="app.wot_lookup.tab_registry({category:formData.category.id})">
            <span class="positive visible-xs visible-sm" ng-bind-html="formData.category.name"></span>
            <a class="positive hidden-xs hidden-sm"
               ui-sref="app.wot_lookup.tab_registry({category:formData.category.id})">
              <span ng-bind-html="formData.category.name"></span>
            </a>
          </h4>
          <h4 ng-if="formData.address">
            <span class="gray" translate>REGISTRY.VIEW.LOCATION</span>
            <a class="positive" target="_system" href="https://www.openstreetmap.org/search?query={{formData.address}},%20{{formData.city}}">
            <a class="positive" target="_blank"
               href="https://www.openstreetmap.org/search?query={{formData.address}},%20{{formData.city}}"
               ng-click="openLink($event, 'https://www.openstreetmap.org/search?query={{formData.address}},%20{{formData.city}}')"
            >
              <span ng-bind-html="formData.address"></span>
              <span ng-if="formData.city"> - </span>
              <span ng-bind-html="formData.city"></span>
@@ -191,5 +196,4 @@
          ng-click="showTransferModal({pubkey: formData.pubkey, uid: formData.title})">
  </button>


</ion-view>
Original line number Diff line number Diff line
@@ -38,8 +38,8 @@
        {{social.type}}
        <i class="ion-locked" ng-if="social.recipient"></i>
      </p>
      <h4>
        <a on-tap="openSocial($event, social)" href="{{::social.url}}" target="_blank">{{::social.url}}</a>
      <h4 class="positive">
        <a ng-click="$event.preventDefault()" href="{{::social.url}}" target="_blank">{{::social.url}}</a>
      </h4>
    </ion-item>
  </div>
Original line number Diff line number Diff line
@@ -15,25 +15,19 @@

        <a class="button button-icon positive icon ion-social-facebook"
           href="https://www.facebook.com/sharer/sharer.php?u={{postUrl|formatEncodeURI}}&amp;title={{postMessage|formatEncodeURI}}"
           onclick="window.open(this.href, 'facebook-share','menubar=no,toolbar=no,resizable=yes,scrollbars=yes,width=580,height=296');return false;"
           onclick="window.open(this.href, '_system','menubar=no,toolbar=no,resizable=yes,scrollbars=yes,width=580,height=296');return false;"
           title="{{'COMMON.POPOVER_SHARE.SHARE_ON_FACEBOOK'|translate}}">
        </a>

        <a class="button button-icon positive icon ion-social-twitter"
           href="https://twitter.com/intent/tweet?url={{postUrl|formatEncodeURI}}&amp;text={{postMessage|formatEncodeURI}}"
           onclick="window.open(this.href, 'twitter-share','menubar=no,toolbar=no,resizable=yes,scrollbars=yes,width=580,height=296');return false;"
           href="https://x.com/intent/tweet?url={{postUrl|formatEncodeURI}}&amp;text={{postMessage|formatEncodeURI}}"
           onclick="window.open(this.href, '_system','menubar=no,toolbar=no,resizable=yes,scrollbars=yes,width=580,height=296');return false;"
           title="{{'COMMON.POPOVER_SHARE.SHARE_ON_TWITTER'|translate}}">
        </a>

        <a class="button button-icon positive icon ion-social-googleplus"
           href="https://plus.google.com/share?url={{postUrl|formatEncodeURI}}"
           onclick="window.open(this.href, 'google-plus-share', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=296,width=580');return false;"
           title="{{'COMMON.POPOVER_SHARE.SHARE_ON_GOOGLEPLUS'|translate}}">
        </a>

        <a class="button button-icon positive icon ion-social-diaspora"
           href="https://sharetodiaspora.github.io/?title={{postMessage|formatEncodeURI}}&amp;url={{postUrl|formatEncodeURI}}"
           onclick="window.open(this.href, 'diaspora-share','menubar=no,toolbar=no,resizable=yes,scrollbars=yes,width=580,height=296');return false;"
           onclick="window.open(this.href, '_system','menubar=no,toolbar=no,resizable=yes,scrollbars=yes,width=580,height=296');return false;"
           title="{{'COMMON.POPOVER_SHARE.SHARE_ON_DIASPORA'|translate}}">
        </a>

+1546 −1519

File changed.

Preview size limit exceeded, changes collapsed.