Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a92dd27
build(app): add premium desktop dependencies
ikerperez12 May 3, 2026
50645df
feat(core): add UI preferences and integration state
ikerperez12 May 3, 2026
323c0c9
feat(icons): unify premium system icons
ikerperez12 May 3, 2026
717a473
feat(desktop): add selection box and taskbar
ikerperez12 May 3, 2026
f32ed7a
fix(apps): repair Matrix Rain and Music Player
ikerperez12 May 3, 2026
b476848
perf(apps): lazy-load apps and remove unsafe eval
ikerperez12 May 3, 2026
b63ea43
feat(os): Finish IndexedDB migration, add Spotlight and Widgets, impl…
ikerperez12 May 4, 2026
86a3402
feat(desktop): add grid engine and glass folders
ikerperez12 May 4, 2026
41e358e
feat(settings): unify wallpapers and dock personalization
ikerperez12 May 4, 2026
763b38c
feat(browser): add YouTube lite and protected-site fallback
ikerperez12 May 4, 2026
e167d55
feat(chrome): add functional acrylic system controls
ikerperez12 May 4, 2026
d4f9141
fix(desktop): close folder overlay when launching apps
ikerperez12 May 4, 2026
8bbdc50
fix(browser): allow trusted video embeds in CSP
ikerperez12 May 4, 2026
b90d401
Remove Open Tasks Bar and update dock prefs
ikerperez12 May 4, 2026
62b58b7
fix(input): keep Tab/Ctrl+W from hijacking app inputs
Ikerperez00 May 5, 2026
1a24a62
refactor(integration): drop Cloud Sync and AI Bridge dead code
Ikerperez00 May 5, 2026
c5575d2
feat(top-panel): add floating Robot button with shortcuts panel
Ikerperez00 May 5, 2026
a47820d
chore(repo): ignore temporary patch artifact files
Ikerperez00 May 5, 2026
0c0d77e
feat(visual): screen filters, acrylic grain, audio bus + visualizer, …
Ikerperez00 May 5, 2026
a2a4868
feat(productivity): clipboard manager, virtual workspaces, snap assis…
Ikerperez00 May 5, 2026
87107b5
chore(security): protect .env, document storage surface and CSP
Ikerperez00 May 5, 2026
7c1a50a
fix(core): restore build and app installation state
Ikerperez00 May 5, 2026
191d16d
feat(terminal): harden tabs profiles and keyboard behavior
Ikerperez00 May 5, 2026
ab9adfa
chore(security): remove unused cloud dependency and dead taskbar
Ikerperez00 May 5, 2026
63f9228
fix(a11y): restore scalable viewport and control semantics
Ikerperez00 May 5, 2026
0483add
docs(public): prepare release docs and web metadata
Ikerperez00 May 5, 2026
a03ad28
ci: add public release checks
Ikerperez00 May 5, 2026
2a6854c
chore(vercel): configure production deployment
Ikerperez00 May 5, 2026
8e0ff22
chore(security): make password app memory-only demo
Ikerperez00 May 5, 2026
031fdbc
fix(responsive): keep desktop windows and dock inside compact viewports
Ikerperez00 May 5, 2026
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
33 changes: 33 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: CI

on:
push:
branches: [main, "cx/**", "codex/**"]
pull_request:
branches: [main]

permissions:
contents: read

jobs:
web:
name: Build and audit web app
runs-on: ubuntu-latest
defaults:
run:
working-directory: app
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: app/package-lock.json
- name: Install
run: npm ci
- name: Audit high severity dependencies
run: npm audit --audit-level=high
- name: Build
run: npm run build
32 changes: 32 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Patch artifacts (legacy)
.playwright-mcp/
.vercel/
app/.vercel/
app/src/App.tsx.head
app/src/components/Desktop.tsx.head
app/src/components/TopPanel.tsx.head
app/src/hooks/useOSStore.tsx.clean
app/src/types/index.ts.clean

# Secrets / env
.env
.env.*
!.env.example
.env.local
.env.production
.env.development
*.pem
*.key
secrets/

# Build / cache
node_modules/
app/node_modules/
dist/
app/dist/
build/
.coverage/
*.log
.DS_Store
.vscode/
.idea/
86 changes: 86 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# IP Linux

