| 1 | 1 | | import { env } from "cloudflare:workers"; |
| 2 | 2 | | import { connectLink } from "@g1t/contracts/discovery"; |
| 3 | | − | import { ArrowRight, Bell, Download, Link2, RefreshCw, Server, Smartphone } from "lucide-react"; |
| 3 | + | import { ArrowRight, Bell, Download, Link2, RefreshCw, Server, ShieldAlert, Smartphone } from "lucide-react"; |
| 4 | 4 | | import { type ReactNode, useEffect, useRef, useState } from "react"; |
| 5 | 5 | | import { useLoaderData } from "react-router"; |
| 6 | 6 | | |
| ⋯ |
| 9 | 9 | | import { QrCode } from "../components/qr-code"; |
| 10 | 10 | | import { ButtonLink } from "../components/ui"; |
| 11 | 11 | | import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "../components/ui/accordion"; |
| 12 | + | import { Alert, AlertDescription, AlertTitle } from "../components/ui/alert"; |
| 12 | 13 | | import { Badge } from "../components/ui/badge"; |
| 13 | 14 | | import { Button } from "../components/ui/button"; |
| 14 | 15 | | import { Card, CardContent } from "../components/ui/card"; |
| ⋯ |
| 134 | 135 | | ios: { name: "iOS", device: "iPhone", note: "" }, |
| 135 | 136 | | }; |
| 136 | 137 | | |
| 138 | + | /** |
| 139 | + | * What each system says about an app that isn't code-signed, and how to |
| 140 | + | * open it anyway. Every build is unsigned while g1t is in alpha. |
| 141 | + | */ |
| 142 | + | const UNSIGNED: Record<PlatformId, string | null> = { |
| 143 | + | windows: "Windows may say it protected your PC: choose More info, then Run anyway.", |
| 144 | + | macos: "macOS may say it can't check g1t: open System Settings, Privacy & Security, and choose Open Anyway.", |
| 145 | + | linux: "Your package manager may say the package isn't signed. The AppImage needs only to be made executable.", |
| 146 | + | android: "Play Protect may warn about an unknown app: choose More details, then Install anyway.", |
| 147 | + | ios: null, |
| 148 | + | }; |
| 149 | + | |
| 137 | 150 | | const KINDS: Record<string, string> = { |
| 138 | 151 | | installer: "Installer", |
| 139 | 152 | | dmg: "Disk image", |
| ⋯ |
| 227 | 240 | | ))} |
| 228 | 241 | | </TabsList> |
| 229 | 242 | | </div> |
| 243 | + | <Alert tone="warn" className="mx-auto mt-6 flex max-w-3xl gap-3 px-4 py-3"> |
| 244 | + | <ShieldAlert size={16} className="mt-0.5 shrink-0 text-warn" /> |
| 245 | + | <div> |
| 246 | + | <AlertTitle>Unsigned while g1t is in alpha</AlertTitle> |
| 247 | + | <AlertDescription> |
| 248 | + | The desktop app, the Android app, the runner and the CLI aren't code-signed yet, so your system warns you before it opens them.{" "} |
| 249 | + | {UNSIGNED[tab] ?? "Every download here is unsigned until g1t leaves alpha."} Each file's SHA-256 is listed to check it against. |
| 250 | + | </AlertDescription> |
| 251 | + | </div> |
| 252 | + | </Alert> |
| 230 | 253 | | {PLATFORM_IDS.map((id) => ( |
| 231 | 254 | | <TabsContent key={id} value={id} className="mt-6"> |
| 232 | 255 | | {isDesktop(id) ? ( |
| ⋯ |
| 648 | 671 | | <AccordionTrigger>Why a download, and not Google Play or the App Store?</AccordionTrigger> |
| 649 | 672 | | <AccordionContent> |
| 650 | 673 | | Both stores publish a company's apps only once it is verified with a D-U-N-S number, and Flagon's is on its way. Until then the Android app is |
| 651 | | − | published {hosted ? "here" : "on g1t.sh"}, signed by g1t, as the desktop app is. It moves into Google Play as soon as it can, and iOS follows |
| 652 | | − | through the App Store. |
| 674 | + | published {hosted ? "here" : "on g1t.sh"}, as the desktop app is. It moves into Google Play as soon as it can, and iOS follows through the App |
| 675 | + | Store. |
| 653 | 676 | | </AccordionContent> |
| 654 | 677 | | </AccordionItem> |
| 655 | | − | <AccordionItem value="macos"> |
| 656 | | − | <AccordionTrigger>Why does macOS ask before opening it?</AccordionTrigger> |
| 657 | | − | <AccordionContent>The app isn't notarized with Apple yet. The first time, right-click it and choose Open.</AccordionContent> |
| 678 | + | <AccordionItem value="unsigned"> |
| 679 | + | <AccordionTrigger>Why does my system warn me before opening it?</AccordionTrigger> |
| 680 | + | <AccordionContent> |
| 681 | + | <p> |
| 682 | + | While g1t is in alpha, none of its builds are code-signed: not the desktop app, the Android app, the runner or the CLI. Your system can't tell |
| 683 | + | who made them, so it warns you the first time. To open one anyway: |
| 684 | + | </p> |
| 685 | + | <ul className="mt-3 space-y-1.5"> |
| 686 | + | {(["windows", "macos", "linux", "android"] as const).map((id) => ( |
| 687 | + | <li key={id}> |
| 688 | + | <span className="text-fg-soft">{PLATFORMS[id].name}:</span> {UNSIGNED[id]} |
| 689 | + | </li> |
| 690 | + | ))} |
| 691 | + | </ul> |
| 692 | + | <p className="mt-3"> |
| 693 | + | Check a download against its SHA-256 first. The desktop app's own updates are checked against g1t's signature before they install. |
| 694 | + | </p> |
| 695 | + | </AccordionContent> |
| 658 | 696 | | </AccordionItem> |
| 659 | 697 | | <AccordionItem value="check"> |
| 660 | 698 | | <AccordionTrigger>How do I check a download?</AccordionTrigger> |