From 4919f028c884a041da7ff098abb02389b4eac598 Mon Sep 17 00:00:00 2001 From: 简律纯 Date: Tue, 18 Apr 2023 03:02:17 +0800 Subject: ✨add envshare docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/[compositeKey]/page.tsx | 7 -- app/components/analytics.tsx | 22 ----- app/components/error.tsx | 11 --- app/components/stats.tsx | 57 ----------- app/components/testimony.tsx | 125 ------------------------ app/components/title.tsx | 9 -- app/deploy/page.tsx | 89 ----------------- app/globals.css | 15 --- app/head.tsx | 42 -------- app/header.tsx | 60 ------------ app/layout.tsx | 58 ----------- app/page.tsx | 50 ---------- app/share/page.tsx | 227 ------------------------------------------- app/unseal/page.tsx | 159 ------------------------------ 14 files changed, 931 deletions(-) delete mode 100644 app/[compositeKey]/page.tsx delete mode 100644 app/components/analytics.tsx delete mode 100644 app/components/error.tsx delete mode 100644 app/components/stats.tsx delete mode 100644 app/components/testimony.tsx delete mode 100644 app/components/title.tsx delete mode 100644 app/deploy/page.tsx delete mode 100644 app/globals.css delete mode 100644 app/head.tsx delete mode 100644 app/header.tsx delete mode 100644 app/layout.tsx delete mode 100644 app/page.tsx delete mode 100644 app/share/page.tsx delete mode 100644 app/unseal/page.tsx (limited to 'app') diff --git a/app/[compositeKey]/page.tsx b/app/[compositeKey]/page.tsx deleted file mode 100644 index d91f182..0000000 --- a/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/app/components/analytics.tsx b/app/components/analytics.tsx deleted file mode 100644 index ef6a2ae..0000000 --- a/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/app/components/error.tsx b/app/components/error.tsx deleted file mode 100644 index acf36d7..0000000 --- a/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/app/components/stats.tsx b/app/components/stats.tsx deleted file mode 100644 index 31d74bc..0000000 --- a/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/chronark/envshare") - .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/app/components/testimony.tsx b/app/components/testimony.tsx deleted file mode 100644 index 757a953..0000000 --- a/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: Frederik Markor, - title: CEO @discreet, - image: "https://pbs.twimg.com/profile_images/1438061314010664962/NecuMIGR_400x400.jpg", - }, - }, - { - 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/app/components/title.tsx b/app/components/title.tsx deleted file mode 100644 index b9b7f3c..0000000 --- a/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/app/deploy/page.tsx b/app/deploy/page.tsx deleted file mode 100644 index b515144..0000000 --- a/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/app/globals.css b/app/globals.css deleted file mode 100644 index b764a11..0000000 --- a/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/app/head.tsx b/app/head.tsx deleted file mode 100644 index aecaa44..0000000 --- a/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/app/header.tsx b/app/header.tsx deleted file mode 100644 index 872459a..0000000 --- a/app/header.tsx +++ /dev/null @@ -1,60 +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/chronark/envshare", - 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/app/layout.tsx b/app/layout.tsx deleted file mode 100644 index 557407d..0000000 --- a/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{" "} - - @chronark_ - - and{" "} - - many others{" "} - -

-

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

-
-
- - - ); -} diff --git a/app/page.tsx b/app/page.tsx deleted file mode 100644 index ba659ca..0000000 --- a/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/app/share/page.tsx b/app/share/page.tsx deleted file mode 100644 index b6089f0..0000000 --- a/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 - -
-            
- - -