// Le transport Gitea : reconnaissance de l'URL, et lecture de la reponse de // l'API des contenus. // // POURQUOI CES DEUX-LA. `giteaUnwrap` est le seul endroit du chemin de sync qui // interprete du JSON venu du reseau, et il decide de ce qui sera ensuite // dechiffre. Une URL a un segment pres rend du JSON valide qui n'est PAS un // fichier ; s'il passait, l'erreur ne se verrait qu'au message // « mot de passe de sync incorrect », qui envoie chercher la cause ailleurs. // // Le `sha` compte autant que le contenu : il repart en `sha` au push, et c'est // lui qui fait refuser une ecriture concurrente. Le rendre vide plutot // qu'absent ferait ecraser la version d'un autre appareil. const test = require('node:test'); const assert = require('node:assert'); const { loadApp } = require('./harness'); function b64(text) { return Buffer.from(text, 'utf8').toString('base64'); } test('syncIsGitea: recognises a contents-API URL, ignores WebDAV', async () => { const { __test: t } = await loadApp(); assert.equal(t.syncIsGitea( 'https://git.example.com/api/v1/repos/Zaki/pm_sync/contents/vault-sync.json'), true); // Casse indifferente : l'URL est saisie a la main. assert.equal(t.syncIsGitea( 'https://git.example.com/API/V1/REPOS/Zaki/pm_sync/contents/v.json'), true); // Une URL de depot n'est pas une URL d'API, et elle ne rendrait pas de sha. assert.equal(t.syncIsGitea('https://git.example.com/Zaki/pm_sync'), false); assert.equal(t.syncIsGitea('https://dav.example.com/remote.php/vault.json'), false); assert.equal(t.syncIsGitea(''), false); assert.equal(t.syncIsGitea(undefined), false); }); test('giteaUnwrap: returns the file and its sha', async () => { const { __test: t } = await loadApp(); const container = '{"version":1,"cipher":"AAAA"}'; const un = t.giteaUnwrap(JSON.stringify({ content: b64(container), encoding: 'base64', sha: 'abc123', name: 'vault-sync.json' })); assert.ok(un, 'devrait accepter une reponse bien formee'); assert.equal(un.container, container); assert.equal(un.sha, 'abc123'); }); test('giteaUnwrap: accepts the line-wrapped base64 Gitea sends', async () => { const { __test: t } = await loadApp(); const container = '{"version":1}'; // Gitea coupe son base64 en lignes ; un decodeur strict s'y casse. const wrapped = b64(container).replace(/(.{4})/, '$1\r\n'); const un = t.giteaUnwrap(JSON.stringify({ content: wrapped, encoding: 'base64', sha: 'deadbeef' })); assert.ok(un, 'les retours a la ligne ne doivent pas faire echouer le decodage'); assert.equal(un.container, container); }); test('giteaUnwrap: refuses anything that is not a file', async () => { const { __test: t } = await loadApp(); // Ce que rend une URL a un segment pres : du JSON valide, sans fichier. assert.equal(t.giteaUnwrap('{"message":"Not found"}'), null); // Un repertoire : l'API rend un TABLEAU, pas un objet. assert.equal(t.giteaUnwrap('[{"name":"vault-sync.json","sha":"x"}]'), null); // Un sha sans contenu ne permet rien de dechiffrer. assert.equal(t.giteaUnwrap('{"sha":"abc"}'), null); // Un contenu sans sha interdirait l'ecriture concurrente : refuse aussi. assert.equal(t.giteaUnwrap(JSON.stringify({ content: b64('{}') })), null); // Un encodage que nous ne savons pas lire. assert.equal(t.giteaUnwrap(JSON.stringify({ content: 'x', encoding: 'utf-8', sha: 'abc' })), null); // Pas du JSON du tout - une page d'erreur HTML, par exemple. assert.equal(t.giteaUnwrap('502'), null); assert.equal(t.giteaUnwrap(''), null); });