Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ node_modules
.sqlite_history
*.patch
request_logs.txt
.DS_Store
.DS_Store
account.json
22 changes: 18 additions & 4 deletions src/activitypub.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,26 +48,39 @@ export function createNoteObject(bookmark, account, domain) {
.join(' ');
}

let escapedDescription = '';
if (updatedBookmark.description?.trim().length > 0) {
updatedBookmark.description = `<br/>${updatedBookmark.description?.trim().replace('\n', '<br/>') || ''}`;
escapedDescription = `<br/>${updatedBookmark.description?.trim().replace('\n', '<br/>') || ''}`;
}

if (linkedTags.trim().length > 0) {
linkedTags = `<p>${linkedTags}</p>`;
}

const noteMessage = {
'@context': 'https://www.w3.org/ns/activitystreams',
'@context': ['https://www.w3.org/ns/activitystreams', { Hashtag: 'https://www.w3.org/ns/activitystreams#Hashtag' }],

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For formal correctness. Practical implementations often ignore JSON-LD contexts, but some of them don't.

id: `https://${domain}/m/${guidNote}`,
type: 'Note',
published: d.toISOString(),
attributedTo: `https://${domain}/u/${account}`,
name: updatedBookmark.title,
content: `<p><strong><a href="${updatedBookmark.url}" rel="nofollow noopener noreferrer">${replaceEmptyText(
updatedBookmark.title,
updatedBookmark.url,
)}</a></strong>${updatedBookmark.description}</p>${linkedTags}`,
)}</a></strong>${escapedDescription}</p>${linkedTags}`,
to: [`https://${domain}/u/${account}/followers/`, 'https://www.w3.org/ns/activitystreams#Public'],
tag: [],
url: `https://${domain}/bookmark/${updatedBookmark.id}`,
source: {
content: updatedBookmark.description,
mediaType: 'text/plain',
},
attachment: [
{
type: 'Link',
href: updatedBookmark.url,
},
],
};

bookmark.tags?.split(' ').forEach((tag) => {
Expand Down Expand Up @@ -262,7 +275,8 @@ export async function broadcastMessage(bookmark, action, db, account, domain) {

// eslint-disable-next-line no-restricted-syntax
for (const follower of followers) {
const inbox = `${follower}/inbox`;
console.log(`Sending to ${follower}...`);
const inbox = await getInboxFromActorProfile(follower);

@bouncepaw bouncepaw Jul 1, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You took a shortcut here, which made sense, but the old logic failed for some servers such as Betula. Some form of caching would make sense, but I didn't find a db table with remote actors.

const myURL = new URL(follower);
const targetDomain = myURL.host;
signAndSend(message, account, domain, db, targetDomain, inbox);
Expand Down
2 changes: 1 addition & 1 deletion src/signature.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ function getSignatureParams(body, method, url) {
*/
function getSignatureHeader(signature, signatureKeys) {
return [
`keyId="https://${domain}/u/${account}"`,
`keyId="https://${domain}/u/${account}#main-key"`,

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did it work before? It shouldn't have.

`algorithm="rsa-sha256"`,
`headers="${signatureKeys.join(' ')}"`,
`signature="${signature}"`,
Expand Down