+
{renderInner()}
diff --git a/src/locales/en.json b/src/locales/en.json
index 3b5804357..ec2fd06a0 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -190,6 +190,7 @@
"auth.logged_out": "Logged out.",
"authorize.success": "Approved",
"backups.actions.create": "Create backup",
+ "backups.download": "Download",
"backups.empty_message": "No backups found. {action}",
"backups.empty_message.action": "Create one now?",
"backups.pending": "Pending",
diff --git a/src/reducers/backups.tsx b/src/reducers/backups.tsx
index fbbfccef0..e2557c845 100644
--- a/src/reducers/backups.tsx
+++ b/src/reducers/backups.tsx
@@ -8,7 +8,7 @@ import {
import type { AnyAction } from 'redux';
import type { APIEntity } from 'soapbox/types/entities';
-const BackupRecord = ImmutableRecord({
+export const BackupRecord = ImmutableRecord({
id: null as number | null,
content_type: '',
url: '',
@@ -17,7 +17,7 @@ const BackupRecord = ImmutableRecord({
inserted_at: '',
});
-type Backup = ReturnType
;
+export type Backup = ReturnType;
type State = ImmutableMap;
const initialState: State = ImmutableMap();
diff --git a/src/schemas/card.ts b/src/schemas/card.ts
index d35c9f109..dc4ba2e6b 100644
--- a/src/schemas/card.ts
+++ b/src/schemas/card.ts
@@ -1,5 +1,6 @@
import punycode from 'punycode';
+import DOMPurify from 'isomorphic-dompurify';
import { z } from 'zod';
import { groupSchema } from './group';
@@ -54,6 +55,33 @@ const cardSchema = z.object({
}
}
+ const html = DOMPurify.sanitize(card.html, {
+ ALLOWED_TAGS: ['iframe'],
+ ALLOWED_ATTR: ['src', 'width', 'height', 'frameborder', 'allowfullscreen'],
+ RETURN_DOM: true,
+ });
+
+ html.querySelectorAll('iframe').forEach((frame) => {
+ try {
+ const src = new URL(frame.src);
+ if (src.protocol !== 'https:') {
+ throw new Error('iframe must be https');
+ }
+ if (src.origin === location.origin) {
+ throw new Error('iframe must not be same origin');
+ }
+ frame.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-presentation');
+ } catch (e) {
+ frame.remove();
+ }
+ });
+
+ card.html = html.innerHTML;
+
+ if (!card.html) {
+ card.type = 'link';
+ }
+
return card;
});