Source
This app’s code and revision history are public. Download a copy or explore the files below.
Public
The app’s code and revision history are public.
Run it yourself
Take the whole tree and run it on your own machine. The download needs no account. Cloning needs a sign-in.
Download .zip
bounded clone 6eca480d6447d873e2e5eed9
A copy you download is not bounded. The guarantees this app runs under - declared egress, proven invariants, writes that fail closed - live in the runtime serving this page, not in the files. What you get is auditable source you can read and run, with no runtime guarantees attached.
src/View.tsx
// A paste's page (/<id>, or /<id>#<key> when encrypted with a key in the link). It reads through the public API,
// so opening a paste needs no account and loads no SDK. A burn-after-reading paste asks before it is opened,
// and a paste locked with a password asks for it.
import { lazy, Suspense, useEffect, useState, type FormEvent } from "react";
import { SERVED_API } from "./lib/app";
import { navigate } from "./lib/router";
import { open as unseal, openWithPassword } from "./lib/crypto";
import { savedPaste } from "./lib/mine";
import { copy, share, canShare, toast, Menu, Icon } from "./ui";
import { CodeView } from "./Code";
import { PasteSkeleton } from "./Skeletons";
import { forkIntoEditor } from "./Editor";
import { languageOf, formatBytes, byteLength, PASSWORD_PREFIX } from "../functions/lib/paste";
import { adminPath, fromNow, shareUrl } from "./lib/format";
const Markdown = lazy(() => import("./Markdown"));
interface ApiPaste {
id: string; url: string; rawUrl: string; title: string; language: string; size: number;
encrypted: boolean; password?: boolean; burn: boolean; createdAt: string; expiresAt: string | null; content?: string; deleted?: boolean;
}
interface Shown extends ApiPaste { content: string }
type State =
| { kind: "loading" }
| { kind: "gone" }
| { kind: "error"; message: string }
| { kind: "confirm"; paste: ApiPaste }
| { kind: "locked"; paste: Shown }
| { kind: "nokey" }
| { kind: "badkey" }
| { kind: "ready"; paste: Shown };
async function fetchPaste(id: string, peek: boolean): Promise<ApiPaste | null> {
const res = await fetch(`${SERVED_API}/pastes/${id}${peek ? "?peek=1" : ""}`);
if (res.status === 404) return null;
const body = await res.json().catch(() => ({}));
if (!res.ok) throw new Error(body.error || "This paste could not be opened. Try again.");
return body as ApiPaste;
}
const hasPassword = (p: ApiPaste) => p.password ?? Boolean(p.encrypted && p.content?.startsWith(PASSWORD_PREFIX));
const isLineHash = (hash: string) => /^#L\d+$/.test(hash);
/** The key of a paste encrypted with a key in the link: everything after the #, unless it is a line link. */
const linkSecret = () => (isLineHash(location.hash) ? "" : location.hash.slice(1));
/** fetch fails with a TypeError when the network or the server cannot be reached. */
const offline = () => "Paste could not be reached. Check your connection, then try again.";
export function ViewPage({ id }: { id: string }) {
const [state, setState] = useState<State>({ kind: "loading" });
const show = async (p: ApiPaste) => {
const paste: Shown = { ...p, password: hasPassword(p), content: p.content ?? "" };
if (paste.password) return setState({ kind: "locked", paste });
if (p.encrypted) {
const secret = linkSecret();
if (!secret) return setState({ kind: "nokey" });
try {
return setState({ kind: "ready", paste: { ...paste, ...(await unseal(paste.content, secret)) } });
} catch {
return setState({ kind: "badkey" });
}
}
setState({ kind: "ready", paste });
};
const load = (peek: boolean) => {
if (peek) setState({ kind: "loading" });
return fetchPaste(id, peek).then(
(p) => {
if (!p) return setState({ kind: "gone" });
// An encrypted burn paste opened without its key would be deleted unread, so stop before opening it.
if (p.burn && p.content == null) return setState(p.encrypted && !hasPassword(p) && !linkSecret() ? { kind: "nokey" } : { kind: "confirm", paste: p });
return show(p);
},
(err) => setState({ kind: "error", message: !navigator.onLine || err instanceof TypeError ? offline() : (err as Error).message }),
);
};
useEffect(() => {
load(true);
// Pasting the full link (with its #key) into a tab already on this paste changes only the hash. Line links do not reload.
const onHash = () => { if (!isLineHash(location.hash)) load(true); };
window.addEventListener("hashchange", onHash);
return () => window.removeEventListener("hashchange", onHash);
}, [id]);
useEffect(() => {
const title = state.kind === "ready" ? state.paste.title : "";
document.title = `${title || "Paste"} | Paste`;
}, [state]);
if (state.kind === "loading") return <PasteSkeleton />;
if (state.kind === "error") return (
<Message title="This paste could not be opened.">
<p className="lede">{state.message}</p>
<button className="btn" type="button" onClick={() => load(true)}>Try again</button>
</Message>
);
if (state.kind === "gone") return (
<Message title="This paste is gone." art>
<p className="lede">It expired, its owner deleted it, or it was set to delete after the first view and someone opened it. Or the link was cut short: check that you copied all of it.</p>
<HomeLink />
</Message>
);
if (state.kind === "nokey") return (
<Message title="This link is missing its key.">
<p className="lede">This paste is encrypted. Its key is the last part of the full link, after the # sign. Open the complete link you were sent.</p>
<HomeLink />
</Message>
);
if (state.kind === "badkey") return (
<Message title="This paste could not be unlocked.">
<p className="lede">The key at the end of the link does not open it. Check that you copied the whole link, including everything after the # sign.</p>
<HomeLink />
</Message>
);
if (state.kind === "confirm") return <Confirm id={id} paste={state.paste} onOpen={() => load(false)} />;
if (state.kind === "locked") return <Unlock paste={state.paste} onOpen={(paste) => setState({ kind: "ready", paste })} />;
return <PasteView id={id} paste={state.paste} />;
}
function Message({ title, art, children }: { title: string; art?: boolean; children: React.ReactNode }) {
return (
<div className="wrap page-pad narrow message enter">
{art && <img className="art message-art" src="/art/card-paste.webp" alt="" width="720" height="511" />}
<h1 className="h1">{title}</h1>
{children}
</div>
);
}
const HomeLink = () => (
<a className="btn" href="/" onClick={(e) => { e.preventDefault(); navigate("/"); }}>Make a paste</a>
);
function Confirm({ id, paste, onOpen }: { id: string; paste: ApiPaste; onOpen: () => Promise<void> }) {
const mine = savedPaste(id);
const [busy, setBusy] = useState(false);
const open = () => { setBusy(true); onOpen().finally(() => setBusy(false)); };
return (
<Message title={paste.title || "This paste deletes itself after one view."}>
{paste.title && <p className="eyebrow">Deletes itself after one view</p>}
<p className="lede">
{mine
? "You made this paste. If you open it here, it is deleted, and the link stops working for the person you meant it for."
: `Once you open it, it is deleted from the server and this link stops working for everyone. Copy or download it while it is on your screen.${hasPassword(paste) ? " You need its password to read it." : ""}`}
</p>
<div className="row">
{mine ? (
<>
<a className="btn" href={adminPath(mine)} onClick={(e) => { e.preventDefault(); navigate(adminPath(mine)); }}>Manage it instead</a>
<button className="btn btn-line" type="button" onClick={open} aria-busy={busy || undefined}><span>Open and delete it</span></button>
</>
) : (
<button className="btn btn-lg" type="button" onClick={open} aria-busy={busy || undefined}><span>Open the paste</span></button>
)}
</div>
<p className="hint">{formatBytes(paste.size)}{hasPassword(paste) ? ", locked with a password" : paste.encrypted ? ", encrypted" : ""}</p>
</Message>
);
}
/** Asks for the password. The locked text is already on the page, so a wrong guess can be retried even after a burn paste is deleted. */
function Unlock({ paste, onOpen }: { paste: Shown; onOpen: (paste: Shown) => void }) {
const [password, setPassword] = useState("");
const [busy, setBusy] = useState(false);
const [error, setError] = useState<string | null>(null);
const submit = async (e: FormEvent) => {
e.preventDefault();
if (!password) return setError("Type the password you were given.");
setBusy(true);
setError(null);
try {
onOpen({ ...paste, ...(await openWithPassword(paste.content, password)) });
} catch {
setError("That password does not open this paste. Check it and try again.");
setBusy(false);
}
};
return (
<Message title="This paste is locked with a password.">
{paste.deleted
? <p className="notice" role="status">It is already deleted from the server, because it was set to delete after one view. Keep this page open until it is unlocked.</p>
: <p className="lede">The person who sent you the link has the password. It was locked in their browser, so our server cannot read it either.</p>}
<form className="unlock" onSubmit={submit} noValidate>
<label className="field">
<span>Password</span>
<input className="input" type="password" value={password} onChange={(e) => { setPassword(e.target.value); setError(null); }} autoFocus
autoComplete="off" autoCapitalize="off" spellCheck={false} enterKeyHint="go"
aria-invalid={error ? true : undefined} aria-describedby={error ? "unlock-error" : undefined} />
{error && <span className="field-error" id="unlock-error" role="alert">{error}</span>}
</label>
<button className="btn" type="submit" aria-busy={busy || undefined}><Icon name="lock" /><span>Unlock</span></button>
</form>
</Message>
);
}
function PasteView({ id, paste }: { id: string; paste: Shown }) {
const isMarkdown = paste.language === "markdown";
const [rendered, setRendered] = useState(isMarkdown);
const [wrap, setWrap] = useState(() => matchMedia("(max-width: 640px)").matches);
const mine = savedPaste(id);
const lang = languageOf(paste.language);
const lines = paste.content.split("\n").length - (paste.content.endsWith("\n") ? 1 : 0);
const expires = paste.expiresAt ? Date.parse(paste.expiresAt) / 1000 : null;
// A paste encrypted with a key in the link uses the # for its key, so its lines cannot have links.
const secret = paste.encrypted && !paste.password ? linkSecret() : "";
const link = shareUrl(id, secret || undefined);
const lock = paste.password ? "Locked with a password" : paste.encrypted ? "Encrypted in the browser" : "";
const download = () => {
const name = (paste.title.replace(/[^\w.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60) || id) + (/\.\w{1,8}$/.test(paste.title) ? "" : `.${lang.ext}`);
const url = URL.createObjectURL(new Blob([paste.content], { type: "text/plain;charset=utf-8" }));
const a = Object.assign(document.createElement("a"), { href: url, download: name });
a.click();
setTimeout(() => URL.revokeObjectURL(url), 1000);
};
const fork = () => {
forkIntoEditor({ content: paste.content, title: paste.title, language: paste.language, lock: paste.password ? "password" : paste.encrypted ? "link" : "none" });
toast("A copy is in the editor. Change it, then create a new link.");
};
return (
<div className="view enter">
<header className="view-head">
<div className="wrap">
<h1 className="view-title">{paste.title || "Untitled paste"}</h1>
<p className="view-meta">
<span>{lang.name}</span>
<span>{lines.toLocaleString()} {lines === 1 ? "line" : "lines"}</span>
<span>{formatBytes(byteLength(paste.content))}</span>
{lock && <span>{lock}</span>}
{paste.deleted ? <span>Deleted after this view</span> : <span>{expires ? `Expires ${fromNow(expires)}` : "Never expires"}</span>}
</p>
</div>
</header>
<div className="wrap view-body">
{paste.deleted && (
<p className="notice notice-ok" role="status">This paste is now deleted from the server, and its link no longer works. This page is the only copy left, so copy or download it before you leave.</p>
)}
<div className="view-bar">
<div className="row view-toggles">
{isMarkdown && (
<div className="seg" role="group" aria-label="Show as">
<button type="button" aria-pressed={rendered} onClick={() => setRendered(true)}>Rendered</button>
<button type="button" aria-pressed={!rendered} onClick={() => setRendered(false)}>Source</button>
</div>
)}
{!rendered && (
<label className="check small"><input type="checkbox" checked={wrap} onChange={(e) => setWrap(e.target.checked)} /> Wrap lines</label>
)}
</div>
<div className="row view-actions">
<button className="btn btn-sm" type="button" onClick={() => copy(paste.content, "Copied the paste")}><Icon name="copy" size={16} /><span>Copy</span></button>
<button className="btn btn-sm btn-line" type="button" onClick={download}><Icon name="download" size={16} /><span>Download</span></button>
{!paste.deleted && (
<button className="btn btn-sm btn-line" type="button" onClick={() => share(link, paste.title || "Paste", "Link copied")}>
<Icon name={canShare() ? "share" : "link"} size={16} /><span>{canShare() ? "Share" : "Copy link"}</span>
</button>
)}
<Menu label="More actions">
{!paste.encrypted && !paste.burn && <a href={paste.rawUrl} target="_blank" rel="noopener">Open raw text</a>}
<button type="button" onClick={fork}>Edit a copy</button>
<button type="button" onClick={() => window.print()}>Print</button>
{mine && !paste.deleted && (
<>
<hr />
<a href={adminPath(mine)} onClick={(e) => { e.preventDefault(); navigate(adminPath(mine)); }}>Edit or delete</a>
</>
)}
</Menu>
</div>
</div>
{rendered ? (
<Suspense fallback={<div className="md md-loading" aria-busy="true"><span className="skeleton skeleton-text" /><span className="skeleton skeleton-text" /></div>}>
<Markdown text={paste.content} />
</Suspense>
) : (
<CodeView code={paste.content} language={paste.language} wrap={wrap} linkable={!secret && !paste.deleted} />
)}
<p className="view-foot">
<a href="/" onClick={(e) => { e.preventDefault(); navigate("/"); }}>Make your own paste</a>
<span>Free, no sign-up, unlisted.</span>
</p>
</div>
</div>
);
}
Change history
Quality pass: password lock, year expiry, line links, text/plain API
Bounded source sync
Bounded source sync
Bounded source sync