From 3adc965dd09490b7efa1cce9f09b0a3b30970277 Mon Sep 17 00:00:00 2001 From: 简律纯 Date: Wed, 19 Apr 2023 17:30:39 +0800 Subject: ✨优化文档 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- envshare/.eslintrc.json | 3 - envshare/.gitignore | 36 - envshare/LICENSE | 21 - envshare/README.md | 139 - envshare/app/[compositeKey]/page.tsx | 7 - envshare/app/components/analytics.tsx | 22 - envshare/app/components/error.tsx | 11 - envshare/app/components/stats.tsx | 57 - envshare/app/components/testimony.tsx | 125 - envshare/app/components/title.tsx | 9 - envshare/app/deploy/page.tsx | 89 - envshare/app/globals.css | 15 - envshare/app/head.tsx | 42 - envshare/app/header.tsx | 59 - envshare/app/layout.tsx | 58 - envshare/app/page.tsx | 50 - envshare/app/share/page.tsx | 227 -- envshare/app/unseal/page.tsx | 159 -- envshare/img/envshare.png | Bin 275552 -> 0 bytes envshare/jest.config.js | 6 - envshare/next.config.js | 11 - envshare/package.json | 42 - envshare/pages/api/v1/load.ts | 36 - envshare/pages/api/v1/og.tsx | 64 - envshare/pages/api/v1/secret/[id].ts | 58 - envshare/pages/api/v1/secret/index.ts | 96 - envshare/pages/api/v1/store.ts | 38 - envshare/pkg/constants.ts | 3 - envshare/pkg/encoding.test.ts | 23 - envshare/pkg/encoding.ts | 31 - envshare/pkg/encryption.test.ts | 24 - envshare/pkg/encryption.ts | 51 - envshare/pkg/id.ts | 8 - envshare/pnpm-lock.yaml | 4505 ------------------------------ envshare/postcss.config.js | 6 - envshare/public/fonts/Inter-SemiBold.ttf | Bin 315756 -> 0 bytes envshare/rome.json | 26 - envshare/tailwind.config.js | 18 - envshare/tsconfig.json | 30 - envshare/util/base58.ts | 7 - 40 files changed, 6212 deletions(-) delete mode 100644 envshare/.eslintrc.json delete mode 100644 envshare/.gitignore delete mode 100644 envshare/LICENSE delete mode 100644 envshare/README.md delete mode 100644 envshare/app/[compositeKey]/page.tsx delete mode 100644 envshare/app/components/analytics.tsx delete mode 100644 envshare/app/components/error.tsx delete mode 100644 envshare/app/components/stats.tsx delete mode 100644 envshare/app/components/testimony.tsx delete mode 100644 envshare/app/components/title.tsx delete mode 100644 envshare/app/deploy/page.tsx delete mode 100644 envshare/app/globals.css delete mode 100644 envshare/app/head.tsx delete mode 100644 envshare/app/header.tsx delete mode 100644 envshare/app/layout.tsx delete mode 100644 envshare/app/page.tsx delete mode 100644 envshare/app/share/page.tsx delete mode 100644 envshare/app/unseal/page.tsx delete mode 100644 envshare/img/envshare.png delete mode 100644 envshare/jest.config.js delete mode 100644 envshare/next.config.js delete mode 100644 envshare/package.json delete mode 100644 envshare/pages/api/v1/load.ts delete mode 100644 envshare/pages/api/v1/og.tsx delete mode 100644 envshare/pages/api/v1/secret/[id].ts delete mode 100644 envshare/pages/api/v1/secret/index.ts delete mode 100644 envshare/pages/api/v1/store.ts delete mode 100644 envshare/pkg/constants.ts delete mode 100644 envshare/pkg/encoding.test.ts delete mode 100644 envshare/pkg/encoding.ts delete mode 100644 envshare/pkg/encryption.test.ts delete mode 100644 envshare/pkg/encryption.ts delete mode 100644 envshare/pkg/id.ts delete mode 100644 envshare/pnpm-lock.yaml delete mode 100644 envshare/postcss.config.js delete mode 100644 envshare/public/fonts/Inter-SemiBold.ttf delete mode 100644 envshare/rome.json delete mode 100644 envshare/tailwind.config.js delete mode 100644 envshare/tsconfig.json delete mode 100644 envshare/util/base58.ts (limited to 'envshare') diff --git a/envshare/.eslintrc.json b/envshare/.eslintrc.json deleted file mode 100644 index bffb357..0000000 --- a/envshare/.eslintrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "next/core-web-vitals" -} diff --git a/envshare/.gitignore b/envshare/.gitignore deleted file mode 100644 index a333bff..0000000 --- a/envshare/.gitignore +++ /dev/null @@ -1,36 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* -.pnpm-debug.log* - -# local env files -.env* - -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts diff --git a/envshare/LICENSE b/envshare/LICENSE deleted file mode 100644 index e4712ee..0000000 --- a/envshare/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2023 Andreas Thomas - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/envshare/README.md b/envshare/README.md deleted file mode 100644 index f890f9d..0000000 --- a/envshare/README.md +++ /dev/null @@ -1,139 +0,0 @@ -
-

