Skip to content

Commit f7b2772

Browse files
committed
feat: remove suggestedUrl and highlight page
1 parent 44890d1 commit f7b2772

File tree

17 files changed

+57
-130
lines changed

17 files changed

+57
-130
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ Error 401: incorrect passwd for basic auth
7373
$ curl -u admin1:this-is-passwd-1 -Fc=@/path/to/file example-pb.com
7474
{
7575
"url": "https://example-pb.com/YCDX",
76-
"suggestUrl": null,
7776
"admin": "https://example-pb.com/YCDX:Sij23HwbMjeZwKznY3K5trG8",
7877
"isPrivate": false
7978
}

doc/api.md

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ If the paste is uploaded with a `lang` parameter, an `X-PB-Highlight-Language` h
1818

1919
- `?a=`: optional. Set `Content-Disposition` to `attachment` if present.
2020

21-
- `?lang=<lang>`: optional. Returns a web page with syntax highlight powered by prism.js.
22-
2321
- `?mime=<mime>`: optional. Specify the mime-type, suppressing the effect of `<ext>`. No effect if `lang` is specified (in which case the mime-type is always `text/html`).
2422

2523
Examples: `GET /abcd?lang=js`, `GET /abcd?mime=application/json`.
@@ -37,8 +35,6 @@ https://web.archive.org/web/20210328091143/https://mp.weixin.qq.com/s/5phCQP7i-J
3735

3836
$ curl https://shz.al/~panty.jpg | feh -
3937

40-
$ firefox 'https://shz.al/kf7z?lang=nix'
41-
4238
$ curl 'https://shz.al/~panty.jpg?mime=image/png' -w '%{content_type}' -o /dev/null -sS
4339
image/png
4440

@@ -74,7 +70,7 @@ $ curl -L https://shz.al/u/i-p-
7470

7571
## GET `/d/<name>`
7672

77-
Return the web page that will decrypt the paste of name `<name>` in browser.
73+
Return the web page that will display the content of the paste of name `<name>`. If the paste is encrypted, a key can be appended to the URL to decrypt the paste of name `<name>` in browser.
7874

7975
If error occurs, the worker returns status code different from `302`:
8076

@@ -84,7 +80,7 @@ If error occurs, the worker returns status code different from `302`:
8480
Usage example:
8581

8682
```shell
87-
$ firefox https://shz.al/e/i-p-
83+
$ firefox https://shz.al/d/i-p-
8884
```
8985

9086
## GET `/m/<name>`
@@ -210,7 +206,6 @@ Upload your paste. It accept parameters in form-data:
210206
Explanation of the fields:
211207

212208
- `url`: String. The URL to fetch the paste. When using a customized name, it looks like `https//shz.al/~myname`.
213-
- `suggestedUrl`: Optional string. The URL that may carry filename or URL redirection.
214209
- `manageUrl`: String. The URL to update and delete the paste, which is `url` suffixed by `~` and the password.
215210
- `expirationSeconds`: String. The expiration seconds.
216211
- `expireAt`: String. An ISO String representing when the paste will expire.

frontend/components/UploadedPanel.tsx

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,16 +80,6 @@ export function UploadedPanel({
8080
<CopyWidget className={copyWidgetClassNames} getCopyContent={() => pasteResponse.manageUrl} />
8181
}
8282
/>
83-
{pasteResponse.suggestedUrl && (
84-
<Input
85-
{...inputProps}
86-
label={"Suggest URL"}
87-
value={pasteResponse.suggestedUrl}
88-
endContent={
89-
<CopyWidget className={copyWidgetClassNames} getCopyContent={() => pasteResponse.suggestedUrl!} />
90-
}
91-
/>
92-
)}
9383
<Input {...inputProps} label={"Expiration"} value={new Date(pasteResponse.expireAt).toLocaleString()} />
9484
</>
9585
)

frontend/decrypt.html renamed to frontend/display.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88
</head>
99
<body>
1010
<div id="root"></div>
11-
<script type="module" src="pages/render/decrypted.tsx"></script>
11+
<script type="module" src="pages/render/display.tsx"></script>
1212
</body>
1313
</html>

frontend/pages/DecryptPaste.tsx renamed to frontend/pages/DisplayPaste.tsx

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ function isBinaryPath(path: string) {
2222
return binaryExtensions.includes(path.replace(/.*\./, ""))
2323
}
2424

