Security Model
FitFileViewer implements multiple security layers following Electron security best practices.
Security Overviewβ
Core Security Featuresβ
Context Isolationβ
Renderer JavaScript runs in an isolated context:
// main.ts
const mainWindow = new BrowserWindow({
webPreferences: {
contextIsolation: true, // Separate contexts
nodeIntegration: false, // No Node in renderer
sandbox: true, // OS sandbox
preload: path.join(__dirname, "preload.js"),
},
});
Why Context Isolation?β
| Without | With |
|---|---|
| Renderer can access Node | Renderer isolated |
| Window object exposed | Window protected |
| Easy to exploit | Secure by default |
IPC Securityβ
Validated Channelsβ
Only specific, validated operations are exposed:
// preload.ts
const validChannels = ["dialog:open-fit-file", "file:read", "app:get-version"];
contextBridge.exposeInMainWorld("electronAPI", {
openFile: () => ipcRenderer.invoke("dialog:open-fit-file"),
getVersion: () => ipcRenderer.invoke("app:get-version"),
// No arbitrary channel access
});
Input Validationβ
All inputs validated before processing:
// main.ts
ipcMain.handle("file:read", async (event, filePath) => {
// Validate file path
if (!isValidFilePath(filePath)) {
throw new Error("Invalid file path");
}
// Validate file extension
if (!filePath.endsWith(".fit")) {
throw new Error("Invalid file type");
}
// Safe to proceed
return fs.promises.readFile(filePath);
});
File System Securityβ
Path Validationβ
function isValidFilePath(filePath) {
// Normalize path
const normalized = path.normalize(filePath);
// Prevent directory traversal
if (normalized.includes("..")) {
return false;
}
// Check file exists
if (!fs.existsSync(normalized)) {
return false;
}
return true;
}
File Type Restrictionsβ
Only FIT files are processed:
const allowedExtensions = [".fit"];
function validateFileType(filePath) {
const ext = path.extname(filePath).toLowerCase();
return allowedExtensions.includes(ext);
}
Content Security Policyβ
CSP Headersβ
// Restrict content sources
const csp = [
"default-src 'self'",
"script-src 'self'",
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data: https://*.tile.openstreetmap.org",
"connect-src 'self' https://*.tile.openstreetmap.org",
].join("; ");
What This Preventsβ
- β Inline script injection
- β External script loading
- β Unauthorized network requests
Navigation Securityβ
Prevent External Navigationβ
// main.ts
mainWindow.webContents.on("will-navigate", (event, url) => {
// Only allow same-origin navigation
if (!url.startsWith("file://")) {
event.preventDefault();
}
});
mainWindow.webContents.setWindowOpenHandler(() => {
// Prevent new windows
return { action: "deny" };
});
Data Privacyβ
Local Data Onlyβ
FitFileViewer processes all data locally:
- β FIT files stay on your computer
- β No data uploaded to servers
- β No telemetry or tracking
- β Map tiles cached locally
What's Storedβ
| Data | Location | Purpose |
|---|---|---|
| Recent files | User data dir | Quick access |
| Preferences | User data dir | Settings |
| Theme | Local storage | UI preference |
What's NOT Storedβ
- β FIT file contents
- β GPS coordinates
- β Personal information
Security Best Practicesβ
For Usersβ
-
Download from official sources
- GitHub releases only
- Verify file hashes
-
Keep updated
- Security patches in updates
- Enable auto-update
-
Be cautious with files
- Only open trusted FIT files
- Don't open files from unknown sources
For Developersβ
- Never disable security features
- Validate all inputs
- Use allowlists, not blocklists
- Keep dependencies updated
Reporting Security Issuesβ
Found a vulnerability? Please report responsibly:
- Don't open a public issue
- Do email:
20943337+Nick2bad4u@users.noreply.github.com - Include:
- Description of vulnerability
- Steps to reproduce
- Potential impact
Related: Architecture Overview