479 lines
28 KiB
HTML
479 lines
28 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en" prefix="og: https://ogp.me/ns#">
|
|
<head>
|
|
<meta charset="utf-8"/>
|
|
<title>Web installer | Install | GrapheneOS</title>
|
|
<meta name="description" content="Web-based installer for GrapheneOS, a security and privacy focused mobile OS with Android app compatibility."/>
|
|
<meta name="theme-color" content="#212121"/>
|
|
<meta name="color-scheme" content="dark light"/>
|
|
<meta name="msapplication-TileColor" content="#ffffff"/>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
<meta name="twitter:site" content="@GrapheneOS"/>
|
|
<meta name="twitter:creator" content="@GrapheneOS"/>
|
|
<meta property="og:title" content="GrapheneOS web installer"/>
|
|
<meta property="og:description" content="Web-based installer for GrapheneOS, a security and privacy focused mobile OS with Android app compatibility."/>
|
|
<meta property="og:type" content="website"/>
|
|
<meta property="og:image" content="https://grapheneos.org/opengraph.png"/>
|
|
<meta property="og:image:width" content="512"/>
|
|
<meta property="og:image:height" content="512"/>
|
|
<meta property="og:image:alt" content="GrapheneOS logo"/>
|
|
<meta property="og:site_name" content="GrapheneOS"/>
|
|
<meta property="og:url" content="https://grapheneos.org/install/web"/>
|
|
<link rel="canonical" href="https://grapheneos.org/install/web"/>
|
|
<link rel="icon" href="/favicon.ico"/>
|
|
<link rel="icon" sizes="any" type="image/svg+xml" href="/favicon.svg"/>
|
|
<link rel="mask-icon" href="{{path|/mask-icon.svg}}" color="#1a1a1a"/>
|
|
<link rel="apple-touch-icon" href="/apple-touch-icon.png"/>
|
|
{{css|/main.css}}
|
|
<link rel="manifest" href="/manifest.webmanifest"/>
|
|
<link rel="license" href="/LICENSE.txt"/>
|
|
<link rel="me" href="https://grapheneos.social/@GrapheneOS"/>
|
|
{{js|/js/redirect.js}}
|
|
<script type="module" src="/js/fastboot/066d736d/fastboot.min.mjs" integrity="sha256-mH1JDLfpm9jffXPX8pRlbJtTYkMcXN7LSLXNhCM9P4E="></script>
|
|
{{js|/js/web-install.js}}
|
|
</head>
|
|
<body>
|
|
<header>
|
|
<nav id="site-menu">
|
|
<ul>
|
|
<li><a href="/"><img src="{{path|/mask-icon.svg}}" alt=""/>GrapheneOS</a></li>
|
|
<li><a href="/features">Features</a></li>
|
|
<li><a href="/install/">Install</a></li>
|
|
<li><a href="/build">Build</a></li>
|
|
<li><a href="/usage">Usage</a></li>
|
|
<li><a href="/faq">FAQ</a></li>
|
|
<li><a href="/releases">Releases</a></li>
|
|
<li><a href="/source">Source</a></li>
|
|
<li><a href="/history/">History</a></li>
|
|
<li><a href="/articles/">Articles</a></li>
|
|
<li><a href="/donate">Donate</a></li>
|
|
<li><a href="/contact">Contact</a></li>
|
|
</ul>
|
|
</nav>
|
|
</header>
|
|
<main id="web-install">
|
|
<h1><a href="#web-install">Web installer</a></h1>
|
|
|
|
<p>This is the WebUSB-based installer for GrapheneOS and is the recommended approach
|
|
for most users. The <a href="/install/cli">command-line installation guide</a> is the
|
|
more traditional approach to installing GrapheneOS.</p>
|
|
|
|
<p>If you have trouble with the installation process, ask for help on the
|
|
<a href="/contact#community">official GrapheneOS chat channel</a>. There are almost
|
|
always people around willing to help with it. Before asking for help, make an attempt
|
|
to follow the guide on your own and then ask for help with anything you get stuck
|
|
on.</p>
|
|
|
|
<nav id="table-of-contents">
|
|
<h2><a href="#table-of-contents">Table of contents</a></h2>
|
|
|
|
<ul>
|
|
<li><a href="#prerequisites">Prerequisites</a></li>
|
|
<li><a href="#enabling-oem-unlocking">Enabling OEM unlocking</a></li>
|
|
<li><a href="#flashing-as-non-root">Flashing as non-root</a></li>
|
|
<li><a href="#booting-into-the-bootloader-interface">Booting into the bootloader interface</a></li>
|
|
<li><a href="#connecting-phone">Connecting the phone</a></li>
|
|
<li><a href="#unlocking-the-bootloader">Unlocking the bootloader</a></li>
|
|
<li><a href="#obtaining-factory-images">Obtaining factory images</a></li>
|
|
<li><a href="#flashing-factory-images">Flashing factory images</a></li>
|
|
<li><a href="#locking-the-bootloader">Locking the bootloader</a></li>
|
|
<li>
|
|
<a href="#post-installation">Post-installation</a>
|
|
<ul>
|
|
<li><a href="#booting">Booting</a></li>
|
|
<li><a href="#disabling-oem-unlocking">Disabling OEM unlocking</a></li>
|
|
<li>
|
|
<a href="#verifying-installation">Verifying installation</a>
|
|
<ul>
|
|
<li><a href="#verified-boot-key-hash">Verified boot key hash</a></li>
|
|
<li><a href="#hardware-based-attestation">Hardware-based attestation</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#replacing-grapheneos-with-the-stock-os">Replacing GrapheneOS with the stock OS</a></li>
|
|
<li><a href="#further-information">Further information</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
|
|
<section id="prerequisites">
|
|
<h2><a href="#prerequisites">Prerequisites</a></h2>
|
|
|
|
<p>You should have at least 2GB of free memory available and 32GB of free storage
|
|
space.</p>
|
|
|
|
<p>You need a USB cable for attaching the device to a laptop or desktop. Whenever
|
|
possible, use the high quality standards compliant USB-C cable packaged with the
|
|
device. If your computer doesn't have any USB-C ports, you'll need a high quality
|
|
USB-C to USB-A cable. You should avoid using a USB hub such as the front panel on
|
|
a desktop computer case. Connect directly to a rear port on a desktop or the ports
|
|
on a laptop. Many widely distributed USB cables and hubs are broken and are the
|
|
most common source of issues for installing GrapheneOS.</p>
|
|
|
|
<p>Installing from an OS in a virtual machine is not recommended. USB passthrough
|
|
is often not reliable. To rule out these problems, install from an OS running on
|
|
bare metal. Virtual machines are also often configured to have overly limited
|
|
memory and storage space.</p>
|
|
|
|
<p>Officially supported operating systems for the web install method:</p>
|
|
|
|
<ul>
|
|
<li>Windows 10</li>
|
|
<li>Windows 11</li>
|
|
<li>macOS Big Sur (11)</li>
|
|
<li>macOS Monterey (12)</li>
|
|
<li>macOS Ventura (13)</li>
|
|
<li>Arch Linux</li>
|
|
<li>Debian 10 (buster)</li>
|
|
<li>Debian 11 (bullseye)</li>
|
|
<li>Debian 12 (bookworm)</li>
|
|
<li>Ubuntu 20.04 LTS</li>
|
|
<li>Ubuntu 22.04 LTS</li>
|
|
<li>Ubuntu 22.10</li>
|
|
<li>Ubuntu 23.04</li>
|
|
<li>ChromeOS</li>
|
|
<li>GrapheneOS</li>
|
|
<li>Google Android (stock Pixel OS) and other certified Android variants</li>
|
|
</ul>
|
|
|
|
<p>Make sure your operating system is up-to-date before proceeding.</p>
|
|
|
|
<p>Officially supported browsers for the web install method:</p>
|
|
|
|
<ul>
|
|
<li>Chromium (outside Ubuntu, since they ship a broken Snap package without working WebUSB)</li>
|
|
<li>Vanadium (GrapheneOS)</li>
|
|
<li>Google Chrome</li>
|
|
<li>Microsoft Edge</li>
|
|
<li>Brave</li>
|
|
</ul>
|
|
|
|
<p>You should avoid Flatpak and Snap versions of browsers, as they're known to cause issues during the installation process.</p>
|
|
|
|
<p>Make sure your browser is up-to-date before proceeding.</p>
|
|
|
|
<p>Do not use Incognito or other private browsing modes. These modes usually
|
|
prevent the web installer from having enough storage space to extract the
|
|
downloaded release.</p>
|
|
|
|
<p>You need one of the officially supported devices. To make sure that the device can
|
|
be unlocked to install GrapheneOS, avoid carrier variants of the devices. Carrier
|
|
variants of Pixels use the same stock OS and firmware with a non-zero carrier id
|
|
flashed onto the persist partition in the factory. The carrier id activates
|
|
carrier-specific configuration in the stock OS including disabling carrier and
|
|
bootloader unlocking. The carrier may be able to remotely disable this, but their
|
|
support staff may not be aware and they probably won't do it. Get a carrier agnostic
|
|
device to avoid the risk and potential hassle. If you CAN figure out a way to unlock a
|
|
carrier device, it isn't a problem as GrapheneOS can just ignore the carrier id
|
|
and the hardware is the same.</p>
|
|
|
|
<p>It's best practice to update the device before installing GrapheneOS to have
|
|
the latest firmware for connecting the phone to the computer and performing the
|
|
early flashing process. Either way, GrapheneOS flashes the latest firmware early
|
|
in the installation process.</p>
|
|
</section>
|
|
|
|
<section id="enabling-oem-unlocking">
|
|
<h2><a href="#enabling-oem-unlocking">Enabling OEM unlocking</a></h2>
|
|
|
|
<p>OEM unlocking needs to be enabled from within the operating system.</p>
|
|
|
|
<p>Enable the developer options menu by going to Settings ➔ About phone and
|
|
repeatedly pressing the build number menu entry until developer mode is
|
|
enabled.</p>
|
|
|
|
<p>Next, go to Settings ➔ System ➔ Developer options and toggle on the 'OEM
|
|
unlocking' setting. On device model variants (SKUs) which support being sold as
|
|
locked devices by carriers, enabling 'OEM unlocking' requires internet access so
|
|
that the stock OS can check if the device was sold as locked by a carrier.</p>
|
|
|
|
<p>For the Pixel 6a, OEM unlocking won't work with the version of the stock OS
|
|
from the factory. You need to update it to the June 2022 release or later via an
|
|
over-the-air update. After you've updated it you'll also need to factory reset
|
|
the device to fix OEM unlocking.</p>
|
|
</section>
|
|
|
|
<section id="flashing-as-non-root">
|
|
<h2><a href="#flashing-as-non-root">Flashing as non-root</a></h2>
|
|
|
|
<p>On traditional Linux distributions, USB devices cannot be used as non-root
|
|
without udev rules for each type of device. This is not an issue for other
|
|
platforms.</p>
|
|
|
|
<p>On Arch Linux, install the <code>android-udev</code> package. On Debian and
|
|
Ubuntu, install the <code>android-sdk-platform-tools-common</code> package.</p>
|
|
</section>
|
|
|
|
<section id="booting-into-the-bootloader-interface">
|
|
<h2><a href="#booting-into-the-bootloader-interface">Booting into the bootloader interface</a></h2>
|
|
|
|
<p>You need to boot your phone into the bootloader interface. To do this, you need
|
|
to hold the volume down button while the phone boots.</p>
|
|
|
|
<p>The easiest approach is to reboot the phone and begin holding the volume down
|
|
button until it boots up into the bootloader interface.</p>
|
|
|
|
<p>Alternatively, turn off the phone, then boot it up while holding the volume
|
|
down button during the boot process. You can either boot it with the power button
|
|
or by plugging it in as required in the next section.</p>
|
|
</section>
|
|
|
|
<section id="connecting-phone">
|
|
<h2><a href="#connecting-phone">Connecting the phone</a></h2>
|
|
|
|
<p>Connect the phone to the computer. On Linux, you'll need to do this again if
|
|
you didn't have the udev rules set up when you connected it.</p>
|
|
|
|
<p>On Linux, GNOME has a bug causing compatibility issues with the installation
|
|
process. It wrongly detects the phone in fastboot mode or fastbootd mode as being
|
|
an MTP device and claims exclusive control over it. This will block the install
|
|
process from proceeding. You can run the following command to work around it:</p>
|
|
|
|
<pre>echo 0 | sudo tee /sys/bus/usb/drivers_autoprobe</pre>
|
|
|
|
<p>After installing, you can undo this by rebooting or by running the following
|
|
command:</p>
|
|
|
|
<pre>echo 1 | sudo tee /sys/bus/usb/drivers_autoprobe</pre>
|
|
|
|
<p>On Windows, you need to install a driver for fastboot if you don't already have
|
|
it. No driver is needed on other operating systems. You can obtain the driver from
|
|
Windows Update which will detect it as an optional update when the device is
|
|
booted into the bootloader interface and connected to the computer. Open Windows
|
|
Update, run a check for updates and then open the "View optional updates"
|
|
interface. Install the driver for the Android bootloader interface as an optional
|
|
update.</p>
|
|
|
|
<p>An alternative approach to obtaining the Windows fastboot driver is to obtain
|
|
the <a href="https://developer.android.com/studio/run/win-usb">latest driver for
|
|
Pixels</a> from Google and then
|
|
<a href="https://developer.android.com/studio/run/oem-usb#InstallingDriver">manually
|
|
install it with the Windows Device Manager</a>.</p>
|
|
</section>
|
|
|
|
<section id="unlocking-the-bootloader">
|
|
<h2><a href="#unlocking-the-bootloader">Unlocking the bootloader</a></h2>
|
|
|
|
<p>Unlock the bootloader to allow flashing the OS and firmware:</p>
|
|
|
|
<button id="unlock-bootloader-button" disabled="">Unlock bootloader</button>
|
|
|
|
<p>The command needs to be confirmed on the device and will wipe all data. Use one
|
|
of the volume buttons to switch the selection to accepting it and the power button to
|
|
confirm.</p>
|
|
|
|
<p><strong id="unlock-bootloader-status"></strong></p>
|
|
</section>
|
|
|
|
<section id="obtaining-factory-images">
|
|
<h2><a href="#obtaining-factory-images">Obtaining factory images</a></h2>
|
|
|
|
<p>You need to obtain the GrapheneOS factory images for your device to proceed with
|
|
the installation process.</p>
|
|
|
|
<p>Press the button below to start the download:</p>
|
|
|
|
<button id="download-release-button" disabled="">Download release</button>
|
|
|
|
<p id="download-release-status-container" hidden="hidden">
|
|
<strong id="download-release-status"></strong>
|
|
<br/>
|
|
<progress id="download-release-progress" hidden="hidden" max="1" value="0"></progress>
|
|
</p>
|
|
</section>
|
|
|
|
<section id="flashing-factory-images">
|
|
<h2><a href="#flashing-factory-images">Flashing factory images</a></h2>
|
|
|
|
<p>The initial install will be performed by flashing the factory images. This will
|
|
replace the existing OS installation and wipe all the existing data.</p>
|
|
|
|
<button id="flash-release-button" disabled="">Flash release</button>
|
|
|
|
|
|
<p>Wait for the flashing process to complete. It will automatically handle
|
|
flashing the firmware, rebooting into the bootloader interface, flashing the core
|
|
OS, rebooting into the userspace fastboot mode, flashing the rest of the OS and
|
|
finally rebooting back into the bootloader interface. Avoid interacting with the
|
|
device until the flashing script is finished and the device is back at the
|
|
bootloader interface. Then, proceed to <a href="#locking-the-bootloader">locking
|
|
the bootloader</a> before using the device as locking wipes the data again.</p>
|
|
|
|
<p id="flash-release-status-container" hidden="hidden">
|
|
<strong id="flash-release-status"></strong>
|
|
<br/>
|
|
|
|
<!-- These appear as part of the status, one at a time -->
|
|
<progress id="flash-release-progress" hidden="hidden" max="1" value="0"></progress>
|
|
<button id="flash-reconnect-button" hidden="hidden"><strong>Reconnect device</strong></button>
|
|
</p>
|
|
</section>
|
|
|
|
<section id="locking-the-bootloader">
|
|
<h2><a href="#locking-the-bootloader">Locking the bootloader</a></h2>
|
|
|
|
<p>Locking the bootloader is important as it enables full verified boot. It also
|
|
prevents using fastboot to flash, format or erase partitions. Verified boot will
|
|
detect modifications to any of the OS partitions and it will prevent reading any
|
|
modified / corrupted data. If changes are detected, error correction data is used
|
|
to attempt to obtain the original data at which point it's verified again which
|
|
makes verified boot robust to non-malicious corruption.</p>
|
|
|
|
<p>In the bootloader interface, set it to locked:</p>
|
|
|
|
<button id="lock-bootloader-button" disabled="">Lock bootloader</button>
|
|
|
|
<p>The command needs to be confirmed on the device and will wipe all data. Use one
|
|
of the volume buttons to switch the selection to accepting it and the power button
|
|
to confirm.</p>
|
|
|
|
<p><strong id="lock-bootloader-status"></strong></p>
|
|
</section>
|
|
|
|
<section id="post-installation">
|
|
<h2><a href="#post-installation">Post-installation</a></h2>
|
|
|
|
<section id="booting">
|
|
<h3><a href="#booting">Booting</a></h3>
|
|
|
|
<p>You've now successfully installed GrapheneOS and can boot it. Pressing the
|
|
power button with the default Start option selected in the bootloader
|
|
interface will boot the OS.</p>
|
|
</section>
|
|
|
|
<section id="disabling-oem-unlocking">
|
|
<h3><a href="#disabling-oem-unlocking">Disabling OEM unlocking</a></h3>
|
|
|
|
<p>OEM unlocking can be disabled again in the developer settings menu within the
|
|
operating system after booting it up again.</p>
|
|
|
|
<p>After disabling OEM unlocking, we recommend disabling developer options as
|
|
a whole for a device that's not being used for app or OS development.</p>
|
|
</section>
|
|
|
|
<section id="verifying-installation">
|
|
<h3><a href="#verifying-installation">Verifying installation</a></h3>
|
|
|
|
<p>The verified boot and attestation features provided by the supported
|
|
devices can be used to verify that the hardware, firmware and GrapheneOS
|
|
installation are genuine. Even if the computer you used to flash GrapheneOS
|
|
was compromised and an attacker replaced GrapheneOS with their own malicious
|
|
OS, it can be detected with these features.</p>
|
|
|
|
<p>Verified boot verifies the entirety of the firmware and OS images on every
|
|
boot. The public key for the firmware images is burned into fuses in the SoC
|
|
at the factory. Firmware security updates can also update the rollback index
|
|
burned into fuses to provide rollback protection.</p>
|
|
|
|
<p>The final firmware boot stage before the OS is responsible for verifying
|
|
it. For the stock OS, it uses a hard-wired public key. Installing GrapheneOS
|
|
flashes the GrapheneOS verified boot public key to the secure element. Each
|
|
boot, this key is loaded and used to verify the OS. For both the stock OS and
|
|
GrapheneOS, a rollback index based on the security patch level is loaded from
|
|
the secure element to provide rollback protection.</p>
|
|
|
|
<section id="verified-boot-key-hash">
|
|
<h3><a href="#verified-boot-key-hash">Verified boot key hash</a></h3>
|
|
|
|
<p>When loading an alternate OS, the device shows a yellow notice on boot
|
|
with the ID of the alternate OS based on the sha256 of the verified boot
|
|
public key. 4th and 5th generation Pixels only show the first 32 bits of
|
|
the hash so you can't use this approach. 6th and 7th generation Pixels
|
|
show the full hash and you can compare it against the official GrapheneOS
|
|
verified boot hashes below:</p>
|
|
|
|
<ul>
|
|
<li>Pixel 7a: <code>508d75dea10c5cbc3e7632260fc0b59f6055a8a49dd84e693b6d8899edbb01e4</code></li>
|
|
<li>Pixel 7 Pro: <code>bc1c0dd95664604382bb888412026422742eb333071ea0b2d19036217d49182f</code></li>
|
|
<li>Pixel 7: <code>3efe5392be3ac38afb894d13de639e521675e62571a8a9b3ef9fc8c44fd17fa1</code></li>
|
|
<li>Pixel 6a: <code>08c860350a9600692d10c8512f7b8e80707757468e8fbfeea2a870c0a83d6031</code></li>
|
|
<li>Pixel 6 Pro: <code>439b76524d94c40652ce1bf0d8243773c634d2f99ba3160d8d02aa5e29ff925c</code></li>
|
|
<li>Pixel 6: <code>f0a890375d1405e62ebfd87e8d3f475f948ef031bbf9ddd516d5f600a23677e8</code></li>
|
|
</ul>
|
|
|
|
<p>Checking this is useful after installation, but you don't need to check
|
|
it manually for verified boot to work. The verified boot public key
|
|
flashed to the secure element can only be changed when the device is
|
|
unlocked. Unlocking the device performs the same wiping of the secure
|
|
element as a factory reset and prevents data from being recovered even if
|
|
the SSD was cloned and your passphrase(s) are obtained because the
|
|
encryption keys can no longer be derived anymore. The verified boot key is
|
|
also one of the inputs for deriving the encryption keys in addition to the
|
|
user's lock method(s) and random token(s) on the secure element.</p>
|
|
</section>
|
|
|
|
<section id="hardware-based-attestation">
|
|
<h3><a href="#hardware-based-attestation">Hardware-based attestation</a></h3>
|
|
|
|
<p>GrapheneOS provides our Auditor app for using a combination of the
|
|
verified boot and attestation features to verify that the hardware,
|
|
firmware and operating system are genuine along with providing other
|
|
useful data from the hardware and operating system.</p>
|
|
|
|
<p>Since the purpose of Auditor is to obtain information about the device
|
|
without trusting it to be honest, results aren't shown on the device being
|
|
verified. You need a 2nd Android device running Auditor for local QR code
|
|
based verification. You can also use our optional device integrity
|
|
monitoring service for automatic scheduled verifications with support for
|
|
email alerts.</p>
|
|
|
|
<p>See the <a href="https://attestation.app/tutorial">Auditor tutorial</a>
|
|
for a guide.</p>
|
|
|
|
<p>Auditor is primarily based on a pairing model where it generates a
|
|
hardware backed signing key and hardware backed attestation signing key
|
|
and pins them as part of the initial verification. The first verification
|
|
is bootstrapped based on chaining trust to one of the Android attestation
|
|
roots. After the first verification, it provides a highly secure system
|
|
for obtaining information about the device going forward. An attacker
|
|
could bypass the initial verification with a leaked attestation key or by
|
|
proxying to another device with the device model, OS and patch level that
|
|
the user is expecting. Proxying to another device will be addressed in the
|
|
future with optional support for the hardware serial number attestation
|
|
feature.</p>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="replacing-grapheneos-with-the-stock-os">
|
|
<h3><a href="#replacing-grapheneos-with-the-stock-os">Replacing GrapheneOS with the stock OS</a></h3>
|
|
|
|
<p>Installation of the stock OS via the stock factory images is similar to the
|
|
process described above but with
|
|
<a href="https://flash.android.com/back-to-public">Google's web flashing
|
|
tool</a>. However, before flashing and locking, there's an additional step to
|
|
fully revert the device to a clean factory state.</p>
|
|
|
|
<p>The GrapheneOS factory images flash a non-stock Android Verified Boot key which
|
|
needs to be erased to fully revert back to a stock device state. Before flashing the
|
|
stock factory images and before locking the bootloader, you should erase the custom
|
|
Android Verified Boot key to untrust it:</p>
|
|
|
|
<button id="remove-custom-key-button" disabled="">Remove non-stock key</button>
|
|
|
|
<p><strong id="remove-custom-key-status"></strong></p>
|
|
</section>
|
|
|
|
<section id="further-information">
|
|
<h3><a href="#further-information">Further information</a></h3>
|
|
|
|
<p>Please look through the <a href="/usage">usage guide</a> and
|
|
<a href="/faq">FAQ</a> for more information. If you have further questions not
|
|
covered by the site, join the <a href="/contact#community">official GrapheneOS
|
|
chat channels</a> and ask the questions in the appropriate channel.</p>
|
|
</section>
|
|
</section>
|
|
</main>
|
|
<footer>
|
|
<a href="/"><img src="{{path|/mask-icon.svg}}" width="512" height="512" alt=""/>GrapheneOS</a>
|
|
<ul id="social">
|
|
<li><a href="https://discuss.grapheneos.org/">Forum</a></li>
|
|
<li><a href="https://twitter.com/GrapheneOS">Twitter</a></li>
|
|
<li><a href="https://grapheneos.social/@GrapheneOS">Mastodon</a></li>
|
|
<li><a href="https://github.com/GrapheneOS">GitHub</a></li>
|
|
<li><a href="https://reddit.com/r/GrapheneOS">Reddit</a></li>
|
|
<li><a href="https://www.linkedin.com/company/grapheneos/">LinkedIn</a></li>
|
|
</ul>
|
|
</footer>
|
|
</body>
|
|
</html>
|