Don't allow previewing `shared` history rooms (#239)
Only `world_readable` can be considered as opting into having history publicly on the web. Anything else must not be archived until there's a dedicated state event for opting into archiving.
This commit is contained in:
parent
e4800852ff
commit
1d3e930fbd
|
@ -155,7 +155,6 @@ const fetchRoomData = traceFunction(async function (
|
||||||
stateCanonicalAliasResDataOutcome,
|
stateCanonicalAliasResDataOutcome,
|
||||||
stateAvatarResDataOutcome,
|
stateAvatarResDataOutcome,
|
||||||
stateHistoryVisibilityResDataOutcome,
|
stateHistoryVisibilityResDataOutcome,
|
||||||
stateJoinRulesResDataOutcome,
|
|
||||||
predecessorInfoOutcome,
|
predecessorInfoOutcome,
|
||||||
successorInfoOutcome,
|
successorInfoOutcome,
|
||||||
] = await Promise.allSettled([
|
] = await Promise.allSettled([
|
||||||
|
@ -182,10 +181,6 @@ const fetchRoomData = traceFunction(async function (
|
||||||
abortSignal,
|
abortSignal,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
fetchEndpointAsJson(getStateEndpointForRoomIdAndEventType(roomId, 'm.room.join_rules'), {
|
|
||||||
accessToken: matrixAccessToken,
|
|
||||||
abortSignal,
|
|
||||||
}),
|
|
||||||
fetchPredecessorInfo(matrixAccessToken, roomId, { abortSignal }),
|
fetchPredecessorInfo(matrixAccessToken, roomId, { abortSignal }),
|
||||||
fetchSuccessorInfo(matrixAccessToken, roomId, { abortSignal }),
|
fetchSuccessorInfo(matrixAccessToken, roomId, { abortSignal }),
|
||||||
]);
|
]);
|
||||||
|
@ -220,12 +215,6 @@ const fetchRoomData = traceFunction(async function (
|
||||||
historyVisibility = data?.content?.history_visibility;
|
historyVisibility = data?.content?.history_visibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
let joinRule;
|
|
||||||
if (stateJoinRulesResDataOutcome.reason === undefined) {
|
|
||||||
const { data } = stateJoinRulesResDataOutcome.value;
|
|
||||||
joinRule = data?.content?.join_rule;
|
|
||||||
}
|
|
||||||
|
|
||||||
let roomCreationTs;
|
let roomCreationTs;
|
||||||
let predecessorRoomId;
|
let predecessorRoomId;
|
||||||
let predecessorLastKnownEventId;
|
let predecessorLastKnownEventId;
|
||||||
|
@ -251,7 +240,6 @@ const fetchRoomData = traceFunction(async function (
|
||||||
canonicalAlias,
|
canonicalAlias,
|
||||||
avatarUrl,
|
avatarUrl,
|
||||||
historyVisibility,
|
historyVisibility,
|
||||||
joinRule,
|
|
||||||
roomCreationTs,
|
roomCreationTs,
|
||||||
predecessorRoomId,
|
predecessorRoomId,
|
||||||
predecessorLastKnownEventId,
|
predecessorLastKnownEventId,
|
||||||
|
|
|
@ -22,7 +22,6 @@ const matrixServerName = config.get('matrixServerName');
|
||||||
assert(matrixServerName);
|
assert(matrixServerName);
|
||||||
const matrixAccessToken = config.get('matrixAccessToken');
|
const matrixAccessToken = config.get('matrixAccessToken');
|
||||||
assert(matrixAccessToken);
|
assert(matrixAccessToken);
|
||||||
const stopSearchEngineIndexing = config.get('stopSearchEngineIndexing');
|
|
||||||
|
|
||||||
const router = express.Router({
|
const router = express.Router({
|
||||||
caseSensitive: true,
|
caseSensitive: true,
|
||||||
|
@ -71,7 +70,8 @@ router.get(
|
||||||
}
|
}
|
||||||
|
|
||||||
// We index the room directory unless the config says we shouldn't index anything
|
// We index the room directory unless the config says we shouldn't index anything
|
||||||
const shouldIndex = !stopSearchEngineIndexing;
|
const stopSearchEngineIndexingFromConfig = config.get('stopSearchEngineIndexing');
|
||||||
|
const shouldIndex = !stopSearchEngineIndexingFromConfig;
|
||||||
|
|
||||||
const pageOptions = {
|
const pageOptions = {
|
||||||
title: `Matrix Public Archive`,
|
title: `Matrix Public Archive`,
|
||||||
|
|
|
@ -57,7 +57,6 @@ const matrixServerUrl = config.get('matrixServerUrl');
|
||||||
assert(matrixServerUrl);
|
assert(matrixServerUrl);
|
||||||
const matrixAccessToken = config.get('matrixAccessToken');
|
const matrixAccessToken = config.get('matrixAccessToken');
|
||||||
assert(matrixAccessToken);
|
assert(matrixAccessToken);
|
||||||
const stopSearchEngineIndexing = config.get('stopSearchEngineIndexing');
|
|
||||||
|
|
||||||
const matrixPublicArchiveURLCreator = new MatrixPublicArchiveURLCreator(basePath);
|
const matrixPublicArchiveURLCreator = new MatrixPublicArchiveURLCreator(basePath);
|
||||||
|
|
||||||
|
@ -828,15 +827,13 @@ router.get(
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Only `world_readable` or `shared` rooms that are `public` are viewable in the archive
|
// Only `world_readable` rooms are viewable in the archive
|
||||||
const allowedToViewRoom =
|
const allowedToViewRoom = roomData.historyVisibility === 'world_readable';
|
||||||
roomData.historyVisibility === 'world_readable' ||
|
|
||||||
(roomData.historyVisibility === 'shared' && roomData.joinRule === 'public');
|
|
||||||
|
|
||||||
if (!allowedToViewRoom) {
|
if (!allowedToViewRoom) {
|
||||||
throw new StatusError(
|
throw new StatusError(
|
||||||
403,
|
403,
|
||||||
`Only \`world_readable\` or \`shared\` rooms that are \`public\` can be viewed in the archive. ${roomData.id} has m.room.history_visiblity=${roomData.historyVisibility} m.room.join_rules=${roomData.joinRule}`
|
`Only \`world_readable\` rooms can be viewed in the archive. ${roomData.id} has m.room.history_visiblity=${roomData.historyVisibility}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -891,7 +888,8 @@ router.get(
|
||||||
|
|
||||||
// Default to no indexing (safe default)
|
// Default to no indexing (safe default)
|
||||||
let shouldIndex = false;
|
let shouldIndex = false;
|
||||||
if (stopSearchEngineIndexing) {
|
const stopSearchEngineIndexingFromConfig = config.get('stopSearchEngineIndexing');
|
||||||
|
if (stopSearchEngineIndexingFromConfig) {
|
||||||
shouldIndex = false;
|
shouldIndex = false;
|
||||||
} else {
|
} else {
|
||||||
// Otherwise we only allow search engines to index `world_readable` rooms
|
// Otherwise we only allow search engines to index `world_readable` rooms
|
||||||
|
|
|
@ -2688,15 +2688,50 @@ describe('matrix-public-archive', () => {
|
||||||
assert.strictEqual(dom.document.querySelector(`meta[name="robots"]`), null);
|
assert.strictEqual(dom.document.querySelector(`meta[name="robots"]`), null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('search engines not allowed to index `public` room', async () => {
|
it('search engines not allowed to access public room with non-`world_readable` history visibility', async () => {
|
||||||
const client = await getTestClientForHs(testMatrixServerUrl1);
|
const client = await getTestClientForHs(testMatrixServerUrl1);
|
||||||
const roomId = await createTestRoom(client, {
|
const roomId = await createTestRoom(client, {
|
||||||
// The default options for the test rooms adds a
|
// Set as `shared` since it's the next most permissive history visibility
|
||||||
// `m.room.history_visiblity` state event so we override that here so
|
// after `world_readable` but still not allowed to be accesible in the
|
||||||
// it's only a public room.
|
// archive.
|
||||||
initial_state: [],
|
initial_state: [
|
||||||
|
{
|
||||||
|
type: 'm.room.history_visibility',
|
||||||
|
state_key: '',
|
||||||
|
content: {
|
||||||
|
history_visibility: 'shared',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
archiveUrl = matrixPublicArchiveURLCreator.archiveUrlForRoom(roomId);
|
||||||
|
await fetchEndpointAsText(archiveUrl);
|
||||||
|
assert.fail(
|
||||||
|
new TestError(
|
||||||
|
'We expect the request to fail with a 403 since the archive should not be able to view a non-world_readable room but it succeeded'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof TestError) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
assert.strictEqual(
|
||||||
|
err.response.status,
|
||||||
|
403,
|
||||||
|
`Expected err.response.status=${err?.response?.status} to be 403 but error was: ${err.stack}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Configuring `stopSearchEngineIndexing` will stop search engine indexing', async () => {
|
||||||
|
// Disable search engine indexing across the entire instance
|
||||||
|
config.set('stopSearchEngineIndexing', true);
|
||||||
|
|
||||||
|
const client = await getTestClientForHs(testMatrixServerUrl1);
|
||||||
|
const roomId = await createTestRoom(client);
|
||||||
|
|
||||||
archiveUrl = matrixPublicArchiveURLCreator.archiveUrlForRoom(roomId);
|
archiveUrl = matrixPublicArchiveURLCreator.archiveUrlForRoom(roomId);
|
||||||
const { data: archivePageHtml } = await fetchEndpointAsText(archiveUrl);
|
const { data: archivePageHtml } = await fetchEndpointAsText(archiveUrl);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue