fix: #12883, activitypub probe timeout

- Added setting to disable probe completely
- Added setting to configure timeout
- Updated probe logic so that if probe times out, it retries in the background with 60s timeout for caching purposes
This commit is contained in:
Julian Lam
2024-10-30 10:59:05 -04:00
parent 22dbf15e5e
commit f8729571db
6 changed files with 48 additions and 4 deletions

View File

@@ -193,6 +193,8 @@
"disableCustomUserSkins": 0,
"activitypubEnabled": 1,
"activitypubAllowLoopback": 0,
"activitypubProbe": 1,
"activitypubProbeTimeout": 500,
"activitypubContentPruneDays": 30,
"activitypubUserPruneDays": 7,
"activitypubFilter": 0

View File

@@ -12,6 +12,12 @@
"allowLoopback": "Allow loopback processing",
"allowLoopback-help": "Useful for debugging purposes only. You should probably leave this disabled.",
"probe": "Open in App",
"probe-enabled": "Try to open ActivityPub-enabled resources in NodeBB",
"probe-enabled-help": "If enabled, NodeBB will check every external link for an ActivityPub equivalent, and load it in NodeBB instead.",
"probe-timeout": "Lookup Timeout (milliseconds)",
"probe-timeout-help": "(Default: 500) If the lookup query does not receive a response within the set timeframe, will send the user to the link directly instead. Adjust this number higher if sites are responding slowly and you wish to give extra time.",
"server-filtering": "Filtering",
"count": "This NodeBB is currently aware of <strong>%1</strong> server(s)",
"server.filter-help": "Specify servers you would like to bar from federating with your NodeBB. Alternatively, you may opt to selectively <em>allow</em> federation with specific servers, instead. Both options are supported, although they are mutually exclusive.",

View File

@@ -609,7 +609,7 @@ $(document).ready(function () {
ajaxify.go('outgoing?url=' + encodeURIComponent(href));
e.preventDefault();
}
} else {
} else if (config.activitypub.probe) {
ajaxify.go(`ap?resource=${encodeURIComponent(this.href)}`);
e.preventDefault();
}

View File

@@ -490,8 +490,10 @@ ActivityPub.probe = async ({ uid, url }) => {
}
// Opportunistic HEAD
const { response } = await request.head(url);
try {
async function checkHeader(timeout) {
const { response } = await request.head(url, {
timeout,
});
const { headers } = response;
if (headers && headers.link) {
let parts = headers.link.split(';');
@@ -509,8 +511,19 @@ ActivityPub.probe = async ({ uid, url }) => {
return true;
}
}
return false;
}
try {
await checkHeader(meta.config.activitypubProbeTimeout || 500);
} catch (e) {
// ...
if (e.name === 'TimeoutError') {
// Return early but retry for caching purposes
checkHeader(1000 * 60).then((result) => {
probeCache.set(url, result);
});
return false;
}
}
probeCache.set(url, false);

View File

@@ -97,6 +97,9 @@ apiController.loadConfig = async function (req) {
styles: fontawesome_styles,
version: fontawesome_version,
},
activitypub: {
probe: meta.config.activitypubProbe,
},
};
let settings = config;

View File

@@ -24,6 +24,26 @@
</div>
</div>
<div class="row settings m-0">
<div class="col-sm-2 col-12 settings-header">[[admin/settings/activitypub:probe]]</div>
<div class="col-sm-10 col-12">
<form>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" data-field="activitypubProbe">
<label class="form-check-label">[[admin/settings/activitypub:probe-enabled]]</label>
<p class="form-text">[[admin/settings/activitypub:probe-enabled-help]]</p>
</div>
<div class="mb-3">
<label class="form-label" for="activitypubProbeTimeout">[[admin/settings/activitypub:probe-timeout]]</label>
<input type="number" id="activitypubProbeTimeout" name="activitypubProbeTimeout" data-field="activitypubProbeTimeout" title="[[admin/settings/activitypub:probe-timeout]]" class="form-control" />
<div class="form-text">
[[admin/settings/activitypub:probe-timeout-help]]
</div>
</div>
</form>
</div>
</div>
<div class="row settings m-0">
<div class="col-sm-2 col-12 settings-header">[[admin/settings/activitypub:pruning]]</div>
<div class="col-sm-10 col-12">