EnvShare

-
Share Environment Variables Securely
-
- -
- envshare.dev -
-
- -EnvShare is a simple tool to share environment variables securely. It uses -**AES-GCM** to encrypt your data before sending it to the server. The encryption -key never leaves your browser. - -## Features - -- **Shareable Links:** Share your environment variables securely by sending a - link -- **End-to-End Encryption:** AES-GCM encryption is used to encrypt your data - before sending it to the server -- **Limit number of reads:** Limit the number of times a link can be read -- **Auto Expire:** Automatically expire links and delete data after a certain - time - -
- -![](img/envshare.png) - -## Built with - -- [Next.js](https://nextjs.org) -- [tailwindcss](https://tailwindcss.com) -- Deployed on [Vercel](https://vercel.com?utm_source=envshare) -- Data stored on [Upstash](https://upstash.com?utm_source=envshare) - -## Deploy your own - -Detailed instructions can be found [here](https://envshare.dev/deploy) - -All you need is a Redis database on Upstash and a Vercel account. Click the -button below to clone and deploy: - -[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?demo-title=EnvShare&demo-description=Simple%20Next.js%20%2B%20Upstash%20app%20to%20share%20environment%20variables%20securely%20using%20AES-GCM%20encryption.&demo-url=https%3A%2F%2Fenvshare.dev%2F&demo-image=%2F%2Fimages.ctfassets.net%2Fe5382hct74si%2F5SaFBHXp5FBFJbsTzVqIJ3%2Ff0f8382369b7642fd8103debb9025c11%2Fenvshare.png&project-name=EnvShare&repository-name=envshare&repository-url=https%3A%2F%2Fgithub.com%2Fchronark%2Fenvshare&from=templates&integration-ids=oac_V3R1GIpkoJorr6fqyiwdhl17) - - -## Sponsors - - - - - -
- - - Upstash - -

Upstash: Serverless Database for Redis

- -
    -
  • Serverless Redis with global replication and durable storage
  • -
  • Price scales to zero with per request pricing
  • -
  • Built-in REST API designed for serverless and edge functions
  • -
