jelveh 08356b4ea9 Keep the permission popup from signing the site in
The popup loads the GUI with embedded_in_popup=true, so it ran the
sign-in token exchange and posted puter.token to the opener before the
user answered the prompt. A site that called requestPermission() walked
away holding a user-app token for the account even when the user pressed
"Don't Allow" — and because the SDK's global puter.token handler feeds
event.data.token into setAuthToken() without looking at `success`, a
failed exchange posted token: null and wiped a token the site already
had. Keep running the exchange (it bootstraps the app row the grant
needs and caches host_app_uid) but leave the token in the popup. A site
that wants credentials still has to call signIn().

Escape on the SDK's consent dialog left the caller pending forever.
PuterDialog wired its Cancel and close buttons but not the <dialog>'s
native cancel event, so the browser dismissed the dialog and nothing
reported it: no dialog, no popup, no answer. Route cancel to the same
handler. Programmatic close() fires only `close`, so launching the popup
— which closes this dialog — is unaffected, and the implicit-auth flow
stops hanging on Escape too.

Serialize the permission dialogs. showModal() makes the whole document
inert rather than just the requesting app's window (which is what the
UIWindow it replaced did), and the dedup map only coalesced identical
requests, so an app asking for permissions in a loop stacked one modal
per request and walled the user off from the desktop — including from
the app doing it. Prompts now queue and open one at a time, and each
caller still gets its own decision.

Identify apps by more than their title. `title` is free-form text the
author picks and is not unique, so it was the whole identity of a prompt
an app titled "Puter Settings" could raise; the registered `name` is
unique and format-restricted, so show it underneath. Give the name line
the unicode-bidi isolation the origin line already had, since escaping
leaves bidi overrides intact.

Stop the dialog from answering over its own in-flight grant: a dismissal
while the POST was outstanding resolved false for a permission the server
was committing. Ignore dismissals while granting, and time-box the
request with AbortController (AbortSignal.timeout isn't everywhere) so a
hung network can't leave a modal no one can close. Fail closed on the
remaining paths that could reject or prompt uselessly — showModal()
throwing under <iframe sandbox>, and a requester known only by app_name,
whose Allow the server would always reject. Pass the error string to
.text() unencoded so translations containing an apostrophe don't render
&#39;.

The e2e suite covers all of it; each new test fails without its fix.
2026-07-25 19:56:13 -07:00
2026-07-16 15:52:37 -07:00
2026-07-16 15:52:37 -07:00
2024-03-02 18:39:14 -08:00
2026-05-29 13:36:10 -04:00
2026-07-07 16:13:18 -07:00
2024-03-02 18:39:14 -08:00
2026-05-14 13:01:34 -07:00
2025-02-03 14:22:01 -08:00

Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time.

The Open-Source Internet Computer!

« LIVE DEMO »

Puter.com · App Store · Developers · Discord · Reddit · X

screenshot


Puter

Puter is an advanced, open-source, self-hostable internet computer designed to be feature-rich, fast, and highly extensible.

For Users

Puter's goal is to provide you with every app and feature you need to work, create, and play under one roof. From a simple Notepad and Voice Recorder to Spreadsheet and Camera, Puter wants to be the all-in-one solution for your digital life.

For Developers

Puter provides everything you need to build and publish web apps and games. From AI to Cloud Storage and Database to Serverless Workers, Puter has you covered. Puter also helps you get users! Once you build your app, you can publish it on our App Store to reach and monetize users.


Getting Started

💻 Local Development

git clone https://github.com/HeyPuter/puter
cd puter
npm install
npm start

This should launch Puter at http://puter.localhost:4100


🚀 Self-Hosting

Linux/macOS

curl -fsSL https://puter.com/selfhost | sh

Windows

irm https://puter.com/selfhost?os=windows | iex

For more details, see Self-Hosting Puter.


☁️ Puter.com

Puter is available as a hosted service at puter.com.


Support

Connect with the maintainers and community through these channels:

We are always happy to help you with any questions you may have. Don't hesitate to ask!


License

This repository, including all its contents, sub-projects, modules, and components, is licensed under AGPL-3.0 unless explicitly stated otherwise. Third-party libraries included in this repository may be subject to their own licenses.


Translations

Languages
TypeScript 55.2%
JavaScript 40.3%
CSS 2.6%
HTML 1.8%