IP Linux is a local-first browser desktop built with React, TypeScript, and Vite. It presents a polished desktop shell with window management, a dock, launcher, virtual workspaces, reactive wallpapers, folders, and a catalog of built-in apps that run entirely in the visitor's browser.

## Preview

The app is designed to deploy as a static web app on Vercel. It does not require a backend or secret environment variables.

## Features

- Desktop shell with draggable/resizable windows, dock, launcher, top panel, virtual workspaces, and snap assist.
- Organized desktop folders with strict grid placement and local persistence.
- Built-in apps including Files, Terminal, Browser, Music, Matrix Rain, Settings, Store, games, productivity tools, and developer utilities.
- Reactive animated wallpapers, acrylic grain, screen filters, visual effects, and reduced-motion support.
- Local-first persistence using IndexedDB/localStorage for user state in the current browser only.
- YouTube-aware browser fallback that embeds supported video URLs and explains sites blocked by iframe policies.

## Safety Model

- No OpenAI, Supabase, Cloud Sync, or backend service is active in this release.
- No real secrets are needed. Do not commit `.env`, tokens, private keys, or Vercel local config.
- Browser state remains on the visitor's own device. The app does not upload files, clipboard content, or app data to a server.
- HTML preview surfaces use DOMPurify where dynamic HTML is rendered.

## Stack

- React 19
- TypeScript
- Vite
- Tailwind CSS
- Radix UI primitives
- IndexedDB via `idb-keyval`
- Vercel static hosting

## Quick Start

```powershell
cd app
npm ci
npm run dev
```

Open the local URL printed by Vite, usually `http://localhost:3000/`.

## Build and Checks

```powershell
cd app
npm run build
npm audit --audit-level=high
```

The production build emits a static app into `app/dist`.

## Deploy

The repository includes `vercel.json` at the root:

```powershell
vercel login
vercel link --repo
vercel deploy --prod
```

Production should deploy from `main` after the release PR passes build and audit checks.

## Project Structure

```text
app/
src/apps/ Built-in desktop applications
src/components/ Shell, dock, launcher, windows, menus
src/hooks/ OS store and filesystem hooks
src/lib/ Layout, storage, effects, helpers
public/ Manifest, sitemap, robots, public assets
SECURITY.md Public security notes
vercel.json Vercel build, routing, and security headers
```

## Current Scope

IP Linux is a browser-based desktop simulation and productivity playground. It is not a real Linux distribution, does not run native binaries, and does not provide cloud sync in this release.

## License

MIT. See [LICENSE](LICENSE).
68 changes: 68 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Security notes for IP Linux (public repo + public web)

This is a 100% client-side React/Vite app. There is no backend in this repo,
so the surface for hard security issues is small. This document is for the
maintainer to keep that surface small as the project grows.

## What ships in the bundle

* The Vite production bundle is compiled JavaScript + CSS shipped to the
browser. Anyone visiting the site can read it.
* Therefore: NEVER add a secret key (`OPENAI_API_KEY`, private Supabase
service role key, etc.) to the source or to a `.env*` file that gets
committed. Only `VITE_*` variables are exposed to the browser at build
time, and they all become public.

## What state persists in the browser

State is stored on the visitor's own browser, never sent to a server:

| Key | Where | Contents |
| ---------------------------------- | ------------- | ------------------------------ |
| `iplinux_filesystem` | IndexedDB | Virtual file system contents |
| `iplinux_app_handoff_v1` | localStorage | Per-app UI state (scroll etc.) |
| `iplinux_disabled_apps_v1` | localStorage | App Store install/remove list |
| `iplinux_desktop_icons_v6` | localStorage | Desktop icon positions |

The clipboard tray (Round 7) is held only in memory; it is **not** saved to
storage and resets on reload. Never persist private clipboard content.

## Code-level safeguards already in place