25-
export function DecryptPaste() {
25+
export function DisplayPaste() {
2626
const [pasteFile, setPasteFile] = useState<File | undefined>(undefined)
2727
const [pasteContentBuffer, setPasteContentBuffer] = useState<ArrayBuffer | undefined>(undefined)
2828
const [pasteLang, setPasteLang] = useState<string | undefined>(undefined)
2929

3030
const [isFileBinary, setFileBinary] = useState(false)
31-
const [isDecrypted, setDecrypted] = useState(false)
31+
const [isDecrypted, setDecrypted] = useState<"not encrypted" | "encrypted" | "decrypted">("not encrypted")
3232
const [forceShowBinary, setForceShowBinary] = useState(false)
3333
const showFileContent = pasteFile !== undefined && (!isFileBinary || forceShowBinary)
3434

@@ -40,11 +40,12 @@ export function DecryptPaste() {
4040

4141
const pasteStringContent = pasteContentBuffer && new TextDecoder().decode(pasteContentBuffer)
4242

43-
const pasteLineCount = (pasteStringContent?.match(/\n/g)?.length || 0) + 1
43+
const highlightedHTML = pasteStringContent ? highlightHTML(hljs, pasteLang, pasteStringContent) : ""
44+
const pasteLineCount = (highlightedHTML?.match(/\n/g)?.length || 0) + 1
4445

4546
// uncomment the following lines for testing
4647
// const url = new URL("http://localhost:8787/GQbf")
47-
const url = location
48+
const url = new URL(location.toString())
4849

4950
const { name, ext, filename } = parsePath(url.pathname)
5051

@@ -68,22 +69,24 @@ export function DecryptPaste() {
6869
filenameFromDisp = filenameFromDisp.replace(/.encrypted$/, "")
6970
}
7071

71-
const lang = resp.headers.get("X-PB-Highlight-Language")
72+
const lang = url.searchParams.get("lang") || resp.headers.get("X-PB-Highlight-Language")
7273

7374
const inferredFilename = filename || (ext && name + ext) || filenameFromDisp
7475
const respBytes = await resp.bytes()
7576
const isBinary = lang === null && inferredFilename !== undefined && isBinaryPath(inferredFilename)
7677
setPasteLang(lang || undefined)
77-
setFileBinary(isBinary)
7878

79-
if (scheme === null) {
79+
const keyString = url.hash.slice(1)
80+
if (scheme === null || keyString.length === 0) {
8081
setPasteFile(new File([respBytes], inferredFilename || name))
8182
setPasteContentBuffer(respBytes)
82-
} else {
83-
const keyString = url.hash.slice(1)
84-
if (keyString.length === 0) {
85-
showModal("Error", "No encryption key is given. You should append the key after a “#” character in the URL")
83+
if (scheme) {
84+
setDecrypted("encrypted")
85+
setFileBinary(true)
86+
} else {
87+
setFileBinary(isBinary)
8688
}
89+
} else {
8790
let key: CryptoKey | undefined
8891
try {
8992
key = await decodeKey(scheme, keyString)
@@ -108,7 +111,7 @@ export function DecryptPaste() {
108111

109112
const isBinary = lang === null && inferredFilename !== undefined && isBinaryPath(inferredFilename)
110113
setFileBinary(isBinary)
111-
setDecrypted(true)
114+
setDecrypted("decrypted")
112115
}
113116
} finally {
114117
setIsLoading(false)
@@ -120,17 +123,6 @@ export function DecryptPaste() {
120123
})
121124
}, [])
122125

123-
const fileIndicator = pasteFile && (
124-
<div className="text-foreground-600 mb-2 text-small">
125-
{`${pasteFile?.name} (${formatSize(pasteFile.size)})` + (pasteLang ? ` (${pasteLang})` : "")}
126-
{forceShowBinary && (
127-
<button className="ml-2 text-primary-500" onClick={() => setForceShowBinary(false)}>
128-
(Click to hide)
129-
</button>
130-
)}
131-
</div>
132-
)
133-
134126
const binaryFileIndicator = pasteFile && (
135127
<div className="absolute top-[50%] left-[50%] translate-[-50%] flex flex-col items-center w-full">
136128
<div className="text-foreground-600 mb-2">{`${pasteFile?.name} (${formatSize(pasteFile.size)})`}</div>
@@ -159,7 +151,9 @@ export function DecryptPaste() {
159151
</Link>
160152
<span className="mx-2">{" / "}</span>
161153
<code>{name}</code>
162-
<span className="ml-1">{isLoading ? " (Loading…)" : isDecrypted ? " (Decrypted)" : ""}</span>
154+
<span className="ml-1">
155+
{isDecrypted === "decrypted" ? " (Decrypted)" : isDecrypted === "encrypted" ? " (Encrypted)" : ""}
156+
</span>
163157
</h1>
164158
{showFileContent && (
165159
<Tooltip content={`Copy to clipboard`}>
@@ -178,19 +172,33 @@ export function DecryptPaste() {
178172
<DarkModeToggle modeSelection={modeSelection} setModeSelection={setModeSelection} />
179173
</div>
180174
<div className="my-4">
181-
<div className={`min-h-[30rem] w-full bg-default-50 rounded-lg p-3 relative ${tst}`}>
175+
<div className={`w-full bg-default-100 rounded-lg p-3 relative ${tst}`}>
182176
{isLoading ? (
183-
<CircularProgress className="absolute top-[50%] left-[50%] translate-[-50%]" />
177+
<div className={"h-[10em]"}>
178+
<CircularProgress
179+
className="h-[10em] absolute top-[50%] left-[50%] translate-[-50%]"
180+
label={"Loading..."}
181+
/>
182+
</div>
184183
) : (
185184
pasteFile && (
186-
<div>
185+
<div className={showFileContent ? "" : "h-[10em]"}>
187186
{showFileContent ? (
188187
<>
189-
{fileIndicator}
190-
<div className="font-mono whitespace-pre-wrap relative" role="article">
188+
<div className="text-foreground-600 mb-2 text-small flex flex-row gap-2">
189+
<span>{pasteFile?.name}</span>
190+
<span>{`(${formatSize(pasteFile.size)})`}</span>
191+
{forceShowBinary && (
192+
<button className="ml-2 text-primary-500" onClick={() => setForceShowBinary(false)}>
193+
(Click to hide)
194+
</button>
195+
)}
196+
{pasteLang && <span className={"grow text-right"}>{pasteLang}</span>}
197+
</div>
198+
<div className="font-mono relative" role="article">
191199
<pre
192200
style={{ paddingLeft: `${Math.floor(Math.log10(pasteLineCount)) + 2}em` }}
193-
dangerouslySetInnerHTML={{ __html: highlightHTML(hljs, pasteLang, pasteStringContent!) }}
201+
dangerouslySetInnerHTML={{ __html: highlightedHTML }}
194202
/>
195203
<span
196204
className={
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import ReactDOM from "react-dom/client"
22
import React from "react"
33
import { HeroUIProvider } from "@heroui/react"
4-
import { DecryptPaste } from "../DecryptPaste.js"
4+
import { DisplayPaste } from "../DisplayPaste.js"
55

66
const root = ReactDOM.createRoot(document.getElementById("root")!)
77

88
root.render(
99
<React.StrictMode>
1010
<HeroUIProvider>
11-
<DecryptPaste />
11+
<DisplayPaste />
1212
</HeroUIProvider>
1313
</React.StrictMode>,
1414
)

frontend/style.css

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
"Noto Color Emoji";
1111
--font-mono:
1212
"Cascadia Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
13-
--default-transition-duration: 5s;
1413
}
1514

1615
.color-tst {
@@ -45,3 +44,8 @@
4544
color: hsl(var(--heroui-foreground));
4645
background-color: hsl(var(--heroui-background));
4746
}
47+
48+
/* https://stackoverflow.com/questions/43492826/why-does-the-browser-not-render-a-line-break-caused-by-a-trailing-newline-charac */
49+
pre::after {
50+
content: "\A";
51+
}

frontend/test/decrypt.spec.tsx renamed to frontend/test/display.spec.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { describe, it, expect, beforeAll, afterEach, afterAll, vi } from "vitest"
22
import { cleanup, render, screen } from "@testing-library/react"
3-
import { DecryptPaste } from "../pages/DecryptPaste.js"
3+
import { DisplayPaste } from "../pages/DisplayPaste.js"
44

55
import "@testing-library/jest-dom/vitest"
66
import { userEvent } from "@testing-library/user-event"
@@ -42,7 +42,7 @@ describe("decrypt page", async () => {
4242
it("decrypt correctly", async () => {
4343
vi.stubGlobal("location", new URL(`https://example.com/e/abcd#${await encodeKey(key)}`))
4444
global.URL.createObjectURL = () => ""
45-
render(<DecryptPaste />)
45+
render(<DisplayPaste />)
4646

4747
const main = screen.getByRole("main")
4848
await userEvent.click(main) // meaningless click, just ensure useEffect is done

frontend/utils/uploader.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export async function uploadPaste(
4545
onEncryptionKeyChange(key)
4646
return new File([ciphertext], editorState.editFilename || "")
4747
} else {
48+
onEncryptionKeyChange(undefined)
4849
return new File([editorState.editContent], editorState.editFilename || "")
4950
}
5051
}

frontend/vite.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export default defineConfig(({ mode }) => {
5050
rollupOptions: {
5151
input: {
5252
index: resolve(__dirname, "index.html"),
53-
decrypt: resolve(__dirname, "decrypt.html"),
53+
display: resolve(__dirname, "display.html"),
5454
},
5555
},
5656
},

0 commit comments

Comments
 (0)