Skip to content

Commit 330d829

Browse files
Copilotsensslen
andcommitted
Implement Base64 encoding for URL parameters with backward compatibility
Co-authored-by: sensslen <3428860+sensslen@users.noreply.github.com>
1 parent de0c673 commit 330d829

File tree

6 files changed

+66
-13
lines changed

6 files changed

+66
-13
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ node_modules
1111
dist
1212
dist-ssr
1313
*.local
14+
*.tsbuildinfo
1415

1516
# Editor directories and files
1617
.vscode/*

src/App.tsx

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import i18n from 'i18next';
44
import { initReactI18next, useTranslation } from 'react-i18next';
55
import localizationsEn from '../locales/en.json';
66
import localizationsDe from '../locales/de.json';
7+
import { encodeUrlToBase64, decodeBase64ToUrl } from './utils/urlEncoding';
78

89
i18n.use(initReactI18next).init({
910
resources: {
@@ -21,24 +22,43 @@ i18n.use(initReactI18next).init({
2122
});
2223

2324
const App: React.FC = () => {
24-
const [url, setUrl] = useState<string>('');
25+
// Initialize URL from query parameter at component creation
26+
const getInitialUrl = () => {
27+
const params = new URLSearchParams(window.location.search);
28+
const urlParam = params.get('url');
29+
if (urlParam) {
30+
try {
31+
// Try to decode as Base64 first (new format)
32+
return decodeBase64ToUrl(urlParam);
33+
} catch {
34+
// Fallback to decodeURIComponent for backward compatibility
35+
try {
36+
return decodeURIComponent(urlParam);
37+
} catch {
38+
console.warn('Failed to decode URL parameter');
39+
return '';
40+
}
41+
}
42+
}
43+
return '';
44+
};
45+
46+
const [url, setUrl] = useState<string>(getInitialUrl);
2547
const [error, setError] = useState<string | null>(null);
2648
const [success, setSuccess] = useState<string | null>(null);
2749
const { t } = useTranslation();
2850

2951
const handleUrlChange = (newUrl: string) => {
3052
setUrl(newUrl);
3153
// Update the URL in the address bar without reloading
32-
window.history.pushState(null, '', `?url=${encodeURIComponent(newUrl)}`);
33-
};
34-
35-
useEffect(() => {
36-
const params = new URLSearchParams(window.location.search);
37-
const initialUrl = params.get('url');
38-
if (initialUrl) {
39-
setUrl(decodeURIComponent(initialUrl));
54+
// Encode the URL in Base64 for better security and readability
55+
if (newUrl) {
56+
const encodedUrl = encodeUrlToBase64(newUrl);
57+
window.history.pushState(null, '', `?url=${encodedUrl}`);
58+
} else {
59+
window.history.pushState(null, '', window.location.pathname);
4060
}
41-
}, []);
61+
};
4262

4363
useEffect(() => {
4464
const lng = navigator.language;

src/api/proPresenter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Message, TriggerPayload } from '../types/proPresenter';
66
// Use URL constructor for basic format validation
77
new URL(inputUrl);
88
return true;
9-
} catch (e) {
9+
} catch {
1010
return false;
1111
}
1212
};

src/utils/urlEncoding.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Encodes a URL string to Base64 format for safe URL parameter usage
3+
* @param url - The URL string to encode
4+
* @returns Base64 encoded string
5+
*/
6+
export const encodeUrlToBase64 = (url: string): string => {
7+
try {
8+
// Use btoa for browser-compatible Base64 encoding
9+
// First encode to handle UTF-8 characters properly
10+
const utf8Bytes = new TextEncoder().encode(url);
11+
const binaryString = Array.from(utf8Bytes, byte => String.fromCharCode(byte)).join('');
12+
return btoa(binaryString);
13+
} catch (error) {
14+
console.error('Error encoding URL to Base64:', error);
15+
throw new Error('Failed to encode URL to Base64');
16+
}
17+
};
18+
19+
/**
20+
* Decodes a Base64 encoded URL string
21+
* @param encodedUrl - The Base64 encoded URL string
22+
* @returns Decoded URL string
23+
*/
24+
export const decodeBase64ToUrl = (encodedUrl: string): string => {
25+
try {
26+
// Use atob for browser-compatible Base64 decoding
27+
const binaryString = atob(encodedUrl);
28+
const bytes = Uint8Array.from(binaryString, char => char.charCodeAt(0));
29+
return new TextDecoder().decode(bytes);
30+
} catch (error) {
31+
console.error('Error decoding Base64 to URL:', error);
32+
throw new Error('Failed to decode Base64 to URL');
33+
}
34+
};

tsconfig.app.tsbuildinfo

Lines changed: 0 additions & 1 deletion
This file was deleted.

tsconfig.node.tsbuildinfo

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)