- -[Start for free in 30 seconds!](https://upstash.com/?utm_source=envshare) - -
- -## Configuration - -### Environment Variables - -`ENABLE_VERCEL_ANALYTICS` Any truthy value will enable Vercel Analytics. This is turned off by default - -## Contributing - -This repository uses `pnpm` to manage dependencies. Install it using -`npm install -g pnpm` - -Please run `pnpm fmt` before committing to format the code. - -## Docs - -Docs in the README are temporary and will be moved to the website soon. - -### API - -#### Store a secret - -**PLEASE NEVER EVER UPLOAD UNENCRYPTED SECRETS.** - -This endpoint is only meant to store **already encrypted** secrets. The -encrypted secrets are stored in plain text. - -```sh-session -$ curl -XPOST -s https://envshare.dev/api/v1/secret -d "already-encrypted-secret" -``` - -You can add optional headers to configure the ttl and number of reads. - -```sh-session -$ curl -XPOST -s https://envshare.dev/api/v1/secret -d "already-encrypted-secret" -H "envshare-ttl: 3600" -H "envshare-reads: 10" -``` - -- Omitting the `envshare-ttl` header will set a default of 30 days. Disable the - ttl by setting it to 0. (`envshare-ttl: 0`) -- Omitting the `envshare-reads` header will simply disable it and allow reading - for an unlimited number of times. - -This endpoint returns a JSON response with the secret id: - -```json -{ - "data": { - "id": "HdPbXgpvUvNk43oxSdK97u", - "ttl": 86400, - "reads": 2, - "expiresAt": "2023-01-19T20:47:28.383Z", - "url": "http://envshare.dev/api/v1/secret/HdPbXgpvUvNk43oxSdK97u" - } -} -``` - -#### Retrieve a secret - -You need an id to retrieve a secret. The id is returned when you store a secret. - -```sh-session -$ curl -s https://envshare.dev/api/v1/secret/HdPbXgpvUvNk43oxSdK97u -``` - -```json -{ - "data": { - "secret": "Hello", - "remainingReads": 1 - } -} -``` diff --git a/envshare/app/[compositeKey]/page.tsx b/envshare/app/[compositeKey]/page.tsx deleted file mode 100644 index d91f182..0000000 --- a/envshare/app/[compositeKey]/page.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { redirect } from "next/navigation"; - -// This page is here for backwards compatibility with old links. -// Old links were of the form /{compositeKey} and now they are of the form /unseal#{compositeKey} -export default function Page(props: { params: { compositeKey: string } }) { - return redirect(`/unseal#${props.params.compositeKey}`); -} diff --git a/envshare/app/components/analytics.tsx b/envshare/app/components/analytics.tsx deleted file mode 100644 index ef6a2ae..0000000 --- a/envshare/app/components/analytics.tsx +++ /dev/null @@ -1,22 +0,0 @@ -"use client"; -import { Analytics as VercelAnalytics } from "@vercel/analytics/react"; - -const track = ["/", "/share", "/deploy", "/unseal"]; - -export function Analytics() { - return ( - { - const url = new URL(event.url); - if (!track.includes(url.pathname)) { - url.pathname = "/__redacted"; - return { - ...event, - url: url.href, - }; - } - return event; - }} - /> - ); -} diff --git a/envshare/app/components/error.tsx b/envshare/app/components/error.tsx deleted file mode 100644 index acf36d7..0000000 --- a/envshare/app/components/error.tsx +++ /dev/null @@ -1,11 +0,0 @@ -type Props = { - message: string; -}; - -export const ErrorMessage: React.FC = ({ message }) => { - return ( -
- {message} -
- ); -}; diff --git a/envshare/app/components/stats.tsx b/envshare/app/components/stats.tsx deleted file mode 100644 index be1aa71..0000000 --- a/envshare/app/components/stats.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { Redis } from "@upstash/redis"; - -const redis = Redis.fromEnv(); -export const revalidate = 60; - -export const Stats = asyncComponent(async () => { - const [reads, writes] = await redis - .pipeline() - .get("envshare:metrics:reads") - .get("envshare:metrics:writes") - .exec<[number, number]>(); - const stars = await fetch("https://api.github.com/repos/retrofor/ChienDice") - .then((res) => res.json()) - .then((json) => json.stargazers_count as number); - - const stats = [ - { - label: "Documents Encrypted", - value: writes, - }, - { - label: "Documents Decrypted", - value: reads, - }, - ] satisfies { label: string; value: number }[]; - - if (stars) { - stats.push({ - label: "GitHub Stars", - value: stars, - }); - } - - return ( -
-
    - {stats.map(({ label, value }) => ( -
  • -
    - {Intl.NumberFormat("en-US", { notation: "compact" }).format(value)} -
    -
    {label}
    -
  • - ))} -
-
- ); -}); - -// stupid hack to make "server components" actually work with components -// https://www.youtube.com/watch?v=h_9Vx6kio2s -function asyncComponent(fn: (arg: T) => Promise): (arg: T) => R { - return fn as (arg: T) => R; -} diff --git a/envshare/app/components/testimony.tsx b/envshare/app/components/testimony.tsx deleted file mode 100644 index c48479a..0000000 --- a/envshare/app/components/testimony.tsx +++ /dev/null @@ -1,125 +0,0 @@ -"use client"; -import Image from "next/image"; -import Link from "next/link"; -import { Props } from "next/script"; -import React, { PropsWithChildren } from "react"; - -const TwitterHandle: React.FC = ({ children }) => { - return {children}; -}; - -const Author: React.FC> = ({ children, href }) => ( - - {children} - -); - -const Title: React.FC> = ({ children, href }) => ( - - {children} - -); - -export const Testimonials = () => { - const posts: { - content: React.ReactNode; - link: string; - author: { - name: React.ReactNode; - title?: React.ReactNode; - image: string; - }; - }[] = [ - { - content: ( -
-

