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
4 changes: 4 additions & 0 deletions Caddyfile
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ header @html Content-Security-Policy "
https://youtube.com
https://player.vimeo.com
https://www.tiktok.com
https://platform.twitter.com
https://twitter.com
https://platform.x.com
https://x.com
https://giphy.com
https://open.spotify.com
https://embed-standalone.spotify.com
Expand Down
2 changes: 1 addition & 1 deletion src/assets/i18n-02-07-23/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@
"multi_post_progress": "Submitting posts:",
"post": "Post",
"embed_image": "Link to Arweave image",
"embed_video": "Embed Youtube, Vimeo, TikTok, Giphy, Spotify, Mousai, or SoundCloud",
"embed_video": "Embed Youtube, Vimeo, TikTok, Twitter, Giphy, Spotify, Mousai, or SoundCloud",
"quotes": {
"quote1": "Go ahead, make my day.",
"quote2": "The stuff that dreams are made of.",
Expand Down
2 changes: 1 addition & 1 deletion src/assets/i18n-02-07-23/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@
"complete":"Terminé",
"post": "Message",
"embed_image": "Lien vers une image Arweave",
"embed_video": "Intégrer Youtube, Vimeo, TikTok, Giphy, Spotify ou SoundCloud",
"embed_video": "Intégrer Youtube, Vimeo, TikTok, Twitter, Giphy, Spotify ou SoundCloud",
"quotes": {
"quote1": "Vas-y, refait ma journée.",
"quote2": "Les choses dont les rêves sont fait.",
Expand Down
2 changes: 1 addition & 1 deletion src/assets/i18n-02-07-23/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@
"complete": "Voltooid",
"post": "Plaats",
"embed_image": "Voeg een link naar een Arweave afbeelding toe",
"embed_video": "Voeg je Youtube, Vimeo, TikTok, Giphy, Spotify of SoundCloud video toe",
"embed_video": "Voeg je Youtube, Vimeo, TikTok, Twitter, Giphy, Spotify of SoundCloud video toe",
"quotes": {
"quote1": "Het leven is wat je vandaag viert.",
"quote2": "Geef wat je ontvangt, Ontvang wat je krijgt, Waardeer wat je hebt.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ describe("EmbedUrlParserService", () => {

const validTikTokEmbedURLs = [`https://www.tiktok.com/embed/v2/${tiktokVideoID}`];

const twitterPostID = "1819749725568110806";
const validTwitterURLs = [
`https://twitter.com/teslaownersSV/status/${twitterPostID}`,
`https://x.com/teslaownersSV/status/${twitterPostID}`,
];
const validTwitterEmbedURLs = [`https://platform.twitter.com/embed/Tweet.html?id=${twitterPostID}`];

const giphyID = "J1ABRhlfvQNwIOiAas";
const validGiphyURLs = [
`https://giphy.com/gifs/memecandy-${giphyID}`,
Expand Down Expand Up @@ -149,6 +156,7 @@ describe("EmbedUrlParserService", () => {
"123abc.com/1234556",
`https://wwwzyoutube.com/embed/${youtubeVideoID}`,
`https://nottiktok.com/embed/v2/${tiktokShortVideoID}`,
`https://notx.com/embed/Tweet.html?id=${twitterPostID}`,
`https://giphy.com/gifs/abc-def-${giphyID}-;<script></script>`,
`https://open.notspotify.com/embed/track/${spotifyID}-?;<script/></script>`,
`https://w.soundcloud.com/player/<script>?url=maliciousscript</script>?hide_related=true&show_comments=false`,
Expand Down Expand Up @@ -230,6 +238,22 @@ describe("EmbedUrlParserService", () => {
}
});

it("parses twitter URLs from user input correctly and only validates embed urls", () => {
for (const link of validTwitterURLs) {
expect(EmbedUrlParserService.isTwitterLink(link)).toBeTruthy();
const embedURL = EmbedUrlParserService.constructTwitterEmbedURL(new URL(link));
expect(embedURL).toEqual(`https://platform.twitter.com/embed/Tweet.html?id=${twitterPostID}`);
expect(EmbedUrlParserService.isValidEmbedURL(embedURL)).toBeTruthy();
expect(EmbedUrlParserService.isValidEmbedURL(link)).toBeFalsy();
}
for (const embedLink of validTwitterEmbedURLs) {
expect(EmbedUrlParserService.isTwitterLink(embedLink)).toBeTruthy();
expect(EmbedUrlParserService.isValidEmbedURL(embedLink)).toBeTruthy();
const constructedEmbedURL = EmbedUrlParserService.constructTwitterEmbedURL(new URL(embedLink));
expect(EmbedUrlParserService.isValidEmbedURL(constructedEmbedURL)).toBeTruthy();
}
});

it("parses giphy URLs from user input correctly and only validates embed urls", () => {
for (const link of validGiphyURLs) {
expect(EmbedUrlParserService.isGiphyLink(link)).toBeTruthy();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,24 @@ export class EmbedUrlParserService {
);
}

static twitterParser(url): string | boolean {
const regExp = /status\/(\d+)/;
const match = url.match(regExp);
if(match && match[1].length >= 1) {
return match[1]
} else {
const regExp2 = /id=(\d+)/;
const match2 = url.match(regExp2);
return match2 && match2[1].length >= 1 ? match2[1] : false;
}
}

static constructTwitterEmbedURL(url: URL): string {
const twitterPostID = this.twitterParser(url.toString());
// If we can't find the postID, return the empty string which stops the iframe from loading.
return twitterPostID ? `https://platform.twitter.com/embed/Tweet.html?id=${twitterPostID}` : "";
}

static getEmbedURL(
backendApi: BackendApiService,
globalVars: GlobalVarsService,
Expand Down Expand Up @@ -209,6 +227,9 @@ export class EmbedUrlParserService {
if (this.isTiktokFromURL(url)) {
return this.constructTikTokEmbedURL(backendApi, globalVars, url);
}
if (this.isTwitterFromURL(url)) {
return of(this.constructTwitterEmbedURL(url));
}
if (this.isGiphyFromURL(url)) {
return of(this.constructGiphyEmbedURL(url));
}
Expand Down Expand Up @@ -282,6 +303,20 @@ export class EmbedUrlParserService {
return pattern.test(url.hostname);
}

static isTwitterLink(link: string): boolean {
try {
const url = new URL(link);
return this.isTwitterFromURL(url);
} catch (e) {
return false;
}
}

static isTwitterFromURL(url: URL): boolean {
const patterns = [/\btwitter\.com$/, /\bx\.com$/];
return patterns.some((p) => p.test(url.hostname));
}

static isGiphyLink(link: string): boolean {
try {
const url = new URL(link);
Expand Down Expand Up @@ -358,6 +393,11 @@ export class EmbedUrlParserService {
return !!link.match(regExp);
}

static isValidTwitterEmbedURL(link: string): boolean {
const regExp = /(https:\/\/platform\.twitter\.com\/embed\/Tweet.html\?id=(\d{0,30}))$/;
return !!link.match(regExp);
}

static isValidGiphyEmbedURL(link: string): boolean {
const regExp = /(https:\/\/giphy\.com\/embed\/([A-Za-z0-9]{0,20}))$/;
return !!link.match(regExp);
Expand Down Expand Up @@ -395,6 +435,7 @@ export class EmbedUrlParserService {
this.isValidYoutubeEmbedURL(link) ||
this.isValidMousaiEmbedURL(link) ||
this.isValidTiktokEmbedURL(link) ||
this.isValidTwitterEmbedURL(link) ||
this.isValidGiphyEmbedURL(link) ||
this.isValidSpotifyEmbedURL(link) ||
this.isValidSoundCloudEmbedURL(link) ||
Expand All @@ -407,7 +448,16 @@ export class EmbedUrlParserService {

static getEmbedHeight(link: string): number {
if (this.isValidTiktokEmbedURL(link)) {
return 700;
return 760;
}
if (this.isTikTokLink(link)) {
return 760;
}
if (this.isValidTwitterEmbedURL(link)) {
return 500;
}
if (this.isTwitterLink(link)) {
return 500;
}
if (this.isValidSpotifyEmbedURL(link)) {
return link.indexOf("embed-podcast") > -1 ? 232 : 380;
Expand Down
2 changes: 1 addition & 1 deletion src/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2691,7 +2691,7 @@ bs-dropdown-container {
justify-content: center;
align-items: center;
overflow: hidden;
max-height: 700px;
max-height: 760px;
border-radius: 6px;
margin-top: 10px;
margin-bottom: 5px;
Expand Down