* No `eval` and no `new Function` in `app/src/**`.
* All `dangerouslySetInnerHTML` calls go through `DOMPurify.sanitize` and
whitelist a tight set of attributes.
* The shipped `index.html` declares a Content-Security-Policy meta tag with
`default-src 'self'`. (Note: Vite still requires `'unsafe-inline'` and
`'unsafe-eval'` for HMR in dev builds; these can be tightened in
production via the deploy host's CSP header.)
Comment on lines +35 to +38
* Browser frame embedding restricted to a small allow-list of trusted
origins (`youtube`, `wikipedia`, `lite.duckduckgo.com`).
* Cloud Sync, AI Bridge, and the unused Supabase client dependency were
removed. Reintroduce cloud services only with a backend/edge function that
keeps service secrets out of the browser bundle.

## Things to keep tight when contributing

* Never commit `.env`, `.env.local`, `*.pem`, `*.key`, or any file under
`secrets/`. Root and `app/` `.gitignore` cover this.
* Treat any `localStorage`/IndexedDB write as user-visible: do not store
passwords, tokens, OAuth state, or third-party API tokens there.
* Any new `dangerouslySetInnerHTML` site MUST go through DOMPurify and be
audited in PR review.
* Any new third-party origin used in iframes MUST be added to the CSP
`frame-src` list in `app/index.html` and re-reviewed.

## Recommended hardening for the deploy host

When deploying the `dist/` bundle, the hosting provider should also send:

```
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), camera=(), microphone=(), payment=()
```

If you publish the live site behind a reverse proxy or static host
(Vercel, Netlify, Cloudflare Pages), configure these as response headers.
7 changes: 7 additions & 0 deletions app/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# IP Linux does not require environment variables for this public release.
#
# Do not add real secrets to Vite environment files. Any VITE_* variable is
# bundled into client-side JavaScript and becomes public to every visitor.
#
# Cloud Sync, AI Bridge, OpenAI, and Supabase integrations are intentionally
# disabled in this release.
14 changes: 14 additions & 0 deletions app/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
node_modules
dist
.vercel
.DS_Store

# Secrets
.env
.env.*
!.env.example
.env.local
.env.production
.env.development

# Build artifacts
*.tsbuildinfo
.cache/
.parcel-cache/
77 changes: 11 additions & 66 deletions app/README.md
Original file line number Diff line number Diff line change
@@ -1,73 +1,18 @@
# React + TypeScript + Vite
# IP Linux Web App

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
This directory contains the React/Vite frontend for IP Linux.

Currently, two official plugins are available:
## Development

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh

## React Compiler

The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).

## Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:

```js
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...

// Remove tseslint.configs.recommended and replace with this
tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
tseslint.configs.stylisticTypeChecked,

// Other configs...
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
```powershell
npm ci
npm run dev
```

You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
## Production Build

```js
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'

export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
```powershell
npm run build
```

The static output is written to `dist/`. The repository root contains the public release README, security notes, CI workflow, and Vercel configuration.
3 changes: 3 additions & 0 deletions app/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,8 @@ export default defineConfig([
ecmaVersion: 2020,
globals: globals.browser,
},
rules: {
'react-refresh/only-export-components': 'off',
},
},
])
16 changes: 14 additions & 2 deletions app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,23 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data: https: blob:; connect-src 'self' https: wss:; frame-src 'self' https://www.youtube.com https://www.youtube-nocookie.com https://lite.duckduckgo.com https://*.wikipedia.org https://example.com;">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<meta name="theme-color" content="#0d001a" />
<meta name="description" content="IP Linux — Advanced Web Desktop Environment" />
<meta name="description" content="IP Linux is a polished browser-based desktop environment with apps, window management, reactive wallpapers, and local-first storage." />
<meta name="robots" content="index,follow" />
<meta property="og:type" content="website" />
<meta property="og:title" content="IP Linux" />
<meta property="og:description" content="A premium browser-based desktop environment built with React and Vite." />
<meta property="og:image" content="/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="IP Linux" />
<meta name="twitter:description" content="A premium browser-based desktop environment built with React and Vite." />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 96 96'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='10' y1='10' x2='86' y2='92'%3E%3Cstop stop-color='%237C4DFF'/%3E%3Cstop offset='.55' stop-color='%2300BCD4'/%3E%3Cstop offset='1' stop-color='%237C4DFF'/%3E%3C/linearGradient%3E%3C/defs%3E%3Cpath d='M48 8 88 31v34L48 88 8 65V31Z' fill='url(%23g)'/%3E%3Ccircle cx='48' cy='48' r='10' fill='%23FF9800'/%3E%3C/svg%3E" />
<link rel="manifest" href="/manifest.webmanifest" />
<title>IP Linux</title>
<style>
html, body { margin: 0; padding: 0; overflow: hidden; width: 100%; height: 100%; background: #000; }
Expand Down
Loading
Loading