- My cursory audit of @chronark_'s envshare: -

-

- It is light, extremely functional, and does its symmetric block cipher correctly, unique initialization - vectors, decryption keys derived securely. -

-
-

Easily modified to remove minimal analytics. Superior to Privnote.

-
-

Self-hosting is easy. 👏

-
- ), - link: "https://twitter.com/FrederikMarkor/status/1615299856205250560", - author: { - name: HsiangNianian, - title: Owner/Contributor @简律纯, - image: "https://github.com/HsiangNianian.png", - }, - }, - // { - // content: ( - //
- //

I'm particularly chuffed about this launch, for a couple of reasons:

- //
    - //
  • - // ◆ Built on @nextjs + @upstash, hosted on{" "} - // @vercel - //
  • - //
  • ◆ 100% free to use & open source
  • - //
  • ◆ One-click deploy via Vercel + Upstash integration
  • - //
- //

Deploy your own → http://vercel.fyi/envshare

- //
- // ), - // link: "https://twitter.com/steventey/status/1615035241772482567?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1615035241772482567%7Ctwgr%5E1db44bb10c690189e24c980fcd787299961c34c6%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fpublish.twitter.com%2F%3Fquery%3Dhttps3A2F2Ftwitter.com2Fsteventey2Fstatus2F1615035241772482567widget%3DTweet", - // author: { - // name: Steven Tey, - // title: Senior Developer Advocate at Vercel, - // image: "https://pbs.twimg.com/profile_images/1506792347840888834/dS-r50Je_400x400.jpg", - // }, - // }, - // { - // content: ( - //
- //

- // Congratulations on the launch @chronark_👏! This is such a valuable product - // for developers. Icing on the cake is that it's open source! ✨ - //

- //
- // ), - // link: "https://twitter.com/DesignSiddharth/status/1615293209164546048", - // author: { - // name: @DesignSiddharth, - // image: "https://pbs.twimg.com/profile_images/1613772710009765888/MbSblJYf_400x400.jpg", - // }, - // }, - ]; - - return ( -
-
    - {posts.map((post, i) => ( -
    - - {post.content} - -
    -
    -
    {post.author.name}
    -
    {post.author.title}
    -
    -
    - -
    -
    -
    - ))} -
