Changeset 1a2f206 in Klonkt


Ignore:
Timestamp:
07/30/2026 11:17:05 PM (6 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
ef519a3
Parents:
55eca8b
Message:

Follow: gesigneerd resolven, fouten naar de app, guardians ingelicht, volg-QR

Robins meldingen (31-7). Vier dingen aan de volg-kant.

Een: followActor haalde het actor-document anoniem op; een
authorized-fetch-instance weigert dat, waardoor volgen vanaf een boost
faalde. De fetch is nu gesigneerd als de eigen actor.

Twee: de C2S-ingest slikte followActor-fouten in en gaf altijd 202,
dus een mislukte follow zag er in de app uit als een gelukte. Fouten
komen nu als 502 follow_failed (met detail) bij de app aan, met test.

Drie: de guardians worden ingelicht als hun ward iemand gaat volgen:
een follow brengt nieuwe content het kind binnen, en het dorp hoort te
weten dat de deur openging. Een directe note per guardian,
best-effort. FEP-633c 5.3 gate't inkomende follows; deze uitgaande
melding is Shaer-beleid (spec-vraag als bead).

Vier: GET /ap/users/:slug/follow-qr.png serveert een QR-PNG van
share:social/follow/AP/@slug@host (npm qrcode, puur JS). Publiek met
opzet: er staat alleen de publieke handle in, en de plain image-loaders
van de apps dragen geen bearer.

Changed files:
src/services/ActivityPubService.js

  • followActor: signedGetJson voor het actor-doc; guardian-notice
  • C2S Follow-case: fouten door naar de app

src/routes/activitypub.js

  • follow-qr.png-route (cache 1 dag)

package.json / package-lock.json

  • qrcode-dependency

test/c2s-compose.test.js

  • onbereikbare follow geeft 502 follow_failed/unreachable

-robo
Co-Authored-By: Claude Opus 4.8 <noreply@…>

Files:
5 edited

Legend:

Unmodified
Added
Removed
  • package-lock.json

    r55eca8b r1a2f206  
    2929        "node-webpmux": "^3.2.1",
    3030        "nodemailer": "^6.9.15",
     31        "qrcode": "^1.5.4",
    3132        "sanitize-html": "^2.17.3",
    3233        "uuid": "^9.0.1",
     
    540541      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
    541542      "license": "MIT"
     543    },
     544    "node_modules/ansi-regex": {
     545      "version": "5.0.1",
     546      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
     547      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
     548      "license": "MIT",
     549      "engines": {
     550        "node": ">=8"
     551      }
     552    },
     553    "node_modules/ansi-styles": {
     554      "version": "4.3.0",
     555      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
     556      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
     557      "license": "MIT",
     558      "dependencies": {
     559        "color-convert": "^2.0.1"
     560      },
     561      "engines": {
     562        "node": ">=8"
     563      },
     564      "funding": {
     565        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
     566      }
    542567    },
    543568    "node_modules/append-field": {
     
    772797      }
    773798    },
     799    "node_modules/camelcase": {
     800      "version": "5.3.1",
     801      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
     802      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
     803      "license": "MIT",
     804      "engines": {
     805        "node": ">=6"
     806      }
     807    },
    774808    "node_modules/caseless": {
    775809      "version": "0.12.0",
     
    783817      "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
    784818      "license": "ISC"
     819    },
     820    "node_modules/cliui": {
     821      "version": "6.0.0",
     822      "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
     823      "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
     824      "license": "ISC",
     825      "dependencies": {
     826        "string-width": "^4.2.0",
     827        "strip-ansi": "^6.0.0",
     828        "wrap-ansi": "^6.2.0"
     829      }
     830    },
     831    "node_modules/color-convert": {
     832      "version": "2.0.1",
     833      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
     834      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
     835      "license": "MIT",
     836      "dependencies": {
     837        "color-name": "~1.1.4"
     838      },
     839      "engines": {
     840        "node": ">=7.0.0"
     841      }
     842    },
     843    "node_modules/color-name": {
     844      "version": "1.1.4",
     845      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
     846      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
     847      "license": "MIT"
    785848    },
    786849    "node_modules/concat-stream": {
     
    880943      }
    881944    },
     945    "node_modules/decamelize": {
     946      "version": "1.2.0",
     947      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
     948      "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
     949      "license": "MIT",
     950      "engines": {
     951        "node": ">=0.10.0"
     952      }
     953    },
    882954    "node_modules/decompress-response": {
    883955      "version": "6.0.0",
     
    9401012        "node": ">=8"
    9411013      }
     1014    },
     1015    "node_modules/dijkstrajs": {
     1016      "version": "1.0.3",
     1017      "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
     1018      "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==",
     1019      "license": "MIT"
    9421020    },
    9431021    "node_modules/dom-serializer": {
     
    10631141        "node": ">=0.10.0"
    10641142      }
     1143    },
     1144    "node_modules/emoji-regex": {
     1145      "version": "8.0.0",
     1146      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
     1147      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
     1148      "license": "MIT"
    10651149    },
    10661150    "node_modules/encodeurl": {
     
    13171401      }
    13181402    },
     1403    "node_modules/find-up": {
     1404      "version": "4.1.0",
     1405      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
     1406      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
     1407      "license": "MIT",
     1408      "dependencies": {
     1409        "locate-path": "^5.0.0",
     1410        "path-exists": "^4.0.0"
     1411      },
     1412      "engines": {
     1413        "node": ">=8"
     1414      }
     1415    },
    13191416    "node_modules/fluent-ffmpeg": {
    13201417      "version": "2.1.3",
     
    13671464      "funding": {
    13681465        "url": "https://github.com/sponsors/ljharb"
     1466      }
     1467    },
     1468    "node_modules/get-caller-file": {
     1469      "version": "2.0.5",
     1470      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
     1471      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
     1472      "license": "ISC",
     1473      "engines": {
     1474        "node": "6.* || 8.* || >= 10.*"
    13691475      }
    13701476    },
     
    16091715      }
    16101716    },
     1717    "node_modules/is-fullwidth-code-point": {
     1718      "version": "3.0.0",
     1719      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
     1720      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
     1721      "license": "MIT",
     1722      "engines": {
     1723        "node": ">=8"
     1724      }
     1725    },
    16111726    "node_modules/is-plain-object": {
    16121727      "version": "5.0.0",
     
    16661781        "jwa": "^2.0.1",
    16671782        "safe-buffer": "^5.0.1"
     1783      }
     1784    },
     1785    "node_modules/locate-path": {
     1786      "version": "5.0.0",
     1787      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
     1788      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
     1789      "license": "MIT",
     1790      "dependencies": {
     1791        "p-locate": "^4.1.0"
     1792      },
     1793      "engines": {
     1794        "node": ">=8"
    16681795      }
    16691796    },
     
    19422069      }
    19432070    },
     2071    "node_modules/p-limit": {
     2072      "version": "2.3.0",
     2073      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
     2074      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
     2075      "license": "MIT",
     2076      "dependencies": {
     2077        "p-try": "^2.0.0"
     2078      },
     2079      "engines": {
     2080        "node": ">=6"
     2081      },
     2082      "funding": {
     2083        "url": "https://github.com/sponsors/sindresorhus"
     2084      }
     2085    },
     2086    "node_modules/p-locate": {
     2087      "version": "4.1.0",
     2088      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
     2089      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
     2090      "license": "MIT",
     2091      "dependencies": {
     2092        "p-limit": "^2.2.0"
     2093      },
     2094      "engines": {
     2095        "node": ">=8"
     2096      }
     2097    },
     2098    "node_modules/p-try": {
     2099      "version": "2.2.0",
     2100      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
     2101      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
     2102      "license": "MIT",
     2103      "engines": {
     2104        "node": ">=6"
     2105      }
     2106    },
    19442107    "node_modules/parse-cache-control": {
    19452108      "version": "1.0.1",
     
    19602123      "engines": {
    19612124        "node": ">= 0.8"
     2125      }
     2126    },
     2127    "node_modules/path-exists": {
     2128      "version": "4.0.0",
     2129      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
     2130      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
     2131      "license": "MIT",
     2132      "engines": {
     2133        "node": ">=8"
    19622134      }
    19632135    },
     
    19732145      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
    19742146      "license": "ISC"
     2147    },
     2148    "node_modules/pngjs": {
     2149      "version": "5.0.0",
     2150      "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz",
     2151      "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==",
     2152      "license": "MIT",
     2153      "engines": {
     2154        "node": ">=10.13.0"
     2155      }
    19752156    },
    19762157    "node_modules/postcss": {
     
    20852266      }
    20862267    },
     2268    "node_modules/qrcode": {
     2269      "version": "1.5.4",
     2270      "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz",
     2271      "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==",
     2272      "license": "MIT",
     2273      "dependencies": {
     2274        "dijkstrajs": "^1.0.1",
     2275        "pngjs": "^5.0.0",
     2276        "yargs": "^15.3.1"
     2277      },
     2278      "bin": {
     2279        "qrcode": "bin/qrcode"
     2280      },
     2281      "engines": {
     2282        "node": ">=10.13.0"
     2283      }
     2284    },
    20872285    "node_modules/qs": {
    20882286      "version": "6.15.1",
     
    21672365      "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==",
    21682366      "license": "Apache-2.0"
     2367    },
     2368    "node_modules/require-directory": {
     2369      "version": "2.1.1",
     2370      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
     2371      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
     2372      "license": "MIT",
     2373      "engines": {
     2374        "node": ">=0.10.0"
     2375      }
     2376    },
     2377    "node_modules/require-main-filename": {
     2378      "version": "2.0.0",
     2379      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
     2380      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
     2381      "license": "ISC"
    21692382    },
    21702383    "node_modules/safe-buffer": {
     
    22652478      }
    22662479    },
     2480    "node_modules/set-blocking": {
     2481      "version": "2.0.0",
     2482      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
     2483      "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
     2484      "license": "ISC"
     2485    },
    22672486    "node_modules/setprototypeof": {
    22682487      "version": "1.2.0",
     
    24232642      }
    24242643    },
     2644    "node_modules/string-width": {
     2645      "version": "4.2.3",
     2646      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
     2647      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
     2648      "license": "MIT",
     2649      "dependencies": {
     2650        "emoji-regex": "^8.0.0",
     2651        "is-fullwidth-code-point": "^3.0.0",
     2652        "strip-ansi": "^6.0.1"
     2653      },
     2654      "engines": {
     2655        "node": ">=8"
     2656      }
     2657    },
     2658    "node_modules/strip-ansi": {
     2659      "version": "6.0.1",
     2660      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
     2661      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
     2662      "license": "MIT",
     2663      "dependencies": {
     2664        "ansi-regex": "^5.0.1"
     2665      },
     2666      "engines": {
     2667        "node": ">=8"
     2668      }
     2669    },
    24252670    "node_modules/strip-json-comments": {
    24262671      "version": "2.0.1",
     
    26582903      }
    26592904    },
     2905    "node_modules/which-module": {
     2906      "version": "2.0.1",
     2907      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
     2908      "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
     2909      "license": "ISC"
     2910    },
     2911    "node_modules/wrap-ansi": {
     2912      "version": "6.2.0",
     2913      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
     2914      "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
     2915      "license": "MIT",
     2916      "dependencies": {
     2917        "ansi-styles": "^4.0.0",
     2918        "string-width": "^4.1.0",
     2919        "strip-ansi": "^6.0.0"
     2920      },
     2921      "engines": {
     2922        "node": ">=8"
     2923      }
     2924    },
    26602925    "node_modules/wrappy": {
    26612926      "version": "1.0.2",
     
    26722937        "node": ">=0.4"
    26732938      }
     2939    },
     2940    "node_modules/y18n": {
     2941      "version": "4.0.3",
     2942      "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
     2943      "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
     2944      "license": "ISC"
     2945    },
     2946    "node_modules/yargs": {
     2947      "version": "15.4.1",
     2948      "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
     2949      "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
     2950      "license": "MIT",
     2951      "dependencies": {
     2952        "cliui": "^6.0.0",
     2953        "decamelize": "^1.2.0",
     2954        "find-up": "^4.1.0",
     2955        "get-caller-file": "^2.0.1",
     2956        "require-directory": "^2.1.1",
     2957        "require-main-filename": "^2.0.0",
     2958        "set-blocking": "^2.0.0",
     2959        "string-width": "^4.2.0",
     2960        "which-module": "^2.0.0",
     2961        "y18n": "^4.0.0",
     2962        "yargs-parser": "^18.1.2"
     2963      },
     2964      "engines": {
     2965        "node": ">=8"
     2966      }
     2967    },
     2968    "node_modules/yargs-parser": {
     2969      "version": "18.1.3",
     2970      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
     2971      "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
     2972      "license": "ISC",
     2973      "dependencies": {
     2974        "camelcase": "^5.0.0",
     2975        "decamelize": "^1.2.0"
     2976      },
     2977      "engines": {
     2978        "node": ">=6"
     2979      }
    26742980    }
    26752981  }
  • package.json

    r55eca8b r1a2f206  
    3434    "node-webpmux": "^3.2.1",
    3535    "nodemailer": "^6.9.15",
     36    "qrcode": "^1.5.4",
    3637    "sanitize-html": "^2.17.3",
    3738    "uuid": "^9.0.1",
  • src/routes/activitypub.js

    r55eca8b r1a2f206  
    121121  }
    122122  AP.sendAP(res, ob, audience === 'friend' ? 'private, no-store' : undefined);
     123});
     124
     125// ── Follow-QR (Robins verzoek, 31-7) ──────────────────────────────
     126// A PNG QR of share:social/follow/AP/@slug@host: the ward shows it in
     127// Account, a friend scans the SCREEN with the ordinary camera app and their
     128// Shaer opens with the follow question. Public on purpose: it encodes only
     129// the public handle, and the app's plain image loaders carry no bearer.
     130router.get('/ap/users/:slug/follow-qr.png', async (req, res) => {
     131  const site = db.prepare('SELECT slug FROM sites WHERE slug = ?').get(req.params.slug);
     132  if (!site) return res.status(404).end();
     133  try {
     134    const host = new URL(baseUrl(req)).host;
     135    const { default: QRCode } = await import('qrcode');
     136    const png = await QRCode.toBuffer(`share:social/follow/AP/@${site.slug}@${host}`, { width: 600, margin: 1 });
     137    res.set('Content-Type', 'image/png');
     138    res.set('Cache-Control', 'public, max-age=86400');
     139    res.send(png);
     140  } catch (e) {
     141    console.warn('[AP] follow-qr failed:', e && e.message);
     142    res.status(500).end();
     143  }
    123144});
    124145
  • src/services/ActivityPubService.js

    r55eca8b r1a2f206  
    23832383        const actorUri = c2sIdOf(object);
    23842384        if (!actorUri) return { status: 400, error: 'missing_object' };
    2385         await followActor(site, actorUri);
     2385        // The error REACHES the app (Robins melding, 31-7): swallowing it
     2386        // made a failed follow look exactly like a successful one.
     2387        const r = await followActor(site, actorUri);
     2388        if (r && r.error) return { status: 502, error: 'follow_failed', detail: r.error };
    23862389        return { status: 202, url: actorUri };
    23872390      }
     
    36453648  else actorUrl = null;
    36463649  if (!actorUrl) return { error: 'not_found' };
    3647   const actor = await fetchActor(actorUrl).catch(() => null);
     3650  // SIGNED, as this actor: an authorized-fetch instance refuses an anonymous
     3651  // GET of the actor doc, which made following from a boost silently fail
     3652  // (Robins melding, 31-7). Signed, the other side sees who asks.
     3653  const actor = await signedGetJson(site.slug, actorUrl);
    36483654  if (!actor || !actor.id || !actor.inbox) return { error: 'unreachable' };
    36493655  const ai = actorInfo(actor, actor.id);
     
    36603666  // Follow + feature in one step → backfill their recent posts into the Cirkel right away.
    36613667  if (autoBoost) backfillFromOutbox(site.slug, actor.id).catch(() => {});
     3668  // A ward's guardians are TOLD about a new follow (Robins verzoek, 31-7):
     3669  // a follow brings new content into the child's feed, and the village
     3670  // should know the door opened. A direct note per guardian, best-effort;
     3671  // FEP-633c 5.3 gates inbound follows, the outbound notice is Shaer policy
     3672  // for now (bead: spec-vraag).
     3673  try {
     3674    const guardians = Guardianship.listGuardians(site.slug);
     3675    if (guardians.length) {
     3676      const meRef = actorId(base, site.slug);
     3677      const esc = (t) => String(t).replace(/[<>&]/g, (c) => ({ '<': '&lt;', '>': '&gt;', '&': '&amp;' }[c]));
     3678      const label = esc(ai.name || ai.handle || actor.id);
     3679      for (const g of guardians) {
     3680        const note = {
     3681          id: `${meRef}/follow-notice/${Date.now().toString(36)}${rid()}`,
     3682          type: 'Note', attributedTo: meRef, to: [g.other_uri],
     3683          tag: [{ type: 'Mention', href: g.other_uri }],
     3684          content: `<p>👀 ${esc(site.title || site.slug)} is now following ${label}.</p>`,
     3685        };
     3686        deliverToActor(site, g.other_uri, { id: `${note.id}#create`, type: 'Create', actor: meRef, to: [g.other_uri], object: note })
     3687          .catch(() => { /* retried by the queue */ });
     3688      }
     3689      console.log('[AP] follow notice →', guardians.length, 'guardian(s) of', site.slug);
     3690    }
     3691  } catch { /* geen guardians is geen fout */ }
    36623692  return { ok: true, name: ai.name, handle: ai.handle, actor: actor.id };
    36633693}
  • test/c2s-compose.test.js

    r55eca8b r1a2f206  
    208208});
    209209
     210test('a failed follow REACHES the app as an error, not a fake 202', async () => {
     211  // Following from a boost silently failed (Robins melding, 31-7): the C2S
     212  // ingest swallowed followActor's error. An unreachable actor must say so.
     213  const r = await AP.ingestOutboxActivity(site, user, {
     214    type: 'Follow', object: 'https://unresolvable.invalid/u/niemand',
     215  });
     216  assert.equal(r.status, 502);
     217  assert.equal(r.error, 'follow_failed');
     218  assert.equal(r.detail, 'unreachable');
     219});
     220
    210221test('selfAuthor: the byline for your own outbox notes', () => {
    211222  // The owner's app reads its own posts from the outbox, which carried no
Note: See TracChangeset for help on using the changeset viewer.