-
- ); -}; diff --git a/envshare/app/components/title.tsx b/envshare/app/components/title.tsx deleted file mode 100644 index b9b7f3c..0000000 --- a/envshare/app/components/title.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import React, { PropsWithChildren } from "react"; - -export const Title: React.FC = ({ children }): JSX.Element => { - return ( -

- {children} -

- ); -}; diff --git a/envshare/app/deploy/page.tsx b/envshare/app/deploy/page.tsx deleted file mode 100644 index b515144..0000000 --- a/envshare/app/deploy/page.tsx +++ /dev/null @@ -1,89 +0,0 @@ -"use client"; -import { ArrowTopRightOnSquareIcon } from "@heroicons/react/20/solid"; -import Link from "next/link"; -import { Title } from "@components/title"; -import React from "react"; -const steps: { - name: string; - description: string | React.ReactNode; - cta?: React.ReactNode; -}[] = [ - { - name: "Create a new Redis database on Upstash", - description: ( - <> - Upstash offers a serverless Redis database with a generous free tier of up to 10,000 requests per day. That's - more than enough. -
- Click the button below to sign up and create a new Redis database on Upstash. - - ), - cta: ( - - Create Database - - - ), - }, - { - name: "Copy the REST connection credentials", - description: ( -

- After creating the database, scroll to the bottom and make a note of UPSTASH_REDIS_REST_URL and{" "} - UPSTASH_REDIS_REST_TOKEN, you need them in the next step -

- ), - }, - { - name: "Deploy to Vercel", - description: "Deploy the app to Vercel and paste the connection credentials into the environment variables.", - cta: ( - - Deploy - - - ), - }, -]; - -export default function Deploy() { - return ( -
- Deploy EnvShare for Free -

- You can deploy your own hosted version of EnvShare, you just need an Upstash and Vercel account. -

-
    - {steps.map((step, stepIdx) => ( -
  1. -
  2. - ))} -
-
- ); -} diff --git a/envshare/app/globals.css b/envshare/app/globals.css deleted file mode 100644 index b764a11..0000000 --- a/envshare/app/globals.css +++ /dev/null @@ -1,15 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -@layer utilities { - input[type="number"]::-webkit-inner-spin-button, - input[type="number"]::-webkit-outer-spin-button { - @apply appearance-none; - } - - - input[type="file"] { - @apply appearance-none; - } -} \ No newline at end of file diff --git a/envshare/app/head.tsx b/envshare/app/head.tsx deleted file mode 100644 index aecaa44..0000000 --- a/envshare/app/head.tsx +++ /dev/null @@ -1,42 +0,0 @@ -export default function Head({ title, subtitle }: { title: string; subtitle: string }) { - // Fallback tagline - title ??= "Share Environment Variables Securely"; - subtitle ??= "EnvShare"; - - const baseUrl = process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : "http://localhost:3000"; - - const url = new URL("/api/v1/og", baseUrl); - url.searchParams.set("title", title); - url.searchParams.set("subtitle", subtitle); - - return ( - <> - EnvShare - - - - - - - - - - - {/* Open Graph / Facebook */} - - - - - - - - - {/* Twitter */} - - - - - - - ); -} diff --git a/envshare/app/header.tsx b/envshare/app/header.tsx deleted file mode 100644 index 9d6a3fe..0000000 --- a/envshare/app/header.tsx +++ /dev/null @@ -1,59 +0,0 @@ -"use client"; -import React from "react"; -import Link from "next/link"; -import { usePathname } from "next/navigation"; - -const navigation = [ - { - name: "Share", - href: "/share", - }, - { - name: "Unseal", - href: "/unseal", - }, - // { - // name: "Deploy", - // href: "/deploy", - // }, - { - name: "GitHub", - href: "https://github.com/retrofor/ChienDice", - external: true, - }, -] satisfies { name: string; href: string; external?: boolean }[]; - -export const Header: React.FC = () => { - const pathname = usePathname(); - return ( -
-
-
- - EnvShare - - {/* Desktop navigation */} - -
-
- - {/* Fancy fading bottom border */} -
- ); -}; diff --git a/envshare/app/layout.tsx b/envshare/app/layout.tsx deleted file mode 100644 index e7d8419..0000000 --- a/envshare/app/layout.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import "./globals.css"; -import { Inter } from "@next/font/google"; -import Link from "next/link"; -import { Header } from "./header"; - -import { Analytics } from "@components/analytics"; -const inter = Inter({ subsets: ["latin"], variable: "--font-inter" }); - -export default function RootLayout({ - children, -}: { - children: React.ReactNode; -}) { - return ( - - - - { - // Not everyone will want to host envshare on Vercel, so it makes sense to make this opt-in. - process.env.ENABLE_VERCEL_ANALYTICS ? : null - } - -
- -
{children}
- -
-
-

- Built by{" "} - - @简律纯 - - and{" "} - - many others{" "} - -

-

- EnvShare is deployed on{" "} - - Vercel - {" "} - and uses{" "} - - Upstash - {" "} - for storing encrypted data. -

-
-
- - - ); -} diff --git a/envshare/app/page.tsx b/envshare/app/page.tsx deleted file mode 100644 index 5cda54d..0000000 --- a/envshare/app/page.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import Link from "next/link"; -import { Stats } from "./components/stats"; -import { Testimonials } from "./components/testimony"; - -export default function Home() { - return ( -
-
-
- - EnvShare is Open Source on{" "} - - GitHub - - -
-
-

- Share Environment Variables Securely -

-

- Your document is encrypted in your browser before being stored for a limited period of time and read - operations. Unencrypted data never leaves your browser. -

-
- {/* - Deploy - */} - - Share - - -
-
-
-

Used and trusted by a growing community

- - -
- ); -} diff --git a/envshare/app/share/page.tsx b/envshare/app/share/page.tsx deleted file mode 100644 index b6089f0..0000000 --- a/envshare/app/share/page.tsx +++ /dev/null @@ -1,227 +0,0 @@ -"use client"; -import { toBase58 } from "util/base58"; -import { useState, Fragment } from "react"; -import { Cog6ToothIcon, ClipboardDocumentIcon, ClipboardDocumentCheckIcon } from "@heroicons/react/24/outline"; -import { Title } from "@components/title"; -import { encrypt } from "pkg/encryption"; -import { ErrorMessage } from "@components/error"; -import { encodeCompositeKey } from "pkg/encoding"; -import { LATEST_KEY_VERSION } from "pkg/constants"; - -export default function Home() { - const [text, setText] = useState(""); - const [reads, setReads] = useState(999); - - const [ttl, setTtl] = useState(7); - const [ttlMultiplier, setTtlMultiplier] = useState(60 * 60 * 24); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(""); - const [copied, setCopied] = useState(false); - - const [link, setLink] = useState(""); - - const onSubmit = async () => { - try { - setError(""); - setLink(""); - setLoading(true); - - const { encrypted, iv, key } = await encrypt(text); - - const { id } = (await fetch("/api/v1/store", { - method: "POST", - body: JSON.stringify({ - ttl: ttl * ttlMultiplier, - reads, - encrypted: toBase58(encrypted), - iv: toBase58(iv), - }), - }).then((r) => r.json())) as { id: string }; - - const compositeKey = encodeCompositeKey(LATEST_KEY_VERSION, id, key); - - const url = new URL(window.location.href); - url.pathname = "/unseal"; - url.hash = compositeKey; - setCopied(false); - setLink(url.toString()); - } catch (e) { - console.error(e); - setError((e as Error).message); - } finally { - setLoading(false); - } - }; - - return ( -
- {error ? : null} - - {link ? ( -
- Share this link with others -
-
-              {link}
-            
- -
-
- ) : ( -
{ - e.preventDefault(); - if (text.length <= 0) return; - onSubmit(); - }} - > - Encrypt and Share - -
-            
- - -