Compare commits

...

25 Commits
v0.0.0 ... main

Author SHA1 Message Date
fea9a4fd83
release: 0.1.0
All checks were successful
Static / Flake checks (push) Successful in 22s
Static / Create distribution (push) Successful in 42s
Release / Create release (push) Successful in 1m7s
2025-07-03 03:52:41 +09:00
0d47db9e2b
process-static: preserve quotes
All checks were successful
Static / Flake checks (push) Successful in 22s
Static / Create distribution (push) Successful in 42s
2025-07-03 03:39:05 +09:00
f38c2a4fc2
static: set up vanity url
All checks were successful
Static / Flake checks (push) Successful in 43s
Static / Create distribution (push) Successful in 1m3s
2025-07-03 03:24:50 +09:00
0e3b069051
release: 0.0.2-hotfix.0
All checks were successful
Static / Flake checks (push) Successful in 22s
Static / Create distribution (push) Successful in 43s
Release / Create release (push) Successful in 1m5s
2025-06-29 04:17:55 +09:00
fadead208a
static: update install path
All checks were successful
Static / Flake checks (push) Successful in 21s
Static / Create distribution (push) Successful in 41s
2025-06-29 04:15:30 +09:00
02c72d59e6
release: 0.0.2
All checks were successful
Static / Flake checks (push) Successful in 22s
Static / Create distribution (push) Successful in 32s
Release / Create release (push) Successful in 1m6s
2025-06-29 03:54:09 +09:00
aeca93f41d
templates: add discord link
All checks were successful
Static / Flake checks (push) Successful in 21s
Static / Create distribution (push) Successful in 41s
This leads to /discord and the redirect should be handled by nginx.
2025-06-29 03:51:56 +09:00
e4db81206f
treewide: remove unused scripts
All checks were successful
Static / Flake checks (push) Successful in 21s
Static / Create distribution (push) Successful in 41s
2025-06-29 03:49:42 +09:00
34b55506fe
static: remove faq page for now
All checks were successful
Static / Flake checks (push) Successful in 21s
Static / Create distribution (push) Successful in 40s
This will be useful after we get some kind of userbase. Omit this for
now since there is nothing to put there.
2025-06-29 03:46:15 +09:00
6aab6189bd
static: replace robots.txt
All checks were successful
Static / Flake checks (push) Successful in 21s
Static / Create distribution (push) Successful in 42s
2025-06-29 03:43:15 +09:00
53caf6046c
static: replace contact.html
All checks were successful
Static / Flake checks (push) Successful in 21s
Static / Create distribution (push) Successful in 26s
2025-06-29 03:42:46 +09:00
2981b588d7
static: remove unused pages
All checks were successful
Static / Flake checks (push) Successful in 21s
Static / Create distribution (push) Successful in 41s
2025-06-29 03:17:30 +09:00
ae9ca7d568
static: replace install
All checks were successful
Static / Flake checks (push) Successful in 21s
Static / Create distribution (push) Successful in 44s
Also get rid of many unused pages and assets.
2025-06-29 03:14:12 +09:00
ae2ce60893
static: replace error page
All checks were successful
Static / Flake checks (push) Successful in 23s
Static / Create distribution (push) Successful in 50s
Also add cat to error page.
2025-06-29 02:52:42 +09:00
bf8a0cfc8d
static: remove source page
All checks were successful
Static / Flake checks (push) Successful in 21s
Static / Create distribution (push) Successful in 47s
There are not that many repositories so an index is not helpful.
2025-06-28 19:30:26 +09:00
09ee7085d1
static/package: minor wording change
All checks were successful
Static / Flake checks (push) Successful in 22s
Static / Create distribution (push) Successful in 51s
2025-06-28 16:25:57 +09:00
0f310aa450
static: replace features with package
All checks were successful
Static / Flake checks (push) Successful in 22s
Static / Create distribution (push) Successful in 50s
2025-06-28 16:04:15 +09:00
c6c9d6dea9
static: punctuation edit
All checks were successful
Static / Flake checks (push) Successful in 22s
Static / Create distribution (push) Successful in 47s
2025-06-28 15:22:51 +09:00
836134f9fc
templates: replace footer
All checks were successful
Static / Flake checks (push) Successful in 22s
Static / Create distribution (push) Successful in 55s
2025-06-28 15:20:41 +09:00
8275ff0d22
static: replace index.html
All checks were successful
Static / Flake checks (push) Successful in 21s
Static / Create distribution (push) Successful in 47s
2025-06-28 14:14:19 +09:00
2f45a8aad6
static: light coloured favicon
All checks were successful
Static / Flake checks (push) Successful in 22s
Static / Create distribution (push) Successful in 48s
2025-06-28 11:49:30 +09:00
10722b6549
static: replace artwork
All checks were successful
Static / Flake checks (push) Successful in 22s
Static / Create distribution (push) Successful in 48s
Artwork is from http://www.rd-sounds.com/C83.html
2025-06-28 03:25:08 +09:00
b9b6e3db16
static: remove unused pages
All checks were successful
Static / Flake checks (push) Successful in 22s
Static / Create distribution (push) Successful in 52s
There are more potentially unused pages, but these are unlikely to
become relevant or reusable in the near future, so remove them.
2025-06-28 01:57:08 +09:00
57a7aa4410
nix: fix rsync order
All checks were successful
Static / Flake checks (push) Successful in 23s
Static / Create distribution (push) Successful in 1m4s
Sitemap gets removed since it is not in the other tree.
2025-06-28 01:34:04 +09:00
f2b4785e33
static: replace humans.txt
All checks were successful
Static / Flake checks (push) Successful in 35s
Static / Create distribution (push) Successful in 1m8s
2025-06-28 00:56:47 +09:00
81 changed files with 455 additions and 13616 deletions

View File

@ -34,6 +34,6 @@ jobs:
- name: Upload static files
uses: actions/upload-artifact@v3
with:
name: "hakurei.app-${{ steps.static-test.outputs.rev }}"
name: "hakurei-static-${{ steps.static-test.outputs.rev }}"
path: result/*
retention-days: 1

View File

@ -1,18 +0,0 @@
#!/bin/bash
set -o errexit -o nounset -o pipefail
status=0
replicas=({1..3}.grapheneos.org)
for replica in ${replicas[@]}; do
echo
echo Deploying to $replica
echo
rsync -rpcvl --delete --fsync --preallocate /etc/letsencrypt/ $replica:/etc/letsencrypt &&
ssh root@$replica nginx -s reload ||
status=1
done
exit $status

View File

@ -1,64 +0,0 @@
#!/bin/bash
set -o errexit -o nounset -o pipefail
shopt -s extglob
touch lock
exec {fd}< lock
if ! flock -n $fd; then
echo already processing/deploying static files >&2
exit 1
fi
./process-static $fd
servers=({0..3}.grapheneos.org)
rsync -pcv --chmod=F755 --fsync --preallocate certbot-replicate root@${servers[0]}:/usr/local/bin/
rsync -pcv --chmod=F644 --fsync --preallocate replicate.conf root@${servers[0]}:/etc/systemd/system/certbot-renew.service.d/
# use last modified timestamps from 0.grapheneos.org
rsync -rptcv --chmod=D755,F644 --delete --fsync --preallocate root@${servers[0]}:/srv/grapheneos.org/ static-production
rsync -pcv --chmod=D755,F644 --fsync --preallocate static-production/sitemap.xml{,.gz,.br} static-tmp/
rsync -rpcv --chmod=D755,F644 --delete --fsync --preallocate static-tmp/ static-production
for f in static-production/**.*(br|gz); do
touch -r "${f%.*}" "$f"
done
changed="$(./generate-sitemap)"
xmllint --noblanks static-tmp/sitemap.xml --output static-tmp/sitemap.xml
brotli -f static-tmp/sitemap.xml
zopfli static-tmp/sitemap.xml
rsync -pcv --chmod=D755,F644 --fsync --preallocate static-tmp/sitemap.xml{,.gz,.br} static-production/
for server in ${servers[@]}; do
echo $server
remote=root@$server
active=$(ssh $remote readlink /srv/grapheneos.org)
if [[ $active = /srv/grapheneos.org_a ]]; then
target=/srv/grapheneos.org_b
else
target=/srv/grapheneos.org_a
fi
echo active is $active
echo target is $target
echo
ssh $remote "rm -rf $target && cp -a $active $target"
rsync -rptcv --chmod=D755,F644 --delete --fsync --preallocate static-production/ $remote:$target
ssh $remote "ln -snf $target /srv/grapheneos.org && sync /srv/grapheneos.org"
echo "root $target;" > nginx-tmp/root_grapheneos.org.conf
rsync -rpcv --chmod=D755,F644 --delete --fsync --preallocate nginx-tmp/{nginx.conf,mime.types,root_grapheneos.org.conf,snippets} $remote:/etc/nginx/
ssh $remote nginx -s reload
echo
echo active is now $target
echo
done
if [[ -n "$changed" ]]; then
./indexnow <<< "$changed"
fi

View File

@ -1,19 +0,0 @@
#!/bin/bash
set -o errexit -o nounset -o pipefail
generate() {
echo $1
qrencode -s 1 -o $1 $2
gm identify -format '%w×%h\n' $1
zopflipng -ym $1 $1
}
generate static/donate-bitcoin.png 'bitcoin:bc1q9qw3g8tdxf3dugkv2z8cahd3axehph0mhsqk96?label=GrapheneOS%20Foundation&message=Donation%20to%20GrapheneOS%20Foundation'
generate static/donate-bitcoin-taproot.png 'bitcoin:bc1prqf5hks5dnd4j87wxw3djn20559yhj7wvvcv6fqxpwlg96udkzgqtamhry?label=GrapheneOS%20Foundation&message=Donation%20to%20GrapheneOS%20Foundation'
generate static/donate-bitcoin-bip47.png 'bitcoin:PM8TJKmhJNQX6UTFagyuBk8UGmwKM6yDovEokpHBscPgP3Ac7WdK5zaQKh5XLSawyxiGYZS2a7HkAoeL6oHg7Ahn1VXX888yRG4PwF1dojouPtW7tEHT'
generate static/donate-monero.png 'monero:862CebHaBpFPgYoNC6zw4U8rsXrDjD8s5LMJNS7yVCRHMUKr9dDi7adMSLUMjkDYJ85xahQTCJHHyK5RCvvRJu9x7iSzN9D?recipient_name=GrapheneOS&tx_description=Donation%20to%20GrapheneOS'
generate static/donate-zcash-transparent.png 'zcash:t1SJABjX8rqgzqgrzLW5dUw7ikSDZ2snD8A?label=GrapheneOS%20Foundation&message=Donation%20to%20GrapheneOS%20Foundation'
generate static/donate-ethereum.png 'ethereum:0xC822A62E5Ab443E0001f30cEB9B2336D0524fC61'
generate static/donate-cardano.png 'web+cardano:addr1q9v89vfwyfssveug5zf2w7leafz8ethq490gvq0ghag883atfnucytpnq2t38dj7cnyngs6ne05cdwu9gseevgmt3ggq2a2wt6'
generate static/donate-litecoin.png 'litecoin:ltc1qzssmqueth6zjzr95rkluy5xdx9q4lk8vyrvea9?label=GrapheneOS%20Foundation&message=Donation%20to%20GrapheneOS%20Foundation'

View File

@ -2,35 +2,16 @@ from datetime import datetime, timezone
from os.path import getmtime
from pathlib import Path
base = "https://grapheneos.org"
base = "https://hakurei.app"
pages = [
["/", 0.5],
["/.well-known/security.txt", 0.0],
["/LICENSE.txt", 0.0],
["/articles/", 0.5],
["/articles/attestation-compatibility-guide", 0.5],
["/articles/grapheneos-servers", 0.1],
["/articles/positon-location-service", 0.5],
["/articles/server-traffic-shaping", 0.5],
["/articles/sitewide-advertising-industry-opt-out", 0.5],
["/build", 0.5],
["/camera-privacy-policy", 0.0],
["/contact", 0.5],
["/donate", 0.5],
["/faq", 1.0],
["/features", 1.0],
["/history/", 0.3],
["/history/copperheados", 0.1],
["/history/legacy-changelog", 0.1],
["/hiring", 0.2],
#["/faq", 1.0],
["/package", 1.0],
["/humans.txt", 0.0],
["/pdfviewer-privacy-policy", 0.0],
["/install/", 0.5],
["/install/cli", 0.5],
["/install/web", 0.5],
["/source", 0.5],
["/usage", 1.0]
["/install", 0.5],
]
base_mtime = getmtime("static-tmp")
@ -38,12 +19,13 @@ entries = []
for page in pages:
path = page[0]
if path[-1] != '/' and "." not in path:
path += ".html"
loc = base + path
filepath = "static-production" + path
if path[-1] == '/':
filepath += "index.html"
elif "." not in path:
filepath += ".html"
mtime = getmtime(filepath)
if mtime > base_mtime:

4
indexnow → indexnow.py Executable file → Normal file
View File

@ -1,5 +1,3 @@
#!/usr/bin/env python3
import sys
import requests
@ -17,7 +15,7 @@ for url in urls:
if not validators.url(url):
sys.exit(3)
host = "grapheneos.org"
host = "hakurei.app"
api_url = "https://api.indexnow.org/indexnow"
with open("indexnow-key.txt") as keyfile:

View File

@ -17,7 +17,7 @@
}:
stdenvNoCC.mkDerivation rec {
pname = "hakurei.app";
version = "0.0.0";
version = "0.1.0";
src = ./.;
@ -89,8 +89,8 @@ stdenvNoCC.mkDerivation rec {
xmllint --noblanks static-tmp/sitemap.xml --output static-tmp/sitemap.xml
brotli -f static-tmp/sitemap.xml
zopfli static-tmp/sitemap.xml
rsync -pcv --chmod=D755,F644 --fsync --preallocate static-tmp/sitemap.xml{,.gz,.br} $out
rsync -rptcv --chmod=D755,F644 --delete --fsync --preallocate static-production/ $out
rsync -pcv --chmod=D755,F644 --fsync --preallocate static-tmp/sitemap.xml{,.gz,.br} $out
runHook postInstall
'';

View File

@ -57,7 +57,7 @@ java -jar node_modules/vnu-jar/build/dist/vnu.jar --Werror --css static-tmp/**/*
java -jar node_modules/vnu-jar/build/dist/vnu.jar --Werror --svg static-tmp/**/!(bimi).svg
find static-tmp -name '*.html' -exec html-minifier-terser --collapse-whitespace \
--process-scripts "application/ld+json" --collapse-boolean-attributes \
--remove-attribute-quotes --remove-comments --remove-empty-attributes \
--remove-comments --remove-empty-attributes \
--remove-redundant-attributes --remove-script-type-attributes \
--remove-style-link-type-attributes --sort-attributes --sort-class-name {} -o {} \;

View File

@ -1 +0,0 @@
{"m.homeserver":{"base_url":"https://matrix.grapheneos.org"}}

View File

@ -1 +0,0 @@
{"m.server":"matrix.grapheneos.org:443"}

View File

@ -1,24 +0,0 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
Contact: mailto:security@grapheneos.org
Canonical: https://grapheneos.org/.well-known/security.txt
Encryption: data:application/x-age-public-key,age1dcftzgq00ykgwvxl5te6d5clqgx75h2g54c0u8gjc43mcnea7p7q3ma0yx
Expires: 2026-03-01T00:00:00Z
Preferred-Languages: en
-----BEGIN PGP SIGNATURE-----
iQIzBAEBCAAdFiEEZe7+AiEI4rcIy/z3+ecS5Zr18ioFAmfDGl4ACgkQ+ecS5Zr1
8iquHQ//e/Wy0rv3YlGTzzE1bM+h45JKyd+vxYdRmUVM4ic0rLpx+v1vQdIDKUtZ
Bax7wE1dMRu02Tpo8vxoEB5QgilxgLtZIi0y3K68/lQJM1BIl20ieL0YfeB9YZt7
TZeAbuIMaq0YyzxexTE2GKQQI4qKAIJpMvEnvxmZ2c9dmOiP6T6TYVsYBmiSe7op
YUQZ1j6yElVXiBA9FJg1vpaWqPFeSEmi8X0c0ef5tdNKCai1c2/arhELK4msB3ih
0Wd7MIukudGvH7Xjfb+H8EZ53OTg/3pAhNdf5E7apwlgNPdp/XPK3Uen+8o0wV4r
cQRNBD0gGA8kyEtYfcgndFo5kVkptOZB4OLx7A9wxjDsfMYduknuTGyniZH2DBlH
S/H0aWaoLSO2FCFT7OIkXxYTjXdbKZwgtPf5ba6gCpDL/aXrjIPeqHtmo/l2ruhx
sc6TYiSHBQuFqQg+X2/49GxDap6k13an5ZiRPUw5CoJl3r3Ztg6ZKu4EiFmLjJ5K
AliaN0hjwqxH0AbMc95DLUZ1oRNpk17dlcXl/Fgk7ZI/6GWEqOhEkzf3je9GrZJR
53OTDvcarq+rS8kcZ/bSxoBLaZNcNes3kcinaCnGCTjFPgoy2f6CtuuA37KwMc0V
TMGaKqRMUCj+lJtdM2HuY0FvWMWjrDKdPrprUx8/umrAa0XPX2k=
=WcPV
-----END PGP SIGNATURE-----

View File

@ -2,22 +2,20 @@
<html lang="en" prefix="og: https://ogp.me/ns#">
<head>
<meta charset="utf-8"/>
<title>Page not found | GrapheneOS</title>
<title>Page not found | Hakurei</title>
<meta name="description" content="The requested page does not exist."/>
<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, viewport-fit=cover"/>
<meta name="twitter:site" content="@GrapheneOS"/>
<meta name="twitter:creator" content="@GrapheneOS"/>
<meta property="og:title" content="Page not found"/>
<meta property="og:description" content="The requested page does not exist."/>
<meta property="og:type" content="website"/>
<meta property="og:image" content="https://grapheneos.org/opengraph.png"/>
<meta property="og:image" content="https://hakurei.app/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:image:alt" content="Hakurei logo"/>
<meta property="og:site_name" content="Hakurei"/>
<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"/>
@ -25,7 +23,8 @@
[[css|/main.css]]
<link rel="manifest" href="/manifest.webmanifest"/>
<link rel="license" href="/LICENSE.txt"/>
<link rel="me" href="https://grapheneos.social/@GrapheneOS"/>
<link rel="me" href="https://port.mk/@hakurei"/>
[[js|/js/oneko.js]]
</head>
<body>
{% include "header.html" %}
@ -33,7 +32,7 @@
<h1><a href="#page-not-found">Page not found</a></h1>
<p>The requested page does not exist. If you think this is a mistake, please
<a href="https://github.com/GrapheneOS/grapheneos.org/issues">report an issue</a>.</p>
<a href="https://git.gensokyo.uk/security/hakurei.app/issues">report an issue</a>.</p>
</main>
{% include "footer.html" %}
</body>

View File

@ -1 +0,0 @@
contact@grapheneos.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIUg/m5CoP83b0rfSCzYSVA4cw4ir49io5GPoxbgxdJE

View File

@ -1,16 +0,0 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEEZe7+AiEI4rcIy/z3+ecS5Zr18ioFAmXMmicACgkQ+ecS5Zr1
8iqOKw//WB9N2C+jT/WmMT4t0+aE/0uHvBqoU9KQFmzFWlixibqF70C3gcBkeZK9
tvWViI1UhQJktM0A4rwTn3r7T+MvIbwlOzHBKmoWyU2+PSwO3lIO9xbHSvu4/rbp
IVkIimgwi9WTvlDvXRhYdXtfJJyXl+qlfbk5sHCOavuR+/xPx3IUDpEZwPvi33VF
Z1Sl/3yJztLB96ngmhs29WBniTvxa3owYwjMhHNuTnxNf2m8bIavYA2Vraj9gE8O
eTNE5oXkGdv2YJnKW0gbMDV2/F7WBW2/kPZ6yvUxR9texHsFn1dofvf604W09PKP
QaIzCKGsJSAVKx/g9mSXm2Z/+hsXLWlJAVK0hmCEhn+Tnmff5KMG7R1WUes0R0rv
PK6sa0NbvRRNiwxM08PnZ14WrYBggOZdRBlseqHIdwu2UD2X2vTNK4VOhBbaQPYd
EwdIwZxqu0bpUtPIowJqppd/ZWxKOJ4OMcDF/2ENBTqp20RWQnTM1WEV1OoUQeh1
XfZDNFBRW7CP4zsbFTIK4DEobxbVXCEVtUK4rGRChX3WL8qhVCgxFf4W8Cwjco2y
u40luFdoNyrd2yTVevcX0w2W/4JvJ5reikepYOAbCwbLbWNJnKoRA+0ZgZ0IE1B4
+RDmB5iIefAPjpD/Do/TtlFjRcyh6g4kNWnS1fTzB9jGNP/PQWs=
=rnsE
-----END PGP SIGNATURE-----

View File

@ -1,2 +0,0 @@
untrusted comment: verify with factory.pub
RWQZW9NItOuQYMZY8ZMX9VX4hfy54df7Pt3Yh1qEWTyRlQKH4PdteqeKUk9jljywlcCl8nzKJAj75F70Y5FTsAK4cw2aV+CZcAA=

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -1,176 +0,0 @@
<!DOCTYPE html>
<html lang="en" prefix="og: https://ogp.me/ns#">
<head>
<meta charset="utf-8"/>
<title>Attestation compatibility guide | Articles | GrapheneOS</title>
<meta name="description" content="Guide on using remote attestation in a way that's compatible with GrapheneOS."/>
<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, viewport-fit=cover"/>
<meta name="twitter:site" content="@GrapheneOS"/>
<meta name="twitter:creator" content="@GrapheneOS"/>
<meta property="og:title" content="GrapheneOS attestation compatibility guide"/>
<meta property="og:description" content="Guide on using remote attestation in a way that's compatible with GrapheneOS."/>
<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/articles/attestation-compatibility-guide"/>
<link rel="canonical" href="https://grapheneos.org/articles/attestation-compatibility-guide"/>
<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"/>
</head>
<body>
{% include "header.html" %}
<main id="attestation-compatibility-guide">
<h1><a href="#attestation-compatibility-guide">Attestation compatibility guide</a></h1>
<p>Apps using the Play Integrity API or
<a href="https://developer.android.com/training/safetynet/deprecation-timeline">obsolete</a>
SafetyNet Attestation API to check the authenticity/integrity of the OS can support
GrapheneOS by using the standard Android hardware attestation API instead and
permitting our official release signing keys. Android's
<a href="https://developer.android.com/training/articles/security-key-attestation">hardware
attestation API</a> provides a much stronger form of attestation than the Play
Integrity API with the ability to whitelist the keys of alternate operating systems.
It also avoids an unnecessary dependency on Google Play services and Google's
Play Integrity servers.</p>
<p>The standard hardware attestation API can be used to verify the authenticity/integrity
of the hardware, firmware, OS and the app running on it. It provides a verified boot key
fingerprint for the OS for permitting secure aftermarket operating systems. The app id,
signing key fingerprint(s) and version code of the app enabling hardware attestation are
included in the signed public key certificate for the generated key. This enables the
app's service to make sure the app is genuine and unmodified along with chaining trust
through the OS to the app which can sign messages with the attested hardware keystore
key to prove they come from their app running on top of a verified OS, firmware and
hardware. The only practical way to bypass hardware attestation is through exploiting
the hardware keystore to obtain attestation signing keys, which is protected against by
the ability to revoke keys that are being misused. Play Integrity API strong integrity
level is directly based on the hardware key attestation API, but apps using it directly
can support aftermarket operating systems, check the hardware attested OS patch level
and other provided information. The hardware attestation API also supports pinning-based
security instead of only root-based security where keys can be leaked and used to fake
attestations. Apps can use pinning to establish a much higher security pairing with a
specific device to obtain fresh attestations with a very high level security based on
the security of the device's own hardware keystore rather than the overall ecosystem.
Hardware attestation also doesn't require using any Google service beyond regularly
fetching the list of revoked keys for root-based attestation. The app's service doesn't
have to go down or start permitting anything if the Google services becomes unavailable
or blocks the app from using it for one reason or another. Using hardware attestation is
therefore more reliable and lower risk for apps.</p>
<p>Devices have been required to ship with hardware attestation support since Android
8. You can use hardware attestation on devices running Android 8 or later when the
<code>ro.product.first_api_level</code> system property isn't set to 25 or below,
which indicates they launched with Android 8 or later with hardware attestation
support as a mandatory feature. On older devices, you can continue using the Play
Integrity API. Some low quality devices shipped broken implementations of hardware
attestation despite the requirement to have it working for CDD/CTS certification and
the Play Integrity API currently still passes on those devices wrongly claiming them
to be CTS certified. If you don't want to fail on those devices, then you can start
with hardware attestation and fall back to the Play Integrity API or do both and
accept either passing as success.</p>
<p>Google provides a <a href="https://github.com/google/android-key-attestation">key
attestation library</a> with examples. Our <a href="https://github.com/GrapheneOS/Auditor">MIT
/ Apache 2 licensed Auditor app</a> can be used as a reference implementation for
verifying hardware-based attestations. There are some subtleties in the verification
process such as making sure only the 2nd certificate in the chain (the one signing the
certificate for the key generated by your app) has an attestation extension to prevent
making a fake attestation by extending the chain. You can reuse our code and simply
omit support for an app generated attestation signing key (attest key) and the other
pinning support.</p>
<p>After verifying the signature of the attestation certificate chain and extracting
the attestation metadata, you can enforce that <code>verifiedBootState</code> is
either <code>Verified</code> or <code>SelfSigned</code>. For the
<code>SelfSigned</code> case, you can check that <code>verifiedBootKey</code> matches
one of the official GrapheneOS verified boot keys. These are the base16-encoded
verified boot key fingerprints for the official GrapheneOS releases:</p>
<ul>
<li><code>0508de44ee00bfb49ece32c418af1896391abde0f05b64f41bc9a2dfb589445b</code>: Pixel 9a</li>
<li><code>af4d2c6e62be0fec54f0271b9776ff061dd8392d9f51cf6ab1551d346679e24c</code>: Pixel 9 Pro Fold</li>
<li><code>55d3c2323db91bb91f20d38d015e85112d038f6b6b5738fe352c1a80dba57023</code>: Pixel 9 Pro XL</li>
<li><code>f729cab861da1b83fdfab402fc9480758f2ae78ee0b61c1f2137dd1ab7076e86</code>: Pixel 9 Pro</li>
<li><code>9e6a8f3e0d761a780179f93acd5721ba1ab7c8c537c7761073c0a754b0e932de</code>: Pixel 9</li>
<li><code>096b8bd6d44527a24ac1564b308839f67e78202185cbff9cfdcb10e63250bc5e</code>: Pixel 8a</li>
<li><code>896db2d09d84e1d6bb747002b8a114950b946e5825772a9d48ba7eb01d118c1c</code>: Pixel 8 Pro</li>
<li><code>cd7479653aa88208f9f03034810ef9b7b0af8a9d41e2000e458ac403a2acb233</code>: Pixel 8</li>
<li><code>ee0c9dfef6f55a878538b0dbf7e78e3bc3f1a13c8c44839b095fe26dd5fe2842</code>: Pixel Fold</li>
<li><code>94df136e6c6aa08dc26580af46f36419b5f9baf46039db076f5295b91aaff230</code>: Pixel Tablet</li>
<li><code>508d75dea10c5cbc3e7632260fc0b59f6055a8a49dd84e693b6d8899edbb01e4</code>: Pixel 7a</li>
<li><code>bc1c0dd95664604382bb888412026422742eb333071ea0b2d19036217d49182f</code>: Pixel 7 Pro</li>
<li><code>3efe5392be3ac38afb894d13de639e521675e62571a8a9b3ef9fc8c44fd17fa1</code>: Pixel 7</li>
<li><code>08c860350a9600692d10c8512f7b8e80707757468e8fbfeea2a870c0a83d6031</code>: Pixel 6a</li>
<li><code>439b76524d94c40652ce1bf0d8243773c634d2f99ba3160d8d02aa5e29ff925c</code>: Pixel 6 Pro</li>
<li><code>f0a890375d1405e62ebfd87e8d3f475f948ef031bbf9ddd516d5f600a23677e8</code>: Pixel 6</li>
</ul>
<p>The <code>verifiedBootKey</code> field is binary data so you either need to encode
it as base16 to compare with these or convert these to binary. An easy approach is
storing the permitted key fingerprints in a set and enforcing that the verified boot
key is in the permitted set when <code>verifiedBootState</code> is
<code>SelfSigned</code>.</p>
<p>GrapheneOS regularly adds support for new devices so you should have a process for
regularly adding the new verified boot key fingerprints from this page.</p>
<p>The hardware attestation API also provides other useful information signed by the
hardware including the OS patch level, in a way that even an attacker exploiting the
OS after boot to gain root cannot trivially bypass. It's a better feature than the
Play Integrity API which has to be designed for the lowest common denominator.</p>
<p>GrapheneOS users are strongly encouraged to share this documentation with app
developers enforcing only being able to use the stock OS. Send an email to the
developers and leave a review of the app with a link to this information. Share it
with other users and create pressure to support GrapheneOS rather than locking users
into the stock OS without a valid security reason. GrapheneOS not only upholds the
app security model but substantially reinforces it, so it cannot be justified with
reasoning based on security, anti-fraud, etc.</p>
<article id="apps-banning-grapheneos">
<h2><a href="#apps-banning-grapheneos">Apps banning GrapheneOS</a></h2>
<p>This is a list of the apps banning GrapheneOS with the Play Integrity API with
links to their Play Store pages for leaving feedback:</p>
<ul>
<li><a href="https://play.google.com/store/apps/details?id=au.gov.mygov.mygovapp" rel="nofollow">myGov</a> (Australian government app)</li>
<li><a href="https://play.google.com/store/apps/details?id=br.gov.meugovbr" rel="nofollow">gov.br</a> (Brazilian government app)</li>
<li><a href="https://play.google.com/store/apps/details?id=ch.ticketcorner.mobile.app.Android" rel="nofollow">Ticketcorner</a></li>
<li><a href="https://play.google.com/store/apps/details?id=com.authy.authy" rel="nofollow">Authy</a></li>
<li><a href="https://play.google.com/store/apps/details?id=com.ebay.mobile" rel="nofollow">eBay</a></li>
<li><a href="https://play.google.com/store/apps/details?id=com.mcdonalds.mobileapp" rel="nofollow">McDonald's</a> (International app used for many but not all countries not including the US)</li>
<li><a href="https://play.google.com/store/apps/details?id=com.ridedott.rider" rel="nofollow">Dott</a></li>
<li><a href="https://play.google.com/store/apps/details?id=com.swissquote.android" rel="nofollow">Swissquote</a></li>
<li><a href="https://play.google.com/store/apps/details?id=com.swisssign.swissid.mobile" rel="nofollow">SwissID</a></li>
<li><a href="https://play.google.com/store/apps/details?id=de.tk.tkapp" rel="nofollow">TK-App</a> (German health insurance app which uses it for fingerprint login)</li>
<li><a href="https://play.google.com/store/apps/details?id=it.pagopa.io.app" rel="nofollow">IO</a> (Italian government app which uses it for the digital wallet feature)</li>
</ul>
<p>In addition to leaving feedback for these apps on the Play Store, file support
requests and leave feedback on third party review sites. Ask them to stop banning
GrapheneOS and explain that it's a much more secure OS than what they permit which
does not lose any of the standard security model. Explain that they can use the
hardware key attestation API to verify that a device is running GrapheneOS to permit
it alongside an OS licensing Google apps as they do with the Play Integrity API
already. Make sure to push back against false claims that it has something to do
with compatibility or security issues. The only reason they aren't permitting it is
because we do not license Google Mobile Services (GMS) and these apps are enforcing
Google's business interests rather than security.</p>
</article>
</main>
{% include "footer.html" %}
</body>
</html>

View File

@ -1,726 +0,0 @@
<!DOCTYPE html>
<html lang="en" prefix="og: https://ogp.me/ns#">
<head>
<meta charset="utf-8"/>
<title>GrapheneOS servers | Articles | GrapheneOS</title>
<meta name="description" content="Documentation on GrapheneOS servers."/>
<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, viewport-fit=cover"/>
<meta name="twitter:site" content="@GrapheneOS"/>
<meta name="twitter:creator" content="@GrapheneOS"/>
<meta property="og:title" content="GrapheneOS servers"/>
<meta property="og:description" content="Documentation on GrapheneOS servers."/>
<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/articles/grapheneos-servers"/>
<link rel="canonical" href="https://grapheneos.org/articles/grapheneos-servers"/>
<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]]
</head>
<body>
{% include "header.html" %}
<main id="grapheneos-servers">
<h1><a href="#grapheneos-servers">GrapheneOS servers</a></h1>
<p>This is a detailed list of the public GrapheneOS servers.</p>
<p>We use hardened local machines for building and signing rather than servers outside
our physical control, so information on that infrastructure is outside the scope of this
page but may be provided in the future elsewhere.</p>
<nav id="table-of-contents">
<h2><a href="#table-of-contents">Table of contents</a></h2>
<ul>
<li><a href="#grapheneos.org">GrapheneOS website</a></li>
<li><a href="#staging.grapheneos.org">Staging GrapheneOS website</a></li>
<li><a href="#releases.grapheneos.org">GrapheneOS release servers</a></li>
<li><a href="#grapheneos.network">GrapheneOS network servers</a></li>
<li><a href="#mail.grapheneos.org">GrapheneOS mail server</a></li>
<li><a href="#discuss.grapheneos.org">GrapheneOS discussion forum server</a></li>
<li><a href="#grapheneos.social">GrapheneOS Mastodon server</a></li>
<li><a href="#matrix.grapheneos.org">GrapheneOS Matrix server</a></li>
<li><a href="#ns1.grapheneos.org">GrapheneOS DNS servers</a></li>
<li><a href="#ns1.staging.grapheneos.org">Staging GrapheneOS DNS server</a></li>
<li><a href="#attestation.app">Attestation website and service</a></li>
<li><a href="#staging.attestation.app">Staging attestation website and service</a></li>
</ul>
</nav>
<section id="grapheneos.org">
<h2><a href="#grapheneos.org">GrapheneOS website</a></h2>
<ul>
<li><a href="https://github.com/GrapheneOS/grapheneos.org">Repository</a></li>
<li><a href="https://github.com/GrapheneOS/grapheneos.org/issues">Issue tracker</a></li>
</ul>
<p>Specs:</p>
<ul>
<li>3x OVH VPS vps2023-le-2</li>
<li>2 core</li>
<li>2 GB memory</li>
<li>40 GB NVMe SSD storage</li>
<li>500 Mbit/s bandwidth</li>
</ul>
<ul>
<li>1x BuyVM Slice 1024</li>
<li>1 core</li>
<li>1 GB memory</li>
<li>20 GB NVMe SSD storage</li>
<li>1000 Mbit/s bandwidth</li>
</ul>
<p>Domains:</p>
<ul>
<li>grapheneos.org</li>
<li>www.grapheneos.org</li>
<li>grapheneos.app</li>
<li>www.grapheneos.app</li>
<li>grapheneos.ca</li>
<li>www.grapheneos.ca</li>
<li>grapheneos.com</li>
<li>www.grapheneos.com</li>
<li>grapheneos.dev</li>
<li>www.grapheneos.dev</li>
<li>grapheneos.foundation</li>
<li>www.grapheneos.foundation</li>
<li>grapheneos.info</li>
<li>www.grapheneos.info</li>
<li>grapheneos.net</li>
<li>www.grapheneos.net</li>
<li>grapheneos.ovh</li>
<li>www.grapheneos.ovh</li>
<li>grapheneos.page</li>
<li>www.grapheneos.page</li>
<li>vanadium.app</li>
<li>www.vanadium.app</li>
</ul>
<p>IPs:</p>
<ul>
<li>51.222.156.101 (0.grapheneos.org) — OVH bhs6</li>
<li>2607:5300:205:200::29c6 (0.grapheneos.org) — OVH bhs6</li>
<li>209.141.35.164 (1.grapheneos.org) — BuyVM Las Vegas</li>
<li>2605:6400:20:1131:8088:e08:84e6:632 (1.grapheneos.org) — BuyVM Las Vegas</li>
<li>54.37.41.189 (2.grapheneos.org) — OVH gra8</li>
<li>2001:41d0:304:200::b109 (2.grapheneos.org) — OVH gra8</li>
<li>51.79.160.50 (3.grapheneos.org) — OVH sgp2</li>
<li>2402:1f00:8000:800::16d6 (3.grapheneos.org) — OVH sgp2</li>
</ul>
<p>Ports:</p>
<ul>
<li>TCP 22 ssh</li>
<li>TCP 80 http</li>
<li>TCP 443 https</li>
</ul>
</section>
<section id="staging.grapheneos.org">
<h2><a href="#staging.grapheneos.org">Staging GrapheneOS website</a></h2>
<ul>
<li><a href="https://github.com/GrapheneOS/grapheneos.org">Repository</a></li>
<li><a href="https://github.com/GrapheneOS/grapheneos.org/issues">Issue tracker</a></li>
</ul>
<p>Specs:</p>
<ul>
<li>BuyVM Slice 1024</li>
<li>1 core</li>
<li>1 GB memory</li>
<li>20 GB NVMe SSD storage</li>
<li>1000 Mbit/s bandwidth</li>
</ul>
<p>Domains:</p>
<ul>
<li>staging.grapheneos.org</li>
</ul>
<p>IPs:</p>
<ul>
<li>199.195.250.78 — BuyVM New York</li>
<li>2605:6400:10:9d6:6d84:e183:acda:16d7 — BuyVM New York</li>
</ul>
<p>Ports:</p>
<ul>
<li>TCP 22 ssh</li>
<li>TCP 80 http</li>
<li>TCP 443 https</li>
</ul>
</section>
<section id="releases.grapheneos.org">
<h2><a href="#releases.grapheneos.org">GrapheneOS release servers</a></h2>
<p>These are the static file servers for GrapheneOS releases and our app
repository. These are used by the releases page and web installer along with the
System Updater and App Store (app repository client) within the OS.</p>
<ul>
<li><a href="https://github.com/GrapheneOS/releases.grapheneos.org">Repository</a></li>
<li><a href="https://github.com/GrapheneOS/releases.grapheneos.org/issues">Issue tracker</a></li>
</ul>
<p>Specs:</p>
<ul>
<li>Macarne dedicated server (sponsored by <a href="https://macarne.com/">Macarne</a>)</li>
<li>Ryzen 9950X</li>
<li>128 GB DDR5</li>
<li>2x 2 TB NVMe SSD storage</li>
<li>25000 Mbit/s bandwidth</li>
</ul>
<ul>
<li>2x ReliableSite dedicated server (sponsored by <a href="https://www.reliablesite.net/">ReliableSite</a>)</li>
<li>Ryzen 9900X</li>
<li>192 GB DDR5</li>
<li>2x 4 TB NVMe SSD storage</li>
<li>10000 Mbit/s bandwidth</li>
</ul>
<p>Domains:</p>
<ul>
<li>releases.grapheneos.org</li>
<li>seamlessupdate.app</li>
<li>www.seamlessupdate.app</li>
<li>apps.grapheneos.org</li>
</ul>
<p>IPs:</p>
<ul>
<li>45.90.185.33 (4.releases.grapheneos.org) — Macarne Amsterdam</li>
<li>2a14:3f87:6920:250::100 (4.releases.grapheneos.org) — Macarne Amsterdam</li>
<li>172.96.172.37 (5.releases.grapheneos.org) — ReliableSite Miami</li>
<li>2605:9880:400:1100:15:1240:515:6e (5.releases.grapheneos.org) — ReliableSite Miami</li>
<li>104.194.8.203 (6.releases.grapheneos.org) — ReliableSite Los Angeles</li>
<li>2605:9880:200:20::113 (6.releases.grapheneos.org) — ReliableSite Los Angeles</li>
</ul>
<p>Ports:</p>
<ul>
<li>TCP 22 ssh</li>
<li>TCP 80 http</li>
<li>TCP 443 https</li>
</ul>
</section>
<section id="grapheneos.network">
<h2><a href="#grapheneos.network">GrapheneOS network servers</a></h2>
<p>These are the default servers used by GrapheneOS for connectivity checks,
secure network time, attestation key provisioning and Predicted Satellite Data
Service (PSDS). These either serve empty responses or provide reverse proxies to
other services.</p>
<ul>
<li><a href="https://github.com/GrapheneOS/grapheneos.network">Repository</a></li>
<li><a href="https://github.com/GrapheneOS/grapheneos.network/issues">Issue tracker</a></li>
</ul>
<p>Specs:</p>
<ul>
<li>3x OVH VPS vps2023-le-2</li>
<li>2 core</li>
<li>2 GB memory</li>
<li>40 GB NVMe SSD storage</li>
<li>500 Mbit/s bandwidth</li>
</ul>
<ul>
<li>1x BuyVM Slice 1024</li>
<li>1 core</li>
<li>1 GB memory</li>
<li>20 GB NVMe SSD storage</li>
<li>1000 Mbit/s bandwidth</li>
</ul>
<p>Domains:</p>
<ul>
<li>grapheneos.network - HTTP/HTTPS connectivity checks</li>
<li>connectivitycheck.grapheneos.network - HTTP/HTTPS connectivity checks</li>
<li>www.grapheneos.network</li>
<li>grapheneos.online - HTTP/HTTPS connectivity checks</li>
<li>connectivitycheck.grapheneos.online - HTTP/HTTPS connectivity checks</li>
<li>www.grapheneos.online</li>
<li>broadcom.psds.grapheneos.org - HTTPS Broadcom PSDS data cache</li>
<li>samsung.psds.grapheneos.org - HTTPS Samsung PSDS data cache</li>
<li>qualcomm.psds.grapheneos.org - HTTPS Qualcomm PSDS data cache</li>
<li>remoteprovisioning.grapheneos.org - HTTPS reverse proxy to remoteprovisioning.google.com</li>
<li>widevineprovisioning.grapheneos.org - HTTPS reverse proxy for Widevine provisioning</li>
<li>time.grapheneos.org - HTTPS time server with millisecond precision X-Time header</li>
<li>supl.grapheneos.org - TLS reverse proxy to supl.google.com</li>
<li>nominatim.grapheneos.org - HTTPS reverse proxy to nominatim.openstreetmap.org, which will become our own instance of Nominatim instead of a proxy</li>
<li>gs-loc.apple.grapheneos.org - HTTPS reverse proxy to Apple's network location service, which will remain an option after we have our own location service</li>
<li>update.vanadium.app - HTTPS reverse proxy to update.googleapis.com for Chromium component updates (will be hosted directly in the future)</li>
<li>dl.vanadium.app - HTTPS reverse proxy to CDNs for Chromium component updates (will be hosted directly in the future)</li>
</ul>
<p>IPs:</p>
<ul>
<li>51.222.159.116 (0.grapheneos.network) — OVH bhs6</li>
<li>2607:5300:205:200::2584 (0.grapheneos.network) — OVH bhs6</li>
<li>209.141.37.35 (1.grapheneos.network) — BuyVM Las Vegas</li>
<li>2605:6400:20:387:72d4:dab9:a369:f351 (1.grapheneos.network) — BuyVM Las Vegas</li>
<li>54.37.41.188 (2.grapheneos.network) — OVH gra8</li>
<li>2001:41d0:304:200::902f (2.grapheneos.network) — OVH gra8</li>
<li>51.79.161.36 (3.grapheneos.network) — OVH sgp2</li>
<li>2402:1f00:8000:800::1949 (3.grapheneos.network) — OVH sgp2</li>
</ul>
<p>Ports:</p>
<ul>
<li>TCP 22 ssh</li>
<li>TCP 80 http</li>
<li>UDP 123 ntp</li>
<li>TCP 443 https</li>
<li>TCP 7275 supl</li>
</ul>
</section>
<section id="mail.grapheneos.org">
<h2><a href="#mail.grapheneos.org">GrapheneOS mail server</a></h2>
<ul>
<li><a href="https://github.com/GrapheneOS/mail.grapheneos.org">Repository</a></li>
<li><a href="https://github.com/GrapheneOS/mail.grapheneos.org/issues">Issue tracker</a></li>
</ul>
<p>Specs:</p>
<ul>
<li>OVH VPS vps2023-le-2</li>
<li>2 core</li>
<li>2 GB memory</li>
<li>40 GB NVMe SSD storage</li>
<li>500 Mbit/s bandwidth</li>
</ul>
<p>Domains:</p>
<ul>
<li>mail.grapheneos.net</li>
<li>mail.grapheneos.org</li>
<li>mta-sts.attestation.app</li>
<li>mta-sts.discuss.grapheneos.org</li>
<li>mta-sts.grapheneos.app</li>
<li>mta-sts.grapheneos.ca</li>
<li>mta-sts.grapheneos.com</li>
<li>mta-sts.grapheneos.dev</li>
<li>mta-sts.grapheneos.foundation</li>
<li>mta-sts.grapheneos.info</li>
<li>mta-sts.grapheneos.net</li>
<li>mta-sts.grapheneos.network</li>
<li>mta-sts.grapheneos.online</li>
<li>mta-sts.grapheneos.org</li>
<li>mta-sts.grapheneos.ovh</li>
<li>mta-sts.grapheneos.page</li>
<li>mta-sts.grapheneos.social</li>
<li>mta-sts.mail.grapheneos.org</li>
<li>mta-sts.matrix.grapheneos.org</li>
<li>mta-sts.seamlessupdate.app</li>
<li>mta-sts.vanadium.app</li>
</ul>
<p>IPs:</p>
<ul>
<li>192.99.98.22 — OVH bhs6</li>
<li>2607:5300:205:200::472f — OVH bhs6</li>
</ul>
<p>Ports:</p>
<ul>
<li>TCP 22 ssh</li>
<li>TCP 25 smtp</li>
<li>TCP 80 http</li>
<li>TCP 443 https</li>
<li>TCP 465 submissions</li>
<li>TCP 993 imaps</li>
</ul>
</section>
<section id="discuss.grapheneos.org">
<h2><a href="#discuss.grapheneos.org">GrapheneOS discussion forum server</a></h2>
<ul>
<li><a href="https://github.com/GrapheneOS/discuss.grapheneos.org">Repository</a></li>
<li><a href="https://github.com/GrapheneOS/discuss.grapheneos.org/issues">Issue tracker</a></li>
</ul>
<p>Specs:</p>
<ul>
<li>OVH VPS vps2023-le-4</li>
<li>4 core</li>
<li>4 GB memory</li>
<li>80 GB NVMe SSD storage</li>
<li>1000 Mbit/s bandwidth</li>
</ul>
<p>Domains:</p>
<ul>
<li>discuss.grapheneos.org</li>
</ul>
<p>IPs:</p>
<ul>
<li>51.222.14.6 — OVH bhs6</li>
<li>2607:5300:205:200::29e8 — OVH bhs6</li>
</ul>
<p>Ports:</p>
<ul>
<li>TCP 22 ssh</li>
<li>TCP 80 http</li>
<li>TCP 443 https</li>
</ul>
</section>
<section id="grapheneos.social">
<h2><a href="#grapheneos.social">GrapheneOS Mastodon server</a></h2>
<ul>
<li><a href="https://github.com/GrapheneOS/grapheneos.social">Repository</a></li>
<li><a href="https://github.com/GrapheneOS/grapheneos.social/issues">Issue tracker</a></li>
</ul>
<p>Specs:</p>
<ul>
<li>OVH VPS vps2023-le-4</li>
<li>4 core</li>
<li>4 GB memory</li>
<li>80 GB NVMe SSD storage</li>
<li>1000 Mbit/s bandwidth</li>
</ul>
<p>Domains:</p>
<ul>
<li>grapheneos.social</li>
<li>www.grapheneos.social</li>
</ul>
<p>IPs:</p>
<ul>
<li>51.222.159.14 — OVH bhs6</li>
<li>2607:5300:205:200::5e3f — OVH bhs6</li>
</ul>
<p>Ports:</p>
<ul>
<li>TCP 22 ssh</li>
<li>TCP 80 http</li>
<li>TCP 443 https</li>
</ul>
</section>
<section id="matrix.grapheneos.org">
<h2><a href="#matrix.grapheneos.org">GrapheneOS Matrix server</a></h2>
<p>This server primarily runs the synapse Matrix server with PostgreSQL behind an
nginx web server. It also runs the mjolnir bot for moderation and matterbridge is
used to implement a bridge between Matrix, IRC and Telegram.</p>
<ul>
<li><a href="https://github.com/GrapheneOS/matrix.grapheneos.org">Repository</a></li>
<li><a href="https://github.com/GrapheneOS/matrix.grapheneos.org/issues">Issue tracker</a></li>
</ul>
<p>Specs:</p>
<ul>
<li>OVH VPS vps2020-comfort-4-8-160</li>
<li>4 core</li>
<li>8 GB memory</li>
<li>160 GB NVMe SSD storage</li>
<li>1000 Mbit/s bandwidth</li>
</ul>
<p>Domains:</p>
<ul>
<li>matrix.grapheneos.org</li>
<li>element.grapheneos.org</li>
</ul>
<p>IPs:</p>
<ul>
<li>51.79.51.42 — OVH bhs6</li>
<li>2607:5300:205:200::26e1 — OVH bhs6</li>
</ul>
<p>Ports:</p>
<ul>
<li>TCP 22 ssh</li>
<li>TCP 80 http</li>
<li>TCP 443 https</li>
</ul>
</section>
<section id="ns1.grapheneos.org">
<h2><a href="#ns1.grapheneos.org">GrapheneOS DNS servers</a></h2>
<ul>
<li><a href="https://github.com/GrapheneOS/ns1.grapheneos.org">Repository</a></li>
<li><a href="https://github.com/GrapheneOS/ns1.grapheneos.org/issues">Issue tracker</a></li>
</ul>
<p>Specs:</p>
<ul>
<li>4x OVH VPS vps2023-le-2</li>
<li>2 core</li>
<li>2 GB memory</li>
<li>40 GB NVMe SSD storage</li>
<li>500 Mbit/s bandwidth</li>
</ul>
<ul>
<li>3x BuyVM Slice 1024</li>
<li>1 core</li>
<li>1 GB memory</li>
<li>20 GB NVMe SSD storage</li>
<li>1000 Mbit/s bandwidth</li>
</ul>
<p>Domains:</p>
<ul>
<li>ns1.attestation.app</li>
<li>ns1.grapheneos.app</li>
<li>ns1.grapheneos.ca</li>
<li>ns1.grapheneos.com</li>
<li>ns1.grapheneos.dev</li>
<li>ns1.grapheneos.foundation</li>
<li>ns1.grapheneos.info</li>
<li>ns1.grapheneos.net</li>
<li>ns1.grapheneos.network</li>
<li>ns1.grapheneos.online</li>
<li>ns1.grapheneos.org</li>
<li>ns1.grapheneos.ovh</li>
<li>ns1.grapheneos.page</li>
<li>ns1.grapheneos.social</li>
<li>ns1.seamlessupdate.app</li>
<li>ns1.vanadium.app</li>
<li>ns2.attestation.app</li>
<li>ns2.grapheneos.app</li>
<li>ns2.grapheneos.ca</li>
<li>ns2.grapheneos.com</li>
<li>ns2.grapheneos.dev</li>
<li>ns2.grapheneos.foundation</li>
<li>ns2.grapheneos.info</li>
<li>ns2.grapheneos.net</li>
<li>ns2.grapheneos.network</li>
<li>ns2.grapheneos.online</li>
<li>ns2.grapheneos.org</li>
<li>ns2.grapheneos.ovh</li>
<li>ns2.grapheneos.page</li>
<li>ns2.grapheneos.social</li>
<li>ns2.seamlessupdate.app</li>
<li>ns2.vanadium.app</li>
</ul>
<p>IPs:</p>
<ul>
<li>185.187.152.9 (anycast), 51.161.34.158 (0.ns1.grapheneos.org) — OVH bhs6</li>
<li>2a05:b0c4:1::8 (anycast), 2607:5300:205:200::eaa (0.ns1.grapheneos.org) — OVH bhs6</li>
<li>185.187.152.9 (anycast), 15.204.8.153 (1.ns1.grapheneos.org) — OVH US us-west-or-2</li>
<li>2a05:b0c4:1::8 (anycast), 2604:2dc0:202:300::23a6 (1.ns1.grapheneos.org) — OVH us-west-or-2</li>
<li>185.187.152.9 (anycast) 57.129.65.223 (2.ns1.grapheneos.org) — OVH de2</li>
<li>2a05:b0c4:1::8 (anycast) 2001:41d0:701:1100::245b (2.ns1.grapheneos.org) — OVH de2</li>
<li>185.187.152.9 (anycast) 15.235.197.61 (3.ns1.grapheneos.org) — OVH sgp2</li>
<li>2a05:b0c4:1::8 (anycast) 2402:1f00:8000:800::3966 (3.ns1.grapheneos.org) — OVH sgp2</li>
<li>198.251.90.93 (anycast), 198.98.53.141 (0.ns2.grapheneos.org) — BuyVM New York</li>
<li>2605:6400:10:102e:95bc:89ef:2e7f:49bb (0.ns2.grapheneos.org) — BuyVM New York</li>
<li>198.251.90.93 (anycast), 205.185.124.155 (1.ns2.grapheneos.org) — BuyVM Las Vegas</li>
<li>2605:6400:20:1c8f:a0c9:372d:482e:945b (1.ns2.grapheneos.org) — BuyVM Las Vegas</li>
<li>198.251.90.93 (anycast), 107.189.3.168 (2.ns2.grapheneos.org) — BuyVM Luxembourg</li>
<li>2605:6400:30:ec25:102c:af6d:5be:1eb8 (2.ns2.grapheneos.org) — BuyVM Luxembourg</li>
</ul>
<p>Ports:</p>
<ul>
<li>TCP 22 ssh</li>
<li>TCP 53 domain</li>
<li>UDP 53 domain</li>
<li>TCP 80 http</li>
<li>TCP 443 https</li>
<li>TCP 853 domain-s</li>
</ul>
</section>
<section id="ns1.staging.grapheneos.org">
<h2><a href="#ns1.staging.grapheneos.org">Staging GrapheneOS DNS server</a></h2>
<ul>
<li><a href="https://github.com/GrapheneOS/ns1.grapheneos.org">Repository</a></li>
<li><a href="https://github.com/GrapheneOS/ns1.grapheneos.org/issues">Issue tracker</a></li>
</ul>
<p>Specs:</p>
<ul>
<li>BuyVM Slice 1024</li>
<li>1 core</li>
<li>1 GB memory</li>
<li>20 GB NVMe SSD storage</li>
<li>1000 Mbit/s bandwidth</li>
</ul>
<p>Domains:</p>
<ul>
<li>ns1.staging.attestation.app</li>
<li>ns2.staging.attestation.app</li>
<li>ns1.staging.grapheneos.org</li>
<li>ns2.staging.grapheneos.org</li>
</ul>
<p>IPs:</p>
<ul>
<li>198.98.56.238 — BuyVM New York</li>
<li>2605:6400:10:c41:de92:c534:326a:711a — BuyVM New York</li>
</ul>
<p>Ports:</p>
<ul>
<li>TCP 22 ssh</li>
<li>TCP 53 domain</li>
<li>UDP 53 domain</li>
<li>TCP 80 http</li>
<li>TCP 443 https</li>
<li>TCP 853 domain-s</li>
</ul>
</section>
<section id="attestation.app">
<h2><a href="#attestation.app">Attestation website and service</a></h2>
<ul>
<li><a href="https://github.com/GrapheneOS/AttestationServer">Repository</a></li>
<li><a href="https://github.com/GrapheneOS/AttestationServer/issues">Issue tracker</a></li>
</ul>
<p>Specs:</p>
<ul>
<li>OVH VPS vps2023-le-4</li>
<li>4 core</li>
<li>4 GB memory</li>
<li>80 GB NVMe SSD storage</li>
<li>1000 Mbit/s bandwidth</li>
</ul>
<p>Domains:</p>
<ul>
<li>attestation.app</li>
<li>www.attestation.app</li>
</ul>
<p>IPs:</p>
<ul>
<li>51.79.66.27 — OVH bhs6</li>
<li>2607:5300:205:200::7e9 — OVH bhs6</li>
</ul>
<p>Ports:</p>
<ul>
<li>TCP 22 ssh</li>
<li>TCP 80 http</li>
<li>TCP 443 https</li>
</ul>
</section>
<section id="staging.attestation.app">
<h2><a href="#staging.attestation.app">Staging attestation website and service</a></h2>
<ul>
<li><a href="https://github.com/GrapheneOS/AttestationServer">Repository</a></li>
<li><a href="https://github.com/GrapheneOS/AttestationServer/issues">Issue tracker</a></li>
</ul>
<p>Specs:</p>
<ul>
<li>BuyVM Slice 1024</li>
<li>1 core</li>
<li>1 GB memory</li>
<li>20 GB NVMe SSD storage</li>
<li>1000 Mbit/s bandwidth</li>
</ul>
<p>Domains:</p>
<ul>
<li>staging.attestation.app</li>
</ul>
<p>IPs:</p>
<ul>
<li>198.98.57.157 — BuyVM New York</li>
<li>2605:6400:10:aa9:1c0f:44d3:da15:c0ec — BuyVM New York</li>
</ul>
<p>Ports:</p>
<ul>
<li>TCP 22 ssh</li>
<li>TCP 80 http</li>
<li>TCP 443 https</li>
</ul>
</section>
</main>
{% include "footer.html" %}
</body>
</html>

View File

@ -1,66 +0,0 @@
<!DOCTYPE html>
<html lang="en" prefix="og: https://ogp.me/ns#">
<head>
<meta charset="utf-8"/>
<title>Articles | GrapheneOS</title>
<meta name="description" content="Articles on assorted topics related to GrapheneOS."/>
<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, viewport-fit=cover"/>
<meta name="twitter:site" content="@GrapheneOS"/>
<meta name="twitter:creator" content="@GrapheneOS"/>
<meta property="og:title" content="Articles | GrapheneOS"/>
<meta property="og:description" content="Articles on assorted topics related to GrapheneOS."/>
<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/articles/"/>
<link rel="canonical" href="https://grapheneos.org/articles/"/>
<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"/>
</head>
<body>
{% with current_page="articles" %}
{% include "header.html" %}
{% endwith %}
<main id="articles">
<h1><a href="#articles">Articles</a></h1>
<p>The main documentation for GrapheneOS is at the top-level of the site:</p>
<ul>
<li><a href="/features">Features overview</a> — Overview of GrapheneOS features differentiating it from the Android Open Source Project.</li>
<li><a href="/install/">Install</a> — Installation instructions for GrapheneOS.</li>
<li><a href="/build">Build</a> — Building instructions for GrapheneOS.</li>
<li><a href="/usage">Usage guide</a> — Usage instructions for GrapheneOS.</li>
<li><a href="/faq">Frequently Asked Questions</a> — Answers to frequently asked questions about GrapheneOS.</li>
<li><a href="/releases#changelog">Releases changelog</a> — Changelog for official releases of GrapheneOS.</li>
<li><a href="/source">Source code</a> — Documenting all source code repositories for GrapheneOS.</li>
<li><a href="/history/">History</a> — History of the GrapheneOS project.</li>
</ul>
<p>Our attestation service has <a href="https://attestation.app/about">a page
explaining how the Auditor app and attestation service work</a>.</p>
<p>Other articles on assorted topics related to GrapheneOS:</p>
<ul>
<li><a href="/articles/attestation-compatibility-guide">Attestation compatibility guide</a> — Guide on using remote attestation in a way that's compatible with GrapheneOS</li>
<li><a href="/articles/grapheneos-servers">GrapheneOS servers</a> — Documentation on GrapheneOS servers.</li>
<li><a href="/articles/server-traffic-shaping">Server traffic shaping</a> — Implementing server traffic shaping on Linux with CAKE.</li>
<li><a href="/articles/sitewide-advertising-industry-opt-out">Sitewide advertising industry opt-out</a> — Using ads.txt / app-ads.txt to disallow buying or selling ads for a domain.</li>
</ul>
</main>
{% include "footer.html" %}
</body>
</html>

View File

@ -1,89 +0,0 @@
<!DOCTYPE html>
<html lang="en" prefix="og: https://ogp.me/ns#">
<head>
<meta charset="utf-8"/>
<title>Positon location service | Articles | GrapheneOS</title>
<meta name="description" content="Information about the Positon location service."/>
<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, viewport-fit=cover"/>
<meta name="twitter:site" content="@GrapheneOS"/>
<meta name="twitter:creator" content="@GrapheneOS"/>
<meta property="og:title" content="Positon location service"/>
<meta property="og:description" content="Information about the Positon location service."/>
<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/articles/positon-location-service"/>
<link rel="canonical" href="https://grapheneos.org/articles/positon-location-service"/>
<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"/>
</head>
<body>
{% include "header.html" %}
<main id="positon-location-service">
<h1><a href="#positon-location-service">Positon location service</a></h1>
<p>The Positon location service is a proprietary and highly privacy invasive service
created by developers tied to /e/OS with their funding. There's a deliberate effort to
hide that it's tied to them in order to convince other projects to adopt it, as opposed
to using the similar service they host for /e/OS itself. Using the service requires
uploading sensitive location data to obtain location estimates, similar to the Apple and
Google location services. As with the Apple and Google services, it's a centralized
proprietary service with fully proprietary data. Unlike those services, the people
behind it have a history of publishing notoriously insecure software such as the /e/OS
operating system itself which massively rolls back standard security, lags years behind
on security updates and covers all of that up. They blatantly scam their users with
false privacy/security claims for /e/OS, and nothing different should be expected from a
location service from the same group of people. Multiple people involved in it are also
actively participating in harassment targeting privacy/security researchers and
engineers including but not limited to GrapheneOS team members.</p>
<p>The people behind the Positon location service have repeatedly talked about the
importance they see in centralizing the whole open source community around using their
service while locking out alternatives to it through proprietary data. They have spread
fear, uncertainty and doubt about making services using open mapping data through
claiming that it's a privacy hazard for people to have access to maps of Wi-Fi networks
publicly broadcasting their SSID despite that data already being available through many
commercial providers including publicly queryable databases such as Wigle. Anyone can
drive around building these maps and many companies have already built them, with the
data available for sale, as Positon shows with them obtaining access to it. The real
privacy hazard is sending your location in real time to a service, particularly a poorly
secured one from people known to cover up and downplay vulnerabilities. Positon has been
built to grab as much market share as possible early on before actual open options can
emerge and gather the necessary data.</p>
<p>The people involved in Positon have only ever cared about their careers, power and
influence. They've consistently been on a side against real privacy and security, but
rather focused on monetizing people's demand for it and grabbing as much market share as
they can as quickly as they can with endless false marketing and attacks on projects
like GrapheneOS. They see GrapheneOS as a huge threat to them due to us striving to
bring people real privacy and security at no cost, which is far easier to obtain and
use. This invalidates the business model of their companies like Murena. They
consistently use their non-profits mainly as a way to earn money and promote their
for-profit initiatives.</p>
<p>The service claims to be free of charge, but a core goal is turning it into a way to
get data from users to build their own database that's largely not going to be available
for use by others. Using it is helping them build a future business at the expense of
user privacy, little different from the Apple and Google services. This is not what the
open source community needs from a location service. The claims of no strings attached
and the implication that it's open are nonsense. Storing as little data as possible
would mean using local database for the region, not a network-based service. They're
opposed to doing a local service well rather than it being their long term goal. They
explicitly aim to lock out other alternatives and deter local location detection via
Wi-Fi.</p>
</main>
{% include "footer.html" %}
</body>
</html>

View File

@ -1,259 +0,0 @@
<!DOCTYPE html>
<html lang="en" prefix="og: https://ogp.me/ns#">
<head>
<meta charset="utf-8"/>
<title>Server traffic shaping | Articles | GrapheneOS</title>
<meta name="description" content="Implementing server traffic shaping on Linux with CAKE."/>
<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, viewport-fit=cover"/>
<meta name="twitter:site" content="@GrapheneOS"/>
<meta name="twitter:creator" content="@GrapheneOS"/>
<meta property="og:title" content="Server traffic shaping"/>
<meta property="og:description" content="Implementing server traffic shaping on Linux with CAKE."/>
<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/articles/server-traffic-shaping"/>
<link rel="canonical" href="https://grapheneos.org/articles/server-traffic-shaping"/>
<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"/>
</head>
<body>
{% include "header.html" %}
<main id="server-traffic-shaping">
<h1><a href="#server-traffic-shaping">Server traffic shaping</a></h1>
<p>This article covers implementing server traffic shaping on Linux with CAKE. The aim
is to provide fair usage of bandwidth between clients and consistently low latency
for dedicated and virtual servers provided by companies like OVH and others.</p>
<p>Traffic shaping is generally discussed in the context of a router shaping traffic
for a local network with assorted clients connected. It also has a lot to offer on a
server where you don't control the network. If you control your own infrastructure
from the server to the ISP, you probably want to do this on the routers instead.</p>
<p>This article was motivated by the serious lack of up-to-date information on this
topic elsewhere. It's very easy to implement on modern Linux kernels and the results
are impressive from extremely simple test cases to heavily loaded servers.</p>
<section id="problem">
<h2><a href="#problem">Problem</a></h2>
<p>A server will generally be provisioned with a specific amount of bandwidth
enforced by a router in close proximity. This router acts as the bottleneck and
ends up being in charge of most of the queuing and congestion decisions. Unless
that's under your control, the best you can hope for is that the router is
configured to use <code>fq_codel</code> as the queuing discipline (qdisc) to
provide fair queuing between streams and low latency by preventing a substantial
backlog of data.</p>
<p>Unfortunately, the Linux kernel still defaults to <code>pfifo_fast</code>
instead of the much saner <code>fq_codel</code> algorithm. This is changed by a
configuration file shipped with systemd, so <em>most</em> distributions using
systemd as init end up with a sane default. Debian removes that configuration and
doesn't set a sane default itself, and is widely used. Many server providers like
OVH do not appear to consistently use modern queue disciplines like
<code>fq_codel</code> within their networks, particularly at artificial
bottlenecks implementing rate limiting based on product tiers.</p>
<p>If the bottleneck doesn't use fair queuing, division of bandwidth across
streams is very arbitrary and latency suffers under congestion. These issues are
often referred to as bufferbloat, and <code>fq_codel</code> is quite good at
resolving it.</p>
<p>The <code>fq_codel</code> algorithm is far from perfect. It has issues with
hash collisions and more importantly only does fair queuing between streams.
Buffer bloat also isn't the only relevant issue. Clients with multiple connections
receive more bandwidth and a client can open a large number of connections to
maximize their bandwidth usage at the expense of others. Fair queuing is important
beyond as a solution to bufferbloat and there's more to fair queuing than doing it
only based on streams.</p>
<p>Traditionally, web browsers open a bunch of HTTP/1.1 connections to each server
which ends up giving them an unfair amount of bandwidth. HTTP/2 is much friendlier
since it uses a single connection to each server for the entire browser. Download
managers take this to the extreme and intentionally use many connections to bypass
server limits and game the division of resources between clients.</p>
</section>
<section id="solution">
<h2><a href="#solution">Solution</a></h2>
<p>Linux 4.19 and later makes it easy to solve all of these problems. The CAKE
queuing discipline provides sophisticated fair queuing based on destination and
source addresses with finer-grained fairness for individual streams.</p>
<p> Unfortunately, simply enabling it as your queuing discipline isn't enough
since it's highly unlikely that your server is the network bottleneck. You need to
configure it with a bandwidth limit based on the provisioned bandwidth to move the
bottleneck under your control where you can control how traffic is queued.</p>
</section>
<section id="results">
<h2><a href="#results">Results</a></h2>
<p>We've used an 100mbit OVH server for as a test platform for a case where
clients can easily max out the server bandwidth on their own. As a very simple
example, consider 2 clients with more than 100mbit of bandwidth each downloading a
large file. These are (rounded) real world results with CAKE:</p>
<ul>
<li>client A with 1 connection gets 50mbit</li>
<li>client B with 10 connections gets 5mbit each adding up to 50mbit</li>
</ul>
<p>CAKE with <code>flows</code> instead of the default <code>triple-isolate</code> to
mimic <code>fq_codel</code> at a bottleneck:</p>
<ul>
<li>client A with 1 connection gets 9mbit</li>
<li>client B with 10 connections gets 9mbit each adding up to 90mbit</li>
</ul>
<p>The situation without traffic shaping is a mess. Latency takes a serious hit
that's very noticeable via SSH. Bandwidth is consistently allocated very unevenly
and ends up fluctuating substantially between test runs. The connections tend to
settle near a rate, often significantly lower or higher than the fair 9mbit
amount. It's generally something like this, but the range varies a lot:</p>
<ul>
<li>client A with 1 connection gets ~6mbit to ~14mbit</li>
<li>client B with 10 connections gets ~6mbit to ~14mbit each adding up to ~86mbit
to ~94mbit</li>
</ul>
<p>CAKE continues working as expected with a far higher number of connections. It
technically has a higher CPU cost than <code>fq_codel</code>, but that's much more
of a concern for low end router hardware. It hardly matters on a server, even one
that's under heavy CPU load. The improvement in user experience is substantial and
it's very noticeable in web page load speeds when a server is under load.</p>
</section>
<section id="implementation">
<h2><a href="#implementation">Implementation</a></h2>
<p>For a server with 2000mbit of bandwidth provisioned, you could start by trying
it with 99.75% of the provisioned bandwidth:</p>
<pre>tc qdisc replace dev eth0 root cake bandwidth 1995mbit besteffort</pre>
<p>On a server, setting it to use 100% of the provisioned bandwidth may work fine
in practice. Unlike a local network connected to a consumer ISP, you shouldn't
need to sacrifice anywhere close to the typically recommended 5-10% of your
bandwidth for traffic shaping.</p>
<p>This also sets <code>besteffort</code> for the common case where the server
doesn't have appropriate Quality of Service markings set up via Diffserv. Fair
scheduling is already great at providing low latency by cycling through the hosts
and streams without needing this kind of configuration. The defaults for Diffserv
traffic classes like real-time video are set up to yield substantial bandwidth in
exchange for lower latency. It's easy to set this up wrong and it usually won't
make much sense on a server. You might want to set up marking low priority traffic
like system updates, but it will already get a tiny share of the overall traffic
on a loaded server due to fair scheduling between hosts and streams.</p>
<p>You can use the <code>tc -s qdisc</code> command to monitor CAKE:</p>
<pre>tc -s qdisc show dev eth0</pre>
<p>If you want to keep an eye on how it changes over time:</p>
<pre>watch -n 1 tc -s qdisc show dev eth0</pre>
<p>This is very helpful for figuring out if you've successfully moved the
bottleneck to the server. If the bandwidth is being fully used, it should
consistently have a backlog of data where it's applying the queuing discipline.
The backlog shouldn't be draining to near zero under full bandwidth usage as that
indicates the bottleneck is the server application itself or a different network
bottleneck.</p>
<p>If you use systemd-network, you can add a CAKE configuration section to the
network configuration file instead of manually running the <code>tc</code> command
with a <code>Type=oneshot</code> service on boot:</p>
<pre>[CAKE]
Bandwidth=1995M
PriorityQueueingPreset=besteffort</pre>
</section>
<section id="quicker-backpressure-propagation">
<h2><a href="#quicker-backpressure-propagation">Quicker backpressure propagation</a></h2>
<p>The Linux kernel can be tuned to more quickly propagate TCP backpressure up to
applications while still maximizing bandwidth usage. This is incredibly useful for
interactive applications aiming to send the freshest possible copy of data and for
protocols like HTTP/2 multiplexing streams/messages with different priorities over
the same TCP connection. This can also substantially reduce memory usage for TCP
by reducing buffer sizes closer to the optimal amount for maximizing bandwidth
use without wasting memory. The downside to quicker backpressure propagation is
increased CPU usage from additional system calls and context switches.</p>
<p>The Linux kernel automatically adjusts the size of the write queue to maximize
bandwidth usage. The write queue is divided into unacknowledged bytes (TCP window
size) and unsent bytes. As acknowledgements of transmitted data are received, it
frees up space for the application to queue more data. The queue of unsent bytes
provides the leeway needed to wake the application and obtain more data. This can
be reduced using <code>net.ipv4.tcp_notsent_lowat</code> to reduce the default and
the <code>TCP_NOTSENT_LOWAT</code> socket option to override it per-socket.</p>
<p>A reasonable choice for internet-based workloads concerned about latency and
particularly prioritization within TCP connections but unwilling to sacrifice
throughput is 128kiB. To configure this, set the following in
<code>/etc/sysctl.d/local.conf</code> or another sysctl configuration file and
load it with <code>sysctl --system</code>:</p>
<pre>net.ipv4.tcp_notsent_lowat = 131072</pre>
<p>Using values as low as 16384 can make sense to further improve latency and
prioritization. However, it's more likely to negatively impact throughput and will
further increase CPU usage. Use at least 128k or the default of not limiting the
automatic unsent buffer size unless you're going to do substantial testing to make
sure there's not a negative impact for the workload.</p>
<p>If you decide to use <code>tcp_notsent_lowat</code>, be aware that newer Linux
kernels (Linux 5.0+ with a further improvement for Linux 5.10+) are recommended to
substantially reduce system calls / context switches by not triggering the
application to provide more data until over half the unsent byte buffer is
empty.</p>
</section>
<section id="high-link-speed">
<h2><a href="#high-link-speed">High link speed</a></h2>
<p>By default, CAKE splits General Segmentation Offload (GSO) super-packets to
reduce latency at the expense of CPU efficiency and throughput. This can create a
bottleneck at high link speeds. We've had to disable this on the 2Gbit GrapheneOS
update servers.</p>
<pre>[CAKE]
Bandwidth=1995M
PriorityQueueingPreset=besteffort
SplitGSO=false</pre>
</section>
<section id="future">
<h2><a href="#future">Future</a></h2>
<p>Ideally, data centers would deploy CAKE throughout their networks with the
default <code>triple-isolate</code> flow isolation. This may mean they need to use
more powerful hardware for routing. If the natural bottlenecks used CAKE, setting
up traffic shaping on the server wouldn't be necessary. This doesn't seem likely
any time soon. Deploying <code>fq_codel</code> is much more realistic and tackles
buffer bloat but not the issue of fairness between hosts rather than only
streams.</p>
</section>
</main>
{% include "footer.html" %}
</body>
</html>

View File

@ -1,65 +0,0 @@
<!DOCTYPE html>
<html lang="en" prefix="og: https://ogp.me/ns#">
<head>
<meta charset="utf-8"/>
<title>Sitewide advertising industry opt-out | Articles | GrapheneOS</title>
<meta name="description" content="Using ads.txt / app-ads.txt to disallow buying or selling ads for a domain."/>
<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, viewport-fit=cover"/>
<meta name="twitter:site" content="@GrapheneOS"/>
<meta name="twitter:creator" content="@GrapheneOS"/>
<meta property="og:title" content="Sitewide advertising industry opt-out"/>
<meta property="og:description" content="Using ads.txt / app-ads.txt to disallow buying or selling ads for a domain."/>
<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/articles/sitewide-advertising-industry-opt-out"/>
<link rel="canonical" href="https://grapheneos.org/articles/sitewide-advertising-industry-opt-out"/>
<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"/>
</head>
<body>
{% include "header.html" %}
<main id="sitewide-advertising-industry-opt-out">
<h1><a href="#sitewide-advertising-industry-opt-out">Sitewide advertising industry opt-out</a></h1>
<p>The <a href="https://iabtechlab.com/wp-content/uploads/2021/03/ads.txt-1.0.3.pdf">ads.txt specification</a>
provides a way to list the authorized sellers of ads for a domain. The
<a href="https://iabtechlab.com/wp-content/uploads/2019/03/app-ads.txt-v1.0-final-.pdf">app-ads.txt specification</a>
extends this to cover apps tied to the domain. As a domain owner, this is a valuable
way to crack down on fraudulent usage of your domain including by adware.</p>
<p>For domains without any third party advertising including those without any ads at
all, you should serve both <code>/ads.txt</code> and <code>/app-ads.txt</code> from a
web server with the placeholder record defined by the specification:</p>
<pre>placeholder.example.com, placeholder, DIRECT, placeholder</pre>
<p>The placeholder record formally disallows buying and selling ads on behalf of the
domain including for any subdomains. This prevents fraudulently buying / selling ads
for your domain anywhere that ads.txt / app-ads.txt are enforced.</p>
<p>It's in the interest of most ad tech companies to enforce these standards due to
losses from ad fraud so adoption is increasingly widespread.</p>
<p>Browser extension malware injecting ads into sites is very common and this is a way
for sites to hurt those malware developers where it hurts: their pocketbook.</p>
<p>These standards have a limited scope and were primarily created to address the cost
of ad fraud for the advertising industry, but they do offer value for domain owners to
protect their reputation and discourage adware.</p>
</main>
{% include "footer.html" %}
</body>
</html>

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because it is too large Load Diff

View File

@ -1,66 +0,0 @@
<!DOCTYPE html>
<html lang="en" prefix="og: https://ogp.me/ns#">
<head>
<meta charset="utf-8"/>
<title>Camera privacy policy | GrapheneOS</title>
<meta name="description" content="Privacy policy for the GrapheneOS Camera app."/>
<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, viewport-fit=cover"/>
<meta name="twitter:site" content="@GrapheneOS"/>
<meta name="twitter:creator" content="@GrapheneOS"/>
<meta property="og:title" content="Camera privacy policy"/>
<meta property="og:description" content="Privacy policy for the GrapheneOS Camera app."/>
<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/camera-privacy-policy"/>
<link rel="canonical" href="https://grapheneos.org/camera-privacy-policy"/>
<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"/>
</head>
<body>
{% include "header.html" %}
<main id="camera-privacy-policy">
<h1><a href="#camera-privacy-policy">Camera privacy policy</a></h1>
<p>This app requires the Camera permission for the core functionality of the app. The
Microphone permission is optional and only requested when starting video recording
without disabling "Include Audio". Video can be recorded without granting Microphone
access as long as "Include Audio" is disabled. Geotagging is disabled by default and
enabling it will request the Location permission. The app doesn't require access to
your media or other files. It stores files to the profile's Media Store and requests
that they be placed in DCIM/Camera which doesn't require a permission. You can also
choose to change the directory which will have you choose a directory for it to use
via the system file manager.</p>
<p>This app implements the system camera intent interfaces enabling other apps to use
it to take pictures or record videos with explicit user consent. Only the resulting
image or video explicitly captured by the user is given to the app. On Android 11 and
later, only a system camera app can provide the system camera intents. This app is the
system camera app on GrapheneOS where it provides that functionality. The handling of
the intents is carefully designed to make it harder to trick users into accidentally
capturing an image by implementing a delay.</p>
<p>This app does not make any network connections and doesn't use any services. The
app will never include any analytics/telemetry or any form of data collection. No
connections will ever be made to a service without the user requesting it. It stores
settings internally and pictures/videos captured by the user in Android's media store
for the profile.</p>
<p>Unlike nearly any other QR/barcode scanning apps, QR/barcode scanning does not open
the resulting URL automatically.</p>
</main>
{% include "footer.html" %}
</body>
</html>

View File

@ -2,24 +2,22 @@
<html lang="en" prefix="og: https://ogp.me/ns#">
<head>
<meta charset="utf-8"/>
<title>Contact | GrapheneOS</title>
<meta name="description" content="Contact information for GrapheneOS."/>
<title>Contact | Hakurei</title>
<meta name="description" content="Contact information for Hakurei."/>
<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, viewport-fit=cover"/>
<meta name="twitter:site" content="@GrapheneOS"/>
<meta name="twitter:creator" content="@GrapheneOS"/>
<meta property="og:title" content="GrapheneOS contact information"/>
<meta property="og:description" content="Contact information for GrapheneOS."/>
<meta property="og:title" content="Hakurei contact information"/>
<meta property="og:description" content="Contact information for Hakurei."/>
<meta property="og:type" content="website"/>
<meta property="og:image" content="https://grapheneos.org/opengraph.png"/>
<meta property="og:image" content="https://hakurei.app/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/contact"/>
<link rel="canonical" href="https://grapheneos.org/contact"/>
<meta property="og:image:alt" content="Hakurei logo"/>
<meta property="og:site_name" content="Hakurei"/>
<meta property="og:url" content="https://hakurei.app/contact.html"/>
<link rel="canonical" href="https://hakurei.app/contact.html"/>
<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"/>
@ -27,7 +25,7 @@
[[css|/main.css]]
<link rel="manifest" href="/manifest.webmanifest"/>
<link rel="license" href="/LICENSE.txt"/>
<link rel="me" href="https://grapheneos.social/@GrapheneOS"/>
<link rel="me" href="https://port.mk/@hakurei"/>
</head>
<body>
{% with current_page="contact" %}
@ -36,247 +34,11 @@
<main id="contact">
<h1><a href="#contact">Contact</a></h1>
<nav id="table-of-contents">
<h2><a href="#table-of-contents">Table of contents</a></h2>
<ul>
<li>
<a href="#community">Community</a>
<ul>
<li><a href="#community-chat">Chat</a></li>
<li><a href="#community-forum">Forum</a></li>
</ul>
</li>
<li><a href="#contacting-the-project">Contacting the project</a></li>
<li><a href="#hiring">Hiring</a></li>
<li>
<a href="#reporting-issues">Reporting issues</a>
<ul>
<li><a href="#standalone-apps">Standalone apps</a></li>
<li><a href="#services">Services</a></li>
</ul>
</li>
</ul>
</nav>
<section id="community">
<h2><a href="#community">Community</a></h2>
<section id="community-chat">
<h3><a href="#community-chat">Chat</a></h3>
<p>GrapheneOS has a very active community primarily based around the official
chat rooms. Our chat rooms are bridged across Discord, Telegram and Matrix so
you can choose your preferred platform.</p>
<p>Discord invite link: <a href="https://discord.com/invite/grapheneos">https://discord.com/invite/grapheneos</a>.</p>
<p>Telegram group: <a href="https://t.me/GrapheneOS">https://t.me/GrapheneOS</a>.</p>
<p>You can join the GrapheneOS Matrix space at
<a href="https://matrix.to/#/%23community:grapheneos.org">#community:grapheneos.org</a>
and can manually join each of the chat rooms from there.</p>
<p>The following 7 chat rooms are available across each platform, with the
Matrix links to each individual room included below:</p>
<table>
<tr>
<td><a href="https://matrix.to/#/%23general:grapheneos.org">#general:grapheneos.org</a></td>
<td>Best place to request support, ask questions or get involved in the project</td>
</tr>
<tr>
<td><a href="https://matrix.to/#/%23apps:grapheneos.org">#apps:grapheneos.org</a></td>
<td>Discuss using third party apps and services with GrapheneOS</td>
</tr>
<tr>
<td><a href="https://matrix.to/#/%23offtopic:grapheneos.org">#offtopic:grapheneos.org</a></td>
<td>Discuss topics not strictly related to GrapheneOS</td>
</tr>
<tr>
<td><a href="https://matrix.to/#/%23dev:grapheneos.org">#dev:grapheneos.org</a></td>
<td>Discuss GrapheneOS app and OS development</td>
</tr>
<tr>
<td><a href="https://matrix.to/#/%23testing:grapheneos.org">#testing:grapheneos.org</a></td>
<td>Provide feedback on Alpha and Beta channel app and OS releases</td>
</tr>
<tr>
<td><a href="https://matrix.to/#/%23releases:grapheneos.org">#releases:grapheneos.org</a></td>
<td>Release announcements</td>
</tr>
<tr>
<td><a href="https://matrix.to/#/%23infra:grapheneos.org">#infra:grapheneos.org</a></td>
<td>Infrastructure monitoring and discussion</td>
</tr>
<tr>
<td><a href="https://matrix.to/#/%23media:grapheneos.org">#media:grapheneos.org</a></td>
<td>Discuss GrapheneOS in news articles and other media coverage</td>
</tr>
</table>
<p>Matrix is a federated service similar to email where you can choose your
provider and has end-to-end encryption for private chats. Matrix can be a more
privacy friendly option but has significant downsides including lag, weak
moderation tools and the rooms needing to be regularly recreated due to bugs
in the protocol for reaching consensus on room state between servers.</p>
<p>The experience on Discord is the best out of all the available options
due to the way messages from the other platforms bridge to it, making
it much easier to read. Search is also generally better on Discord,
making it easier to look up information and previous discussions on
specific topics. Additionally, Discord allows you to select your preferred
release channels and devices via the roles feature in order to be
notified when an app or OS release in the channel you are interested in.</p>
<p>Telegram is a good option to choose if you already have a Telegram account
and use it. There is one Telegram group, which separates the different rooms via
topics.</p>
</section>
<section id="community-forum">
<h3><a href="#community-forum">Forum</a></h3>
<p>We have an official
<a href="https://discuss.grapheneos.org">forum</a> for longer form posts,
which is publicly accessible and easier to search. We are
using Flarum for our forum.</p>
</section>
</section>
<section id="contacting-the-project">
<h2><a href="#contacting-the-project">Contacting the project</a></h2>
<p>Do not contact us with offers to sell us products or services.</p>
<p>Please don't contact the GrapheneOS project or developers to request support /
device support / features or to report bugs. Use the <a href="#community">community
platforms</a> and <a href="#reporting-issues">issue trackers</a> listed below. The
developers are active on the Matrix room but the broader community can usually
answer most questions, and this allows the developers to focus their time and
energy on the project.</p>
<p>Email is the preferred way to contact the project. X direct messages are
checked much less frequently. A public @reply in a tweet is not a good way to contact
the project. It is not considered sending a message by X and is not queued up as
a message to be read, only as a regular notification that is likely to be missed or
forgotten.</p>
<p>Please do not send multiple copies / versions of the same email to different
addresses. Either send it to a single address or CC the other addresses. In general,
it's the same people handling every email address, and they don't need to see multiple
copies of the same email in their inbox.</p>
<p>You can contact <a href="mailto:contact@grapheneos.org">contact@grapheneos.org</a>
for topics related to GrapheneOS. Please don't send emails unrelated to GrapheneOS to
this address.</p>
<p>The <a href="mailto:security@grapheneos.org">security@grapheneos.org</a>
address is for reporting high priority security issues related to GrapheneOS. Please
don't send other kinds of emails to this address. It is not a way of increasing the
priority of emails that are not security reports. Your emails will be treated as a
much lower priority if you misuse this address.</p>
<p>The official X account for the project is <a
href="https://x.com/GrapheneOS">@GrapheneOS</a> which is used for official
announcements.</p>
<p>The official Mastodon account for the project is <a
href="https://grapheneos.social/@GrapheneOS">@GrapheneOS@grapheneos.social</a> which
is used for official announcements.</p>
<p>The official Bluesky account for the project is <a
href="https://bsky.app/profile/grapheneos.org">@grapheneos.org</a> which is used for
official announcements.</p>
</section>
<section id="hiring">
<h2><a href="#hiring">Hiring</a></h2>
<p>Interested in joining the GrapheneOS team? Check out our <a href="https://grapheneos.org/hiring">hiring page</a>.</p>
</section>
<section id="reporting-issues">
<h2><a href="#reporting-issues">Reporting issues</a></h2>
<p>Most issues should be reported to the global OS issue tracker for GrapheneOS
sub-projects. However, standalone projects and anything outside of the GrapheneOS
source tree (like the websites) has a dedicated issue tracker. The issue trackers are
listed for reference:</p>
<ul>
<li><a href="https://github.com/GrapheneOS/os-issue-tracker/issues">OS issue tracker</a> for all GrapheneOS repositories that are not standalone projects</li>
<li><a href="https://github.com/GrapheneOS/hardened_malloc/issues">hardened_malloc issue tracker</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_Updater/issues">Update client issue tracker</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_SetupWizard2/issues">Setup wizard issue tracker</a></li>
<li><a href="https://github.com/GrapheneOS/talkback/issues">Talkback issue tracker</a></li>
</ul>
<section id="standalone-apps">
<h3><a href="#standalone-apps">Standalone apps</a></h3>
<ul>
<li><a href="https://github.com/GrapheneOS/AppStore/issues">App Store issue tracker</a></li>
<li><a href="https://github.com/GrapheneOS/Auditor/issues">Auditor issue tracker</a></li>
<li><a href="https://github.com/GrapheneOS/Camera/issues">Camera app issue tracker</a></li>
<li><a href="https://github.com/GrapheneOS/Messaging/issues">Messaging app issue tracker</a></li>
<li><a href="https://github.com/GrapheneOS/PdfViewer/issues">PDF Viewer issue tracker</a></li>
<li><a href="https://github.com/GrapheneOS/Vanadium/issues">Vanadium (Chromium variant) issue tracker</a></li>
</ul>
</section>
<section id="services">
<h3><a href="#services">Services</a></h3>
<ul>
<li><a href="https://github.com/GrapheneOS/infrastructure/issues">Server infrastructure issue tracker (for issues applying across services)</a></li>
<li><a href="https://github.com/GrapheneOS/AttestationServer/issues">AttestationServer (attestation.app) issue tracker</a></li>
<li><a href="https://github.com/GrapheneOS/grapheneos.org/issues">GrapheneOS site (grapheneos.org) issue tracker</a></li>
<li><a href="https://github.com/GrapheneOS/releases.grapheneos.org/issues">Update server (releases.grapheneos.org) issue tracker</a></li>
<li><a href="https://github.com/GrapheneOS/grapheneos.network/issues">Connectivity check / time server (grapheneos.network) issue tracker</a></li>
<li><a href="https://github.com/GrapheneOS/mail.grapheneos.org/issues">Mail server (mail.grapheneos.org) issue tracker</a></li>
<li><a href="https://github.com/GrapheneOS/apps.grapheneos.org/issues">App repository (apps.grapheneos.org) issue tracker</a></li>
<li><a href="https://github.com/GrapheneOS/matrix.grapheneos.org/issues">GrapheneOS Matrix server (matrix.grapheneos.org) issue tracker</a></li>
<li><a href="https://github.com/GrapheneOS/discuss.grapheneos.org/issues">GrapheneOS discussion forum (discuss.grapheneos.org) issue tracker</a></li>
</ul>
</section>
</section>
<p>Hakurei maintainers are reachable via <a href="mailto:hakurei@gensokyo.uk">hakurei@gensokyo.uk</a>.
You may request for an account on the <a href="https://git.gensokyo.uk/" target="_blank">Gensokyo Gitea</a>
instance. Otherwise, contributions via email are welcome as well.</p>
</main>
{% include "footer.html" %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"@id": "https://grapheneos.org/#organization",
"name": "GrapheneOS",
"description": "GrapheneOS is an open source project focused on mobile privacy and security.",
"url": "https://grapheneos.org/",
"logo": "https://grapheneos.org/logo.png",
"email": "contact@grapheneos.org",
"sameAs": [
"https://discuss.grapheneos.org/u/GrapheneOS",
"https://x.com/GrapheneOS",
"https://grapheneos.social/@GrapheneOS",
"https://bsky.app/profile/grapheneos.org",
"https://cohost.org/GrapheneOS",
"https://github.com/GrapheneOS",
"https://reddit.com/u/GrapheneOS",
"https://discord.com/invite/grapheneos",
"https://discord.com/servers/grapheneos-private-and-secure-mobile-os-1176414688112820234",
"https://t.me/GrapheneOS",
"https://www.linkedin.com/company/grapheneos/",
"https://www.facebook.com/GrapheneOS",
"https://www.instagram.com/grapheneos/",
"https://www.threads.net/@grapheneos",
"https://www.youtube.com/channel/UCoZjKwzqhlir_vWeZwvl8CQ",
"https://www.youtube.com/@GrapheneOS",
"https://g.page/r/CeQbRTxotybUEAE",
"https://linktr.ee/grapheneos",
"https://en.wikipedia.org/wiki/GrapheneOS",
"https://www.wikidata.org/wiki/Q85764357"
],
"foundingDate": "2014"
}
</script>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 419 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 372 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 483 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 373 B

View File

@ -1,422 +0,0 @@
<!DOCTYPE html>
<html lang="en" prefix="og: https://ogp.me/ns#">
<head>
<meta charset="utf-8"/>
<title>Donate | GrapheneOS</title>
<meta name="description" content="Donating to support development of GrapheneOS."/>
<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, viewport-fit=cover"/>
<meta name="twitter:site" content="@GrapheneOS"/>
<meta name="twitter:creator" content="@GrapheneOS"/>
<meta property="og:title" content="GrapheneOS donations"/>
<meta property="og:description" content="Donating to support development of GrapheneOS."/>
<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/donate"/>
<link rel="canonical" href="https://grapheneos.org/donate"/>
<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"/>
</head>
<body>
{% with current_page="donate" %}
{% include "header.html" %}
{% endwith %}
<main id="donate">
<h1><a href="#donate">Donate</a></h1>
<p>GrapheneOS is an open source project supported via donations from individuals,
companies and other organizations. Donations are used for paying developers,
purchasing hardware (workstations, test devices, debugging cables/boards, etc.),
paying for infrastructure (domains, virtual/dedicated servers) and paying legal
fees.</p>
<p>The multiple ways to donate are listed in the sections on this page.</p>
<nav id="table-of-contents">
<h2><a href="#table-of-contents">Table of contents</a></h2>
<ul>
<li><a href="#github">GitHub Sponsors (credit card)</a></li>
<li><a href="#bitcoin">Bitcoin</a></li>
<li><a href="#monero">Monero</a></li>
<li><a href="#zcash">Zcash</a></li>
<li><a href="#ethereum">Ethereum</a></li>
<li><a href="#cardano">Cardano</a></li>
<li><a href="#litecoin">Litecoin</a></li>
<li><a href="#wise">Local Bank Transfer to Wise</a></li>
<li><a href="#paypal">PayPal</a></li>
<li><a href="#e-transfer">Interac e-Transfer</a></li>
</ul>
</nav>
<section id="github">
<h2><a href="#github">GitHub Sponsors (credit card)</a></h2>
<p>GrapheneOS can be sponsored with recurring or one-time donations via credit
cards through <a href="https://github.com/sponsors/thestinger">GitHub
Sponsors</a>. There are standard tiers from $5 to $5,000 or you can donate a custom
amount.</p>
</section>
<section id="bitcoin">
<h2><a href="#bitcoin">Bitcoin</a></h2>
<p>Bitcoin can be used to make donations to the non-profit GrapheneOS
Foundation.</p>
<p>You can send Bitcoin donations to the following Bech32 (Segwit) address:</p>
<div class="coin-address">
<a href="bitcoin:bc1q9qw3g8tdxf3dugkv2z8cahd3axehph0mhsqk96?label=GrapheneOS%20Foundation&amp;message=Donation%20to%20GrapheneOS%20Foundation" rel="nofollow">
<img src="/donate-bitcoin.png?1" alt="Bitcoin donation QR code"/>
<p>bc1q9qw3g8tdxf3dugkv2z8cahd3axehph0mhsqk96</p>
</a>
</div>
<p>Alternatively, you can donate to the following Bech32m (Taproot) address if
your wallet supports it (preferred):</p>
<div class="coin-address">
<a href="bitcoin:bc1prqf5hks5dnd4j87wxw3djn20559yhj7wvvcv6fqxpwlg96udkzgqtamhry?label=GrapheneOS%20Foundation&amp;message=Donation%20to%20GrapheneOS%20Foundation" rel="nofollow">
<img src="/donate-bitcoin-taproot.png?1" alt="Bitcoin Taproot donation QR code"/>
<p>bc1prqf5hks5dnd4j87wxw3djn20559yhj7wvvcv6fqxpwlg96udkzgqtamhry</p>
</a>
</div>
<p>You can donate to the following BIP47 payment code (stealth address) or PayNym
if your wallet supports it:</p>
<div class="coin-address">
<a href="bitcoin:PM8TJKmhJNQX6UTFagyuBk8UGmwKM6yDovEokpHBscPgP3Ac7WdK5zaQKh5XLSawyxiGYZS2a7HkAoeL6oHg7Ahn1VXX888yRG4PwF1dojouPtW7tEHT" rel="nofollow">
<img src="/donate-bitcoin-bip47.png" alt="Bitcoin BIP47 payment code QR code"/>
<p>PM8TJKmhJNQX6UTFagyuBk8UGmwKM6yDovEokpHBscPgP3Ac7WdK5zaQKh5XLSawyxiGYZS2a7HkAoeL6oHg7Ahn1VXX888yRG4PwF1dojouPtW7tEHT</p>
</a>
</div>
<p>PayNym: <var>+GrapheneOS</var></p>
</section>
<section id="monero">
<h2><a href="#monero">Monero</a></h2>
<p>Monero can be used to make donations to the non-profit GrapheneOS
Foundation.</p>
<p>You can send Monero donations to the following address:</p>
<div class="coin-address">
<a href="monero:862CebHaBpFPgYoNC6zw4U8rsXrDjD8s5LMJNS7yVCRHMUKr9dDi7adMSLUMjkDYJ85xahQTCJHHyK5RCvvRJu9x7iSzN9D?recipient_name=GrapheneOS%20Foundation&amp;tx_description=Donation%20to%20GrapheneOS%20Foundation" rel="nofollow">
<img src="/donate-monero.png?1" alt="Monero donation QR code"/>
<p>862CebHaBpFPgYoNC6zw4U8rsXrDjD8s5LMJNS7yVCRHMUKr9dDi7adMSLUMjkDYJ85xahQTCJHHyK5RCvvRJu9x7iSzN9D</p>
</a>
</div>
</section>
<section id="zcash">
<h2><a href="#zcash">Zcash</a></h2>
<p>Zcash can be used to make donations to the non-profit GrapheneOS
Foundation.</p>
<p>You can send Zcash donations to the following transparent address:</p>
<div class="coin-address">
<a href="zcash:t1SJABjX8rqgzqgrzLW5dUw7ikSDZ2snD8A?label=GrapheneOS%20Foundation&amp;message=Donation%20to%20GrapheneOS%20Foundation" rel="nofollow">
<img src="/donate-zcash-transparent.png?1" alt="Transparent Zcash donation QR code"/>
<p>t1SJABjX8rqgzqgrzLW5dUw7ikSDZ2snD8A</p>
</a>
</div>
</section>
<section id="ethereum">
<h2><a href="#ethereum">Ethereum</a></h2>
<p>Ethereum can be used to make donations to the non-profit GrapheneOS
Foundation.</p>
<p>You can send Ethereum donations to the following address:</p>
<div class="coin-address">
<a href="ethereum:0xC822A62E5Ab443E0001f30cEB9B2336D0524fC61" rel="nofollow">
<img src="/donate-ethereum.png?1" alt="Ethereum donation QR code"/>
<p>0xC822A62E5Ab443E0001f30cEB9B2336D0524fC61</p>
</a>
</div>
<p><strong>We aren't looking for donations of tokens, only Ethereum itself.</strong></p>
</section>
<section id="cardano">
<h2><a href="#cardano">Cardano</a></h2>
<p>Cardano can be used to make donations to the non-profit GrapheneOS
Foundation.</p>
<p>You can send Cardano donations to the following address:</p>
<div class="coin-address">
<a href="web+cardano:addr1q9v89vfwyfssveug5zf2w7leafz8ethq490gvq0ghag883atfnucytpnq2t38dj7cnyngs6ne05cdwu9gseevgmt3ggq2a2wt6" rel="nofollow">
<img src="/donate-cardano.png?1" alt="Cardano donation QR code"/>
<p>addr1q9v89vfwyfssveug5zf2w7leafz8ethq490gvq0ghag883atfnucytpnq2t38dj7cnyngs6ne05cdwu9gseevgmt3ggq2a2wt6</p>
</a>
</div>
<p>We own the <var>$grapheneos</var> handle with this address so you can also send to the handle.</p>
<p><strong>We aren't looking for donations of tokens, only Cardano itself.</strong></p>
</section>
<section id="litecoin">
<h2><a href="#litecoin">Litecoin</a></h2>
<p>Litecoin can be used to make donations to the non-profit GrapheneOS
Foundation.</p>
<p>You can send Litecoin donations to the following Bech32 (Segwit) address:</p>
<div class="coin-address">
<a href="litecoin:ltc1qzssmqueth6zjzr95rkluy5xdx9q4lk8vyrvea9?label=GrapheneOS%20Foundation&amp;message=Donation%20to%20GrapheneOS%20Foundation" rel="nofollow">
<img src="/donate-litecoin.png" alt="Litecoin donation QR code"/>
<p>ltc1qzssmqueth6zjzr95rkluy5xdx9q4lk8vyrvea9</p>
</a>
</div>
</section>
<section id="wise">
<h2><a href="#wise">Local Bank Transfer to Wise</a></h2>
<p>You can donate to the non-profit GrapheneOS Foundation via local bank transfers
to our Wise account in the EU/SEPA, UK, US, Australia, New Zealand, Canada,
Hungary and Turkey.</p>
<section id="wise-sepa">
<h2><a href="#wise-sepa">EU/SEPA (EUR)</a></h2>
<dl>
<dt>Account holder</dt>
<dd>GrapheneOS Foundation</dd>
<dt>IBAN</dt>
<dd>BE20 9677 1140 7056</dd>
<dt>BIC</dt>
<dd>TRWIBEB1XXX</dd>
<dt>Bank name</dt>
<dd>Wise Europe SA</dd>
<dt>Wise and Bank address</dt>
<dd>Rue du Trône 100, 3rd floor<br/>Brussels<br/>1050<br/>Belgium</dd>
</dl>
</section>
<section id="wise-uk">
<h2><a href="#wise-uk">UK (GBP)</a></h2>
<dl>
<dt>Account holder</dt>
<dd>GrapheneOS Foundation</dd>
<dt>Account number</dt>
<dd>49883070</dd>
<dt>IBAN</dt>
<dd>GB68 TRWI 2314 7049 8830 70</dd>
<dt>Sort code</dt>
<dd>23-14-70</dd>
<dt>Bank name</dt>
<dd>Wise Payments Limited</dd>
<dt>Wise and Bank address</dt>
<dd>56 Shoreditch High Street<br/>London<br/>E1 6JJ<br/>United Kingdom</dd>
</dl>
</section>
<section id="wise-us">
<h2><a href="#wise-us">US (USD)</a></h2>
<dl>
<dt>Account holder</dt>
<dd>GrapheneOS Foundation</dd>
<dt>Account number</dt>
<dd>8313560023</dd>
<dt>Routing number</dt>
<dd>026073150</dd>
<dt>Account type</dt>
<dd>Checking</dd>
<dt>Wise address</dt>
<dd>30 W. 26th Street, Sixth Floor<br/>New York NY<br/>10010<br/>United States</dd>
<dt>Bank name</dt>
<dd>Community Federal Savings Bank</dd>
<dt>Bank address</dt>
<dd>89-16 Jamaica Ave<br/>Woodhaven NY<br/>11421<br/>United States</dd>
</dl>
</section>
<section id="wise-australia">
<h2><a href="#wise-australia">Australia (AUD)</a></h2>
<dl>
<dt>Account holder</dt>
<dd>GrapheneOS Foundation</dd>
<dt>Account number</dt>
<dd>213524417</dd>
<dt>BSB code</dt>
<dd>774-001</dd>
<dt>Bank name</dt>
<dd>Wise Australia Pty Ltd</dd>
<dt>Wise address</dt>
<dd>Suite 1, Level 11, 66 Goulburn Street<br/>Sydney<br/>2000<br/>Australia</dd>
</dl>
</section>
<section id="wise-new-zealand">
<h2><a href="#wise-new-zealand">New Zealand (NZD)</a></h2>
<dl>
<dt>Account holder</dt>
<dd>GrapheneOS Foundation</dd>
<dt>Account number</dt>
<dd>04-2021-0151878-36</dd>
<dt>Wise address</dt>
<dd>56 Shoreditch High Street<br/>London<br/>E1 6JJ<br/>United Kingdom</dd>
<dt>Bank name</dt>
<dd>JPMorgan Chase</dd>
<dt>Bank address</dt>
<dd>Head Office, Pwc Tower<br/>Auckland<br/>1010<br/>New Zealand</dd>
</dl>
</section>
<section id="wise-canada">
<h2><a href="#wise-canada">Canada (CAD)</a></h2>
<dl>
<dt>Account holder</dt>
<dd>GrapheneOS Foundation</dd>
<dt>Account number</dt>
<dd>200110745303</dd>
<dt>Transit number</dt>
<dd>16001</dd>
<dt>Institution number</dt>
<dd>621</dd>
<dt>Wise address</dt>
<dd>99 Bank Street, Suite 1420<br/>Ottawa ON<br/>K1P 1H4<br/>Canada</dd>
<dt>Bank name</dt>
<dd>Peoples Trust</dd>
<dt>Bank address</dt>
<dd>595 Burrard Street<br/>Vancouver BC<br/>V7X 1L7<br/>Canada</dd>
</dl>
</section>
<section id="wise-hungary">
<h2><a href="#wise-hungary">Hungary (HUF)</a></h2>
<dl>
<dt>Account holder</dt>
<dd>GrapheneOS Foundation</dd>
<dt>Account number</dt>
<dd>12600016-11020392-99827322</dd>
<dt>Bank name</dt>
<dd>Wise Europe SA</dd>
<dt>Wise and Bank address</dt>
<dd>Rue du Trône 100, 3rd floor<br/>Brussels<br/>1050<br/>Belgium</dd>
</dl>
</section>
<section id="wise-turkey">
<h2><a href="#wise-turkey">Turkey (TRY)</a></h2>
<dl>
<dt>Account holder</dt>
<dd>GrapheneOS Foundation</dd>
<dt>IBAN</dt>
<dd>TR43 0010 3000 0000 0057 4294 70</dd>
<dt>Wise address</dt>
<dd>56 Shoreditch High Street, London, E1 6JJ, United Kingdom</dd>
<dt>Bank name</dt>
<dd>Fibabanka A.Ş.</dd>
<dt>Bank address</dt>
<dd>Büyükdere Cad. 129<br/>Esentepe Mah.<br/>Sisli<br/>Istanbul<br/>Turkey</dd>
</dl>
</section>
</section>
<section id="paypal">
<h2><a href="#paypal">PayPal</a></h2>
<p>PayPal can be used to make one-time, monthly or yearly donations to the
non-profit GrapheneOS Foundation.</p>
<p>If possible, use the donation link for your currency. If it's not listed,
please use the CAD donation link.</p>
<p>Donation links:</p>
<ul>
<li><a href="https://www.paypal.com/donate/?hosted_button_id=T8KRPYKU5QVNE">Canadian dollar (CAD)</a></li>
<li><a href="https://www.paypal.com/donate/?hosted_button_id=2S2BP8V4E7PXU">United States dollar (USD)</a></li>
<li><a href="https://www.paypal.com/donate/?hosted_button_id=5SNPWEDS53HW4">Euro (EUR)</a></li>
<li><a href="https://www.paypal.com/donate/?hosted_button_id=N498QNB7NPKU8">British pound (GBP)</a></li>
</ul>
<p>PayPal charges a base fee of 30 cents and 2.9% of the donation amount within
Canada. There's an additional 0.8% fee for donations from the US and 1% for other
countries. Currency conversion adds an additional 4% fee as opposed to the usual
PayPal conversion fee of 3%.</p>
</section>
<section id="e-transfer">
<h2><a href="#e-transfer">Interac e-Transfer</a></h2>
<p>If you have a Canadian bank account, you can send Canadian dollar donations to
the non-profit GrapheneOS Foundation via Interac e-Transfer to
<var>contact@grapheneos.org</var>. The email address has Interac e-Transfer
Autodeposit support enabled so no security question is necessary. If your bank
doesn't support Autodeposit, set the answer to the security question to
GrapheneOS.</p>
</section>
</main>
{% include "footer.html" %}
</body>
</html>

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because it is too large Load Diff

View File

@ -1,86 +0,0 @@
<!DOCTYPE html>
<html lang="en" prefix="og: https://ogp.me/ns#">
<head>
<meta charset="utf-8"/>
<title>Hiring | GrapheneOS</title>
<meta name="description" content="GrapheneOS job opportunities."/>
<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, viewport-fit=cover"/>
<meta name="twitter:site" content="@GrapheneOS"/>
<meta name="twitter:creator" content="@GrapheneOS"/>
<meta property="og:title" content="GrapheneOS Hiring"/>
<meta property="og:description" content="GrapheneOS job opportunities."/>
<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/hiring"/>
<link rel="canonical" href="https://grapheneos.org/hiring"/>
<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"/>
</head>
<body>
{% with current_page="hiring" %}
{% include "header.html" %}
{% endwith %}
<main id="hiring">
<h1><a href="#hiring">GrapheneOS Remote Developer</a></h1>
<p><strong>Location:</strong> Remote</p>
<p><strong>Position Type:</strong> Independent Contractor</p>
<p>We are seeking a highly skilled and self-directed developer to contribute to our open source project, someone who shares our passion for enhancing the privacy and security of mobile devices. The ideal candidate will have experience working with Android-based operating systems, the Linux kernel and its hardening, memory allocators, or extensive experience in Android app development. In this role, you will play a key role in the development and maintenance of our <a href="https://github.com/GrapheneOS">existing projects</a>, and will be expected to commit a minimum of 80 hours per month. The role will require a high level of autonomy and the ability to independently manage workloads.</p>
<section id="responsibilities">
<h2><a href="#responsibilities">Responsibilities</a></h2>
<ul>
<li>Manage a specific aspect of the project, such as the kernel, memory allocator, custom OS features, or apps like Vanadium, Auditor, Camera, PDFViewer. Your time will be spent improving them, porting them to new Android versions, reviewing code contributions etc.</li>
<li>Adhere to our development guidelines, available <a href="https://grapheneos.org/build#development-guidelines">here</a></li>
<li>Collaborate with the development team to address bugs, vulnerabilities, and performance issues</li>
</ul>
</section>
<section id="qualifications">
<h2><a href="#qualifications">Qualifications</a></h2>
<ul>
<li>Prior experience working on one or more of Android/AOSP-based operating systems, the Linux kernel and its hardening, memory allocators, or Android app development</li>
<li>Strong programming skills in relevant languages (in order from most to least common: Java, Kotlin, C++, C, Rust, JavaScript, TypeScript, arm64 assembly, Bash, Python)</li>
<li>Need to have enough experience to be comfortable to self direct workloads and submit finished features and fixes ready for review</li>
<li>Commitment to privacy and security principles</li>
<li>Ideally prior experience contributing to free and open source projects</li>
</ul>
</section>
<section id="time">
<h2><a href="#time">Time Commitment</a></h2>
<p>Must be able to commit to spending 80 hours or more a month, but we are extremely flexible about how you want to structure your working times. There is, however, a significant workload porting GrapheneOS forward when each new Android version is released. Having the capacity to focus and/or increase work hours during these periods is a great advantage.</p>
</section>
<section id="salary">
<h2><a href="#salary">Salary</a></h2>
<p>Salary and remuneration will be commensurate with experience and aligned with industry standards. You will be employed as an independent contractor.</p>
</section>
<section id="about">
<h2><a href="#about">About GrapheneOS</a></h2>
<p>GrapheneOS is a privacy and security-focused mobile OS with Android app compatibility developed as a non-profit open source project. It's focused on the research and development of privacy and security technology, including substantial improvements to sandboxing, exploit mitigations, and the permission model. It was founded in 2014 and was formerly known as CopperheadOS. In 2023, the GrapheneOS Foundation was established as a non-profit to help steward development over the long term.</p>
</section>
<section id="apply">
<h2><a href="#apply">How to Apply</a></h2>
<p>Send an email to <a href="mailto:hiring@grapheneos.org">hiring@grapheneos.org</a> with a description of your background and explain why you are interested in GrapheneOS. Additionally, please share any examples of relevant work or FOSS contributions.</p>
</section>
</main>
{% include "footer.html" %}
</body>
</html>

View File

@ -1,112 +0,0 @@
<!DOCTYPE html>
<html lang="en" prefix="og: https://ogp.me/ns#">
<head>
<meta charset="utf-8"/>
<title>CopperheadOS | History | GrapheneOS</title>
<meta name="description" content="GrapheneOS was previously known as CopperheadOS. It's the continuation of the original open source project."/>
<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, viewport-fit=cover"/>
<meta name="twitter:site" content="@GrapheneOS"/>
<meta name="twitter:creator" content="@GrapheneOS"/>
<meta property="og:title" content="CopperheadOS is now GrapheneOS"/>
<meta property="og:description" content="GrapheneOS was previously known as CopperheadOS. It's the continuation of the original open source project."/>
<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/history/copperheados"/>
<link rel="canonical" href="https://grapheneos.org/history/copperheados"/>
<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"/>
</head>
<body>
{% include "header.html" %}
<main id="copperheados">
<h1><a href="#copperheados">CopperheadOS is now GrapheneOS</a></h1>
<p>CopperheadOS was renamed to GrapheneOS in 2019. It was temporarily known as the
Android Hardening project in 2018 before a permanent name had been chosen. For more
details on why the project was renamed, see <a href="/history/">our history page</a>.
For the historical release notes of the original CopperheadOS, see
<a href="/history/legacy-changelog">our legacy changelog page</a>. The
<a href="https://reddit.com/r/CopperheadOS">/r/CopperheadOS subreddit</a> was
historically the central hub of the community along with a bridged IRC/Matrix channel
that's no longer available.</p>
<p>GrapheneOS is the continuation of the original open source project by the original
development team. Our <a href="/source">source code repositories</a> have been used
since CopperheadOS transitioned to being directly based on the Android Open Source
Project in 2015. The prior repositories predate the CopperheadOS branding and were
also owned by us. It can be confirmed that our repositories are the original ones from
the GitHub network graphs showing the forks over the years.</p>
<section id="ownership">
<h2><a href="#ownership">Ownership</a></h2>
<p>We own the historical CopperheadOS source code, documentation and accounts tied
to the open source project. Our legacy Twitter account still needs to be returned
to us so that it can be renamed and made into an archive.</p>
<p>Copperhead has no valid claim over the ownership of the source code. It was not
developed for them. They were involved as a sponsor for the work and had
permission to sell products based on it, similar to companies selling devices with
GrapheneOS. We've learned a lot of lessons from what happened and are being very
careful to avoid being strongly associated with any particular company in the
future.</p>
</section>
<section id="new-product">
<h2><a href="#new-product">New closed source product reusing the legacy branding</a></h2>
<p>The new product branded as CopperheadOS is closed source and not associated with
the original project. They took our project's previous name and copied our legacy
source code and documentation. Attribution to us has been stripped away and they
pretend to be the ones who created it.</p>
<p>They've essentially stolen the identity of our open source project and have
invested substantial resources into misrepresenting GrapheneOS as being a new
project. They've built a business based on taking credit for research and
development not done by them. Substantial damage has been done to GrapheneOS
through an organized campaign of misinformation and harassment.</p>
</section>
<section id="new-copperheados-vs-grapheneos">
<h2><a href="#new-copperheados-vs-grapheneos">New CopperheadOS vs. GrapheneOS</a></h2>
<p>The new CopperheadOS is a shadow of the historical GrapheneOS code. They've
continued copying portions of our newer generation code but haven't developed any
significant privacy or security improvements on their own. It's a poor imitation
of the original. It has a fraction of the privacy and security improvements and
lacks a team with an understanding of how they work. It often doesn't receive
timely security updates. It has made serious mistakes compromising user privacy
and security.</p>
<p>CopperheadOS is a paid product and has license enforcement compromising user
privacy and security through tracking devices to implement DRM. They use the
outrageous business model of charging users for security updates rather than
simply selling them the software or devices with it.</p>
<p>GrapheneOS devices can be purchased from a bunch of different companies,
organizations and individuals. Many of these offer customer support. Unlike
CopperheadOS, it's still open source software and you aren't being charged to
simply get the OS updates. Anyone can sell devices with GrapheneOS without
permission from the project due the open source licensing. Many of these sellers
voluntarily contribute back to the project.</p>
<p>GrapheneOS is far more actively developed than the new CopperheadOS and has
substantially more resources available, including significantly more funding.</p>
</section>
</main>
{% include "footer.html" %}
</body>
</html>

View File

@ -1,99 +0,0 @@
<!DOCTYPE html>
<html lang="en" prefix="og: https://ogp.me/ns#">
<head>
<meta charset="utf-8"/>
<title>History | GrapheneOS</title>
<meta name="description" content="History of the GrapheneOS project."/>
<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, viewport-fit=cover"/>
<meta name="twitter:site" content="@GrapheneOS"/>
<meta name="twitter:creator" content="@GrapheneOS"/>
<meta property="og:title" content="GrapheneOS history"/>
<meta property="og:description" content="History of the GrapheneOS project."/>
<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/history/"/>
<link rel="canonical" href="https://grapheneos.org/history/"/>
<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"/>
</head>
<body>
{% with current_page="history" %}
{% include "header.html" %}
{% endwith %}
<main id="history">
<h1><a href="#history">History</a></h1>
<p>GrapheneOS was founded by Daniel Micay in late 2014. It started as a solo project
incorporating his previous open source privacy/security work. The project initially
created a port of OpenBSD malloc to Android's Bionic libc and a port of the PaX kernel
patches to the kernels for the supported devices. It quickly expanded to having a
large set of homegrown privacy and security improvements, particularly low-level
hardening work on the compiler toolchain and Bionic. Work began on landing code
upstream in AOSP and other upstream projects. A substantial portion of these early
changes were either successfully landed upstream or heavily influenced the upstream
changes which replaced them. The project was able to move very quickly in these days
because there was so much low hanging fruit to address and it wasn't yet trying to
produce a highly robust, production quality OS.</p>
<p>In late 2015, a company was incorporated which became the primary sponsor of the
project. GrapheneOS was <a href="/history/copperheados">previously known as
CopperheadOS</a> while it was sponsored by this company. The intention was to use the
company to build a business around GrapheneOS selling support, contract work and
customized proprietary variants of the OS. The company was supposed to serve the needs
of the open source project, rather than vice versa. It was explicitly agreed that
GrapheneOS would remain independently owned and controlled by Daniel Micay. This
company failed to live up the promises and is no longer associated in any way with
GrapheneOS. The company ended up holding back the open source project and taking far
more from it than was provided to it.</p>
<p>In 2018, the company was hijacked by the CEO who attempted to take over the project
through coercion, but they were rebuked. They seized the infrastructure and stole the
donations, but the project successfully moved on without them and has been fully
revived. Since then, they've taken to fraudulently claiming ownership and authorship
of our work, which has no basis in fact. They've tried to retroactively change the
terms of their involvement and rewrite the history of the project. These claims are
easily disproven through the public record and by people involved with the open source
project and the former sponsor. This former sponsor has engaged in a campaign of
misinformation and harassment of contributors to the project. Be aware that they are
actively trying to sabotage GrapheneOS and are engaging in many forms of attacks
against the project, the developers, contributors and supporters. Meanwhile, they
continue profiting from our open source work which they falsely claim as their own
creation.</p>
<p>After splitting from the former sponsor, the project was rebranded to
AndroidHardening and then to GrapheneOS and it has continued down the original path of
being an independent open source project. It will never again be closely tied to any
particular sponsor or company.</p>
<p>GrapheneOS now has multiple full-time and part-time developers supported by
donations and multiple companies collaborating with the project.</p>
<p>GrapheneOS Foundation was created as a non-profit organization in Canada in March
2023 to handle the intake and distribution of donations.</p>
<section id="releases">
<h2><a href="#releases">Releases</a></h2>
<p>A history of releases for the current incarnation of GrapheneOS is available
via the <a href="/releases#changelog">releases changelog</a>.</p>
<p>An archive of changelogs for the earlier releases is available via the
<a href="/history/legacy-changelog">legacy changelog page</a>.</p>
</section>
</main>
{% include "footer.html" %}
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -1,60 +1,60 @@
0N:
0N:
0N:
0N:
0N:
0N:
.;KNx,.
.lKNNNNNNNO;
.KNNNNNNNNNNNx
xNNNNNNNNNNNNN,
xNNNNNNNNNNNNN'
.:ONNNNNNNNNNNNNd,
dl' ,o0N0o,cONNNNNNXx;:xKXkc. .;oc
.lONXx:. .ckXXk:. .';;,. 'l0NKd;. 'lONXx:
.;o0NOl' 'okKXK0xc. .;dKXOl' .;dKNOl' 'okKXK0xc. .;dKXkl'
.cOXX0NNNNNNNNNN0NKd;. .ckNX0NNNNNNNNNN0NXx;
.XNNNNNNNNNNNNO .NNNNNNNNNNNNNk
'NNNNNNNNNNNNNK 'NNNNNNNNNNNNNK
KNNNNNNNNNNNNo KNNNNNNNNNNNNo
.xNNNNNNNNNXc .xNNNNNNNNNXl
.cxKNXOd; .cx0NNOd;
dNx NN.
dNx NN.
dNx NN.
dNx NN.
dNx NN.
dNx NN.
dNx NN.
dNx NN.
'oOXNX0xc. 'oOKNNKkc.
.ONNNNNNNNNXo .ONNNNNNNNNXo
KNNNNNNNNNNNNd KNNNNNNNNNNNNd
'NNNNNNNNNNNNNK 'NNNNNNNNNNNNNK
.XNNNNNNNNNNNNO 'NNNNNNNNNNNNNO.
'o0NKONNNNNNNNNXkXXkc. 'l0NKONNNNNNNNNXkXXOc.
.:xXXx:. .cxO00kd; ,o0N0d;. .cxXXkc. .cxO00ko; 'lON0o;.
.dKN0o, .;xKN0l. .;cc:,. ;dKN0o, .:xXNOl
l:. .ckXKx:oKNNNNNNNO:lkXKd;. 'l:
;kNNNNNNNNNNNNNl'
xNNNNNNNNNNNNN,
xNNNNNNNNNNNNN,
.0NNNNNNNNNNNd
cONNNNNNXx,
.'KNd.
0N:
0N:
0N:
0N:
0N:
0N:
..::::: . .
-=*%@@@@@@@@#=:--
:@@@@@@@@@@@@@@#-::
.*%@@@@@@@@@@@@@@@@#=
:-%@@@@@@@@@@@@@@@#
=@@@@@@@@@@@@@@@%+ .:-=+=-.
-+#@@@@@@@@@@@@@@@@@*-..-=======---=:
:#@@@@@@@@@@@@@@@@@@@@@@@%+-: .:*@.
*#@@@@@@@@@@@@@@@@@@@@@@@%*+%@**%%@%%@@@*-
-@@@@@@@@@@@@@@@@@@@@@@@@@@%%@*-=+##%@=.-%%=.
+@@@@@@@@@@@@@@@@@@@@@@@@@@#=@@*: :#@#: -%@*.
:#@@@@@@@@@@@@@@@@@@@@@@@@@@@@#%%@@+ :@@- #@@*
=@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%*@#-#@%. :@+:**%*:
=@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#+@@@@@@..@#@=::.
=%@#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* #@@+-
*@#*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%=-#@=
=@@@%*#%@@@@@@@@@@@@@@@@@@@@@@#@@@==@@@: .%*
.%@@@% %@@@@@@@@@@@@@@@@@@@@%%*-#%++@@+ .:=:
*%@@@###@@@@@@@@@@@@@@@@@@@@%@#*%%*--
.#-.#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%#**=-.
%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%*-
.#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#-
.+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#+-:..:==
:*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%#-
.+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
=@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#
.@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#
.@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%
-@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%+.
*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%=
.#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+=:
+%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%#%@++##--=-.
-%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#**
.@@@@@@@@@@@@@@@@@@@@@@@@@@@%##
...+@@@@@@@@@@@@@@@@@@@@@@@@@@@#
.#@@@@@@@@@@@@@@@@@@@@@@@@@@@+--
.=%@@@%##@@@@@@@@@@@@#*-=-..
-: :*##@@@@@@@:
*@@@@@@
=@@@@@%
.@@@@@+
.@@@@@=
:@@@@@=
+@@@@@*
.@@@@@@@-
*@@@@@@@%
.-==-==-
GrapheneOS is a collaboratively developed open source project.
Hakurei is a collaboratively developed open source project.
See the repositories at https://github.com/GrapheneOS for more details.
See the repositories at https://git.gensokyo.uk/security for more details.
This website is developed in the https://github.com/GrapheneOS/grapheneos.org repository.
This website is developed in the https://git.gensokyo.uk/security/hakurei.app repository.

View File

@ -2,24 +2,24 @@
<html lang="en" prefix="og: https://ogp.me/ns#">
<head>
<meta charset="utf-8"/>
<title>GrapheneOS: the private and secure mobile OS</title>
<meta name="description" content="GrapheneOS is a security and privacy focused mobile OS with Android app compatibility."/>
<title>Hakurei: the secure desktop application sandbox</title>
<meta name="description" content="Hakurei is a security-focused Linux container runtime for desktop applications."/>
<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, viewport-fit=cover"/>
<meta name="twitter:site" content="@GrapheneOS"/>
<meta name="twitter:creator" content="@GrapheneOS"/>
<meta property="og:title" content="GrapheneOS: the private and secure mobile OS"/>
<meta property="og:description" content="GrapheneOS is a security and privacy focused mobile OS with Android app compatibility."/>
<meta name="go-import" content="hakurei.app git https://git.gensokyo.uk/security/hakurei"/>
<meta name="go-source" content="hakurei.app _ https://git.gensokyo.uk/security/hakurei/src/branch/master{/dir} https://git.gensokyo.uk/security/hakurei/src/branch/master{/dir}/{file}#L{line}"/>
<meta property="og:title" content="Hakurei: the secure desktop application sandbox"/>
<meta property="og:description" content="Hakurei is a security-focused Linux container runtime for desktop applications."/>
<meta property="og:type" content="website"/>
<meta property="og:image" content="https://grapheneos.org/opengraph.png"/>
<meta property="og:image" content="https://hakurei.app/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/"/>
<link rel="canonical" href="https://grapheneos.org/"/>
<meta property="og:image:alt" content="Hakurei logo"/>
<meta property="og:site_name" content="Hakurei"/>
<meta property="og:url" content="https://hakurei.app/"/>
<link rel="canonical" href="https://hakurei.app/"/>
<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"/>
@ -27,33 +27,32 @@
[[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]]
<link rel="me" href="https://port.mk/@hakurei"/>
</head>
<body>
{% with current_page="/" %}
{% include "header.html" %}
{% endwith %}
<main class="normalize" id="grapheneos">
<main class="normalize" id="hakurei">
<div class="content hero">
<div>
<h1><a href="#grapheneos">GrapheneOS</a></h1>
<p>The private and secure mobile operating system with Android app compatibility.
<h1><a href="#hakurei">Hakurei</a></h1>
<p>A security-focused Linux container runtime for desktop applications.
Developed as a non-profit open source project.</p>
<a class="button" href="/install/">Install GrapheneOS</a>
<a class="button" href="/install.html">Install Hakurei</a>
</div>
<figure class="device-img">
<img class="phone-img" width="276" height="579" src="[[path|/pixel-7-pro.svg]]" alt=""/>
<img class="phone-logo-img" width="200" height="200" src="[[path|/mask-icon.svg]]" alt=""/>
<img class="laptop-img" width="288" height="171" src="[[path|/laptop.svg]]" alt=""/>
<img class="laptop-logo-img" width="108" height="108" src="[[path|/mask-icon.svg]]" alt=""/>
</figure>
</div>
<div class="surface">
<div class="content break">
<p>Get to know GrapheneOS</p>
<p>Get to know Hakurei</p>
</div>
</div>
@ -61,63 +60,59 @@
<section id="about">
<h2 class="start"><a href="#about">About</a></h2>
<p>GrapheneOS is a privacy and security focused mobile OS with Android app
compatibility developed as a non-profit <a href="/source">open source</a>
project. It's focused on the research and development of privacy and security
technology including substantial improvements to sandboxing, exploit
mitigations and the permission model. It was founded in 2014 and was
<a href="/history/copperheados">formerly known as CopperheadOS</a>.</p>
<p>Hakurei is a security-focused Linux container runtime for running unmodified
desktop applications, developed as a non-profit <a
href="https://git.gensokyo.uk/security/hakurei" target="_blank">open source</a>
project. It also implements <a href="/package.html">planterette</a>, an
experimental self-contained Android-like package manager with modern security
features.</p>
<p>GrapheneOS improves the privacy and security of the OS from the bottom up.
It deploys technologies to mitigate whole classes of vulnerabilities and make
exploiting the most common sources of vulnerabilities substantially more
difficult. It improves the security of both the OS and the apps running on it.
The app sandbox and other security boundaries are fortified. GrapheneOS tries
to avoid impacting the user experience with the privacy and security features.
Ideally, the features can be designed so that they're always enabled with no
impact on the user experience and no additional complexity like configuration
options. It's not always feasible, and GrapheneOS does add various toggles for
features like the Network permission, Sensors permission, restrictions when
the device is locked (USB-C / pogo pins, camera, quick tiles), etc. along with
more complex user-facing privacy and security features with their own UX.</p>
<p>Security on the desktop has always left something to be desired. While <a
href="https://www.qubes-os.org" target="_blank">Qubes OS</a> provides excellent
security, its performance and usability limitations make it unsuitable for most
use cases. Hakurei attempts to fill that gap by running applications natively
while still establishing decent compartmentalisation enforced by the kernel.</p>
<p>The <a href="/features">features page</a> provides an overview of the
substantial privacy and security improvements added by GrapheneOS to the
Android Open Source Project (AOSP). Many of our past features were <a
href="/faq#upstream">contributed to AOSP, Linux and other projects to improve
privacy and security for billions of users</a> so they're no longer listed on
our features page.</p>
<p>Hakurei runs each container as a dedicated subordinate user and sets up the
container via unprivileged user namespaces as another layer of defense against
privilege escalation. Unprivileged user namespace creation is made unavailable
in containers by default to reduce attack surface, but can be optionally enabled
for applications with strong built-in sandboxes to avoid having to ruin their
sandbox.</p>
<p>Official releases are available on the <a href="/releases">releases
page</a> and installation instructions are on the <a href="/install/">install
page</a>.</p>
<p>GrapheneOS also develops various apps and services with a focus on privacy
and security. Vanadium is a hardened variant of the Chromium browser and
WebView specifically built for GrapheneOS. GrapheneOS also includes our
minimal security-focused PDF Viewer, our hardware-based Auditor app /
attestation service providing local and remote verification of devices,
our modern privacy / security focused camera app, and the externally developed
Seedvault encrypted backup which was initially developed for inclusion in
GrapheneOS.</p>
<p>Official releases are available via <a
href="https://git.gensokyo.uk/security/hakurei/releases" target="_blank">Gitea
</a> and documentation for the included NixOS module can be found
<a href="https://git.gensokyo.uk/security/hakurei/src/branch/master/options.md"
target="_blank">here</a>.</p>
</section>
<section id="never-google-services">
<h2><a href="#never-google-services">No Google apps or services</a></h2>
<section id="compatibility">
<h2><a href="#compatibility">OS Compatibility</a></h2>
<p>GrapheneOS will never include either Google Play services or another
implementation of Google services like microG. It's possible to install Play
services as a set of fully sandboxed apps without special privileges via our
<a href="/usage#sandboxed-google-play">sandboxed Google Play compatibility
layer</a>. See <a href="/faq#google-services">the FAQ section</a> for more
details on our plans for filling in the gaps from not shipping Play services
and Google apps.</p>
</section>
<p>Hakurei does not try to support every major Linux distribution and their
configuration of the kernel. Most Debian-based distributions disable
unprivileged user namespace creation by default, and while that could be a
good way to reduce attack surface, it also disables a layer of security
where the kernel enforces strict limits on user namespaces created by
an unprivileged user. Having to set up the sandbox as root also adds
significant complexity to the setuid wrapper.
The reduction of attack surface is also made irrelevant since hakurei can
disable unprivileged user namespace creation on a per-container basis.</p>
<section id="device-support">
<h2><a href="/faq#device-support">Device support</a></h2>
<p>Users on affected kernels can switch to an unmodified (and up to date) kernel
or enable unprivileged user namespace creation by setting the
<code>kernel.unprivileged_userns_clone</code> sysctl to 1.
Whether or not it increases attack surface is largely dependent on what runs
on the system; however, if all apps are spawned by Hakurei and the rest of the
system is sufficiently secured, enabling unprivileged user namespace creation
should not increase attack surface whatsoever.</p>
<p class="end">See <a href="/faq#device-support">the FAQ section on device support</a>.</p>
<p>While Hakurei is primarily developed on NixOS and relies on Nix for its
integration test suite, it does not target NixOS or make assumptions that are
only true on NixOS. Unfortunately, mistakes do happen semi-often as the
architecture of NixOS can often hide bugs and assumptions. Please <a
href="/contact.html">report</a> such anomalies if you encounter them.</p>
</section>
</div>
</main>

50
static/install.html Normal file
View File

@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="en" prefix="og: https://ogp.me/ns#">
<head>
<meta charset="utf-8"/>
<title>Install | Hakurei</title>
<meta name="description" content="Installation instructions for Hakurei, a security-focused Linux container runtime for desktop applications."/>
<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, viewport-fit=cover"/>
<meta property="og:title" content="Hakurei installation"/>
<meta property="og:description" content="Installation instructions for Hakurei, a security-focused Linux container runtime for desktop applications."/>
<meta property="og:type" content="website"/>
<meta property="og:image" content="https://hakurei.app/opengraph.png"/>
<meta property="og:image:width" content="512"/>
<meta property="og:image:height" content="512"/>
<meta property="og:image:alt" content="Hakurei logo"/>
<meta property="og:site_name" content="Hakurei"/>
<meta property="og:url" content="https://hakurei.app/install.html"/>
<link rel="canonical" href="https://hakurei.app/install.html"/>
<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://port.mk/@hakurei"/>
</head>
<body>
{% with current_page="install" %}
{% include "header.html" %}
{% endwith %}
<main id="install">
<h1><a href="#install">Install</a></h1>
<p>Hakurei can be installed to almost any Linux-based operating system by running
<code>install.sh</code> from a release tarball found <a
href="https://git.gensokyo.uk/security/hakurei/releases" target="_blank">here</a>.
With that said, the current easiest method for using Hakurei with desktop apps would be
via the <a href="https://git.gensokyo.uk/security/hakurei/src/branch/master/options.md"
target="_blank">companion NixOS module</a>.</p>
<p>We strongly recommend using one of the official installation methods. Third party
installation guides tend to be out-of-date and often contain misguided advice and
errors.</p>
</main>
{% include "footer.html" %}
</body>
</html>

View File

@ -1,666 +0,0 @@
<!DOCTYPE html>
<html lang="en" prefix="og: https://ogp.me/ns#">
<head>
<meta charset="utf-8"/>
<title>CLI install guide | Install | GrapheneOS</title>
<meta name="description" content="Command-line installation instructions 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, viewport-fit=cover"/>
<meta name="twitter:site" content="@GrapheneOS"/>
<meta name="twitter:creator" content="@GrapheneOS"/>
<meta property="og:title" content="GrapheneOS CLI install guide"/>
<meta property="og:description" content="Command-line installation instructions 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/cli"/>
<link rel="canonical" href="https://grapheneos.org/install/cli"/>
<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]]
</head>
<body>
{% include "header.html" %}
<main id="cli-install">
<h1><a href="#cli-install">CLI install guide</a></h1>
<p>This is a guide on installing GrapheneOS on the
<a href="/faq#supported-devices">officially supported devices</a>. It can be followed
for both the <a href="/releases">official releases</a> and <a href="/build">custom
builds</a>. The <a href="/install/web">web installer</a> is an
easier approach to installing the official releases via a browser with WebUSB
support.</p>
<p>We strongly recommend following these official instructions. The official guide has
a lot of collaborative effort put into covering all of the edge cases and is regularly
tested by many people on each supported OS. Following these instructions to the letter
without skipping, reordering or adding any steps will give you a proper GrapheneOS
installation unless there's a hardware issue. We strongly recommend against following
unofficial guides deviating in any way from the official instructions.</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="#opening-terminal">Opening terminal</a></li>
<li>
<a href="#obtaining-fastboot">Obtaining fastboot</a>
<ul>
<li><a href="#standalone-platform-tools">Standalone platform-tools</a></li>
</ul>
</li>
<li><a href="#checking-fastboot-version">Checking fastboot version</a></li>
<li><a href="#flashing-as-non-root">Flashing as non-root</a></li>
<li><a href="#working-around-fwupd-bugs-on-linux-distributions">Working around fwupd bugs on Linux distributions</a></li>
<li><a href="#booting-into-the-bootloader-interface">Booting into the bootloader interface</a></li>
<li><a href="#connecting-device">Connecting the device</a></li>
<li><a href="#unlocking-the-bootloader">Unlocking the bootloader</a></li>
<li><a href="#obtaining-openssh">Obtaining OpenSSH</a></li>
<li><a href="#obtaining-factory-images">Obtaining factory images</a></li>
<li>
<a href="#flashing-factory-images">Flashing factory images</a>
<ul>
<li><a href="#troubleshooting">Troubleshooting</a></li>
</ul>
</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="#further-information">Further information</a></li>
<li><a href="#replacing-grapheneos-with-the-stock-os">Replacing GrapheneOS with the stock OS</a></li>
</ul>
</li>
</ul>
</nav>
<section id="prerequisites">
<h2><a href="#prerequisites">Prerequisites</a></h2>
<p>You need a computer for running the CLI install process with at least 2GB of free
memory available and 32GB of free storage space. The web installer can be run on an
Android phone or tablet, unlike the command-line installation.</p>
<p>You need a USB cable for attaching the device to the computer performing the
installation. 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 CLI install method:</p>
<ul>
<li>Windows 10</li>
<li>Windows 11</li>
<li>macOS Ventura (13)</li>
<li>macOS Sonoma (14)</li>
<li>macOS Sequoia (15)</li>
<li>Arch Linux</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 24.04 LTS</li>
<li>Ubuntu 24.10</li>
<li>Linux Mint 20 (follow Ubuntu 20.04 LTS instructions)</li>
<li>Linux Mint 21 (follow Ubuntu 22.04 LTS instructions)</li>
<li>Linux Mint 22 (follow Ubuntu 24.04 LTS instructions)</li>
<li>Linux Mint Debian Edition 6 (follow Debian 12 instructions)</li>
</ul>
<p>Make sure your operating system is up-to-date before proceeding.</p>
<p>The <a href="/install/web">web installer</a> is more portable and can be used
from Android, ChromeOS and GrapheneOS itself since it can run anywhere with a
browser with working WebUSB support.</p>
<p>You need one of the <a href="/faq#supported-devices">officially supported
devices</a>. 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 device 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 <b>Settings&#160;<span
aria-label="and then">></span> About phone/tablet</b> and repeatedly
pressing the <b>Build number</b> menu entry until developer mode is enabled.</p>
<p>Next, go to <b>Settings&#160;<span aria-label="and then">></span>
System&#160;<span aria-label="and then">></span> Developer options</b> and
toggle on the <b>OEM unlocking</b> setting. On device model variants (SKUs) which
support being sold as locked devices by carriers, enabling <b>OEM unlocking</b>
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="opening-terminal">
<h2><a href="#opening-terminal">Opening terminal</a></h2>
<p>These instructions use command-line tools. Launch the terminal as you would any
other application. On Windows, launch a regular non-administrator instance of the
PowerShell terminal. Do not use the legacy Command Prompt or administrator variant
of PowerShell.</p>
<p>Use the same terminal for the whole installation process. If you close it,
you'll lose the setup of the environment for the installation.</p>
<p>On Windows, run the following command to remove PowerShell's legacy curl alias
for the current shell to avoid needing to reference it as <code>curl.exe</code>
instead of <code>curl</code>:</p>
<pre>Remove-Item Alias:Curl</pre>
</section>
<section id="obtaining-fastboot">
<h2><a href="#obtaining-fastboot">Obtaining fastboot</a></h2>
<p>You need an updated copy of the <code>fastboot</code> tool and the
directory containing it needs to be included in the <code>PATH</code>
environment variable. You can run <code>fastboot --version</code> to determine
the current version. It must be at least <code>35.0.1</code>. You can use a
distribution package for this, but most of them mistakenly package development
snapshots of fastboot, clobber the standard version scheme for platform-tools
(adb, fastboot, etc.) with their own scheme and don't keep it up-to-date
despite that being crucial.</p>
<p>On Arch Linux, install <code>android-tools</code> and skip the section below on
using the standalone release of platform-tools from Android:</p>
<pre>sudo pacman -S android-tools</pre>
<p>Debian and Ubuntu do not have a usable package for fastboot. Their packages for
these tools are both broken and many years out-of-date. Follow the instructions
below for platforms without a proper package.</p>
<section id="standalone-platform-tools">
<h3><a href="#standalone-platform-tools">Standalone platform-tools</a></h3>
<!-- https://developer.android.com/studio/releases/platform-tools -->
<p>If your operating system doesn't include a usable version of fastboot,
you can use the official standalone releases of platform-tools. This is
our recommendation for most users. The flashing process won't work unless
you follow these instructions including setting up PATH.</p>
<p>To download, verify and extract the standalone platform-tools on Debian and
Ubuntu:</p>
<pre>sudo apt install libarchive-tools
curl -O https://dl.google.com/android/repository/platform-tools_r35.0.2-linux.zip
echo 'acfdcccb123a8718c46c46c059b2f621140194e5ec1ac9d81715be3d6ab6cd0a platform-tools_r35.0.2-linux.zip' | sha256sum -c
bsdtar xvf platform-tools_r35.0.2-linux.zip</pre>
<p>To download, verify and extract the standalone platform-tools on macOS:</p>
<pre>curl -O https://dl.google.com/android/repository/platform-tools_r35.0.2-darwin.zip
echo 'SHA256 (platform-tools_r35.0.2-darwin.zip) = 1820078db90bf21628d257ff052528af1c61bb48f754b3555648f5652fa35d78' | shasum -c
tar xvf platform-tools_r35.0.2-darwin.zip</pre>
<p>To download, verify and extract the standalone platform-tools on Windows:</p>
<pre>curl -O https://dl.google.com/android/repository/platform-tools_r35.0.2-win.zip
(Get-FileHash platform-tools_r35.0.2-win.zip).hash -eq "2975a3eac0b19182748d64195375ad056986561d994fffbdc64332a516300bb9"
tar xvf platform-tools_r35.0.2-win.zip</pre>
<p>Next, add the tools to your <code>PATH</code> in the current shell so they can be
used without referencing them by file path, enabling usage by the flashing script.</p>
<p>On Debian, Ubuntu and macOS:</p>
<pre>export PATH="$PWD/platform-tools:$PATH"</pre>
<p>On Windows:</p>
<pre>$env:Path = "$pwd\platform-tools;$env:Path"</pre>
<p>This only changes <code>PATH</code> for the current shell and will need
to be done again if you open a new terminal.</p>
</section>
</section>
<section id="checking-fastboot-version">
<h2><a href="#checking-fastboot-version">Checking fastboot version</a></h2>
<p>Check the output of <code>fastboot --version</code> before continuing.</p>
<p>Example of the output after following the instructions above for the
standalone platform-tools:</p>
<pre>fastboot version 35.0.2-12147458
Installed as /home/username/platform-tools/fastboot</pre>
</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:</p>
<pre>sudo pacman -S android-udev</pre>
<p>On Debian and Ubuntu:</p>
<pre>sudo apt install android-sdk-platform-tools-common</pre>
<p>The udev rules on Debian and Ubuntu are very out-of-date but the package has
the rules needed for Pixel devices since the same USB IDs have been used for many
years.</p>
</section>
<section id="working-around-fwupd-bugs-on-linux-distributions">
<h2><a href="#working-around-fwupd-bugs-on-linux-distributions">Working around fwupd bugs on Linux distributions</a></h2>
<p>The fwupd software often used on Linux distributions for updating firmware is
known to incorrectly connect to arbitrary devices using the fastboot protocol which
will block using them for the intended purpose. This can result in receiving an
error about the USB device already being in use (claimed) when trying to connect to
it for the intended purpose.</p>
<p>You can stop fwupd with the following command:</p>
<pre>sudo systemctl stop fwupd.service</pre>
<p>This doesn't disable the service and it will start again on reboot.</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 device into the bootloader interface. To do this, you need
to hold the volume down button while the device boots.</p>
<p>The easiest approach is to reboot the device and begin holding the volume down
button until it boots up into the bootloader interface.</p>
<p>Alternatively, turn off the device, 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>
<p>This step is not complete until your device displays a red warning triangle
and the words "Fastboot Mode". You must not press the device's power button
to activate the "Start" menu item, because the device must remain paused in
Fastboot mode for the <code>fastboot</code> command to connect to it.</p>
</section>
<section id="connecting-device">
<h2><a href="#connecting-device">Connecting the device</a></h2>
<p>Connect the device 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>Current Windows 10 and Windows 11 include a generic driver usable for fastboot
and no longer require installing a driver for installation on the Pixel 4a (5G) or
later. It isn't enough for legacy 4th generation Pixels due to the driver not
handling fastbootd, so you still need the driver for those. Outdated Windows
versions will still need the driver for non-obsolete devices too. 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, which will show up as "LeMobile Android Device" due to USB ID overlap. 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>
<p>For the Pixel Tablet, disconnect it from the stand before continuing. The stand
uses USB to provide charging and audio output, but the tablet lacks support for
using both the stand and USB port at the same time.</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>
<pre>fastboot flashing unlock</pre>
<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>
</section>
<section id="obtaining-openssh">
<h2><a href="#obtaining-openssh">Obtaining openssh</a></h2>
<p>OpenSSH is used to verify the download of the OS beyond the security offered by
HTTPS.</p>
<p>macOS and Windows include OpenSSH in their base install so this isn't needed.</p>
<p>On Arch Linux:</p>
<pre>sudo pacman -S openssh</pre>
<p>On Debian and Ubuntu:</p>
<pre>sudo apt install openssh-client</pre>
</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>You can either download the files with your browser or using a command like
<code>curl</code>. It's generally easier to use the command-line since you're already
using it for the rest of the installation process, so these instructions use
<code>curl</code>.</p>
<p>Download <a href="https://releases.grapheneos.org/allowed_signers">the factory images
public key (allowed_signers)</a> in order to verify the factory images:</p>
<pre>curl -O https://releases.grapheneos.org/allowed_signers</pre>
<p>This is the content of <code>allowed_signers</code>:</p>
<pre>contact@grapheneos.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIUg/m5CoP83b0rfSCzYSVA4cw4ir49io5GPoxbgxdJE</pre>
<p>Other locations to obtain the signing key:</p>
<ul>
<li><a href="https://bsky.app/profile/grapheneos.org/post/3kleyygkptm2x">Bluesky</a></li>
<li><a href="https://x.com/GrapheneOS/status/1757758688952009209">Twitter</a></li>
<li><a href="https://github.com/GrapheneOS/releases.grapheneos.org/blob/main/static/allowed_signers">GitHub</a></li>
</ul>
<p>When the current signing key is replaced, the new key will be signed with it.</p>
<p>Download the factory images for the device from <a href="/releases">the releases
page</a>. For example, to download the <code><var>VERSION</var></code> release for
a device with the codename <code><var>DEVICE_NAME</var></code>:</p>
<pre>curl -O https://releases.grapheneos.org/<var>DEVICE_NAME</var>-install-<var>VERSION</var>.zip
curl -O https://releases.grapheneos.org/<var>DEVICE_NAME</var>-install-<var>VERSION</var>.zip.sig</pre>
<p>Next, verify the factory images using the signature.</p>
<p>On Linux and macOS:</p>
<pre>ssh-keygen -Y verify -f allowed_signers -I contact@grapheneos.org -n "factory images" -s <var>DEVICE_NAME</var>-install-<var>VERSION</var>.zip.sig &lt; <var>DEVICE_NAME</var>-install-<var>VERSION</var>.zip</pre>
<p>On Windows:</p>
<pre>cmd /c 'ssh-keygen -Y verify -f allowed_signers -I contact@grapheneos.org -n "factory images" -s <var>DEVICE_NAME</var>-install-<var>VERSION</var>.zip.sig &lt; <var>DEVICE_NAME</var>-install-<var>VERSION</var>.zip'</pre>
<p>This will produce the following output when successful:</p>
<pre>Good "factory images" signature for contact@grapheneos.org with ED25519 key SHA256:AhgHif0mei+9aNyKLfMZBh2yptHdw/aN7Tlh/j2eFwM</pre>
</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>
<p>Next, extract the factory images.</p>
<p>On Linux:</p>
<pre>bsdtar xvf <var>DEVICE_NAME</var>-install-<var>VERSION</var>.zip</pre>
<p>On macOS and Windows:</p>
<pre>tar xvf <var>DEVICE_NAME</var>-install-<var>VERSION</var>.zip</pre>
<p>Move into the directory:</p>
<pre>cd <var>DEVICE_NAME</var>-install-<var>VERSION</var></pre>
<p>Flash the images with the flash-all script in the directory.</p>
<p>On Linux and macOS:</p>
<pre>bash flash-all.sh</pre>
<p>On Windows:</p>
<pre>./flash-all.bat</pre>
<p>Wait for the flashing process to complete. It will automatically handle
flashing the firmware, rebooting into the bootloader interface and flashing the OS.
Avoid interacting with the device until the flashing script is finished. Then,
proceed to <a href="#locking-the-bootloader">locking the bootloader</a> before using
the device as locking wipes the data again.</p>
<section id="troubleshooting">
<h3><a href="#troubleshooting">Troubleshooting</a></h3>
<p>The text output from a failed attempt at flashing will contain valuable
diagnostic information which is essential in knowing where and how the process
went wrong. Please provide this information when asking for help on the
<a href="/contact#community">GrapheneOS chat room</a>.</p>
<p>A common issue on Linux distributions is that they mount the default temporary file
directory <code>/tmp</code> as tmpfs which results in it being backed by memory and
swap rather than persistent storage. By default, the size is 50% of the available
virtual memory. This is often not enough for the flashing process, especially since
<code>/tmp</code> is shared between applications and users. To use a different
temporary directory if your <code>/tmp</code> doesn't have enough space available:</p>
<pre>mkdir tmp &amp;&amp; TMPDIR="$PWD/tmp" ./flash-all.sh</pre>
</section>
</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>
<pre>fastboot flashing lock</pre>
<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>
</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>During first setup, the final screen will contain a toggle regarding OEM
unlocking which is checked by default. This will disable OEM unlocking, which is
recommended.</p>
<p>If you need to enable or disable OEM unlocking in the future, it can be done
in the developer settings menu within the operating system.</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 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 generation Pixels onwards
show the full hash and you can compare it against the official GrapheneOS
verified boot key hashes below:</p>
<ul>
<li>Pixel 9a: <code>0508de44ee00bfb49ece32c418af1896391abde0f05b64f41bc9a2dfb589445b</code></li>
<li>Pixel 9 Pro Fold: <code>af4d2c6e62be0fec54f0271b9776ff061dd8392d9f51cf6ab1551d346679e24c</code></li>
<li>Pixel 9 Pro XL: <code>55d3c2323db91bb91f20d38d015e85112d038f6b6b5738fe352c1a80dba57023</code></li>
<li>Pixel 9 Pro: <code>f729cab861da1b83fdfab402fc9480758f2ae78ee0b61c1f2137dd1ab7076e86</code></li>
<li>Pixel 9: <code>9e6a8f3e0d761a780179f93acd5721ba1ab7c8c537c7761073c0a754b0e932de</code></li>
<li>Pixel 8a: <code>096b8bd6d44527a24ac1564b308839f67e78202185cbff9cfdcb10e63250bc5e</code></li>
<li>Pixel 8 Pro: <code>896db2d09d84e1d6bb747002b8a114950b946e5825772a9d48ba7eb01d118c1c</code></li>
<li>Pixel 8: <code>cd7479653aa88208f9f03034810ef9b7b0af8a9d41e2000e458ac403a2acb233</code></li>
<li>Pixel Fold: <code>ee0c9dfef6f55a878538b0dbf7e78e3bc3f1a13c8c44839b095fe26dd5fe2842</code></li>
<li>Pixel Tablet: <code>94df136e6c6aa08dc26580af46f36419b5f9baf46039db076f5295b91aaff230</code></li>
<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="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 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 the same process
described above. 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, you should boot the device into fastboot mode and make sure the
bootloader is unlocked. Then erase the custom Android Verified Boot key to untrust it:</p>
<pre>fastboot erase avb_custom_key</pre>
</section>
</section>
</main>
{% include "footer.html" %}
</body>
</html>

View File

@ -1,63 +0,0 @@
<!DOCTYPE html>
<html lang="en" prefix="og: https://ogp.me/ns#">
<head>
<meta charset="utf-8"/>
<title>Install | GrapheneOS</title>
<meta name="description" content="Installation instructions 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, viewport-fit=cover"/>
<meta name="twitter:site" content="@GrapheneOS"/>
<meta name="twitter:creator" content="@GrapheneOS"/>
<meta property="og:title" content="GrapheneOS installation"/>
<meta property="og:description" content="Installation instructions 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/"/>
<link rel="canonical" href="https://grapheneos.org/install/"/>
<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]]
</head>
<body>
{% with current_page="install" %}
{% include "header.html" %}
{% endwith %}
<main id="install">
<h1><a href="#install">Install</a></h1>
<p>GrapheneOS has two officially supported installation methods. You can either use
the <a href="/install/web">WebUSB-based installer</a> recommended for most users or
the <a href="/install/cli">command-line installation guide</a> aimed at more technical
users.</p>
<p>We strongly recommend using one of the official installation methods. Third party
installation guides tend to be out-of-date and often contain misguided advice and
errors.</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>
<p>The command-line approach requires being on an OS with proper fastboot and OpenSSH
packages, along with understanding the process enough to avoid blindly trusting the
instructions from our site. The web-based installation approach avoids needing any
software beyond a browser with WebUSB support and you can still avoid trusting our
server infrastructure by checking the verified boot key hash.</p>
</main>
{% include "footer.html" %}
</body>
</html>

View File

@ -1,489 +0,0 @@
<!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, viewport-fit=cover"/>
<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/ffe7e270/fastboot.min.mjs" integrity="sha256-/TM74wkIOUV1rXRSGlzJPb4ZjBA52fzUW3aSypxxtwc="></script>
[[js|/js/web-install.js]]
</head>
<body>
{% include "header.html" %}
<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="#working-around-fwupd-bugs-on-linux-distributions">Working around fwupd bugs on Linux distributions</a></li>
<li><a href="#booting-into-the-bootloader-interface">Booting into the bootloader interface</a></li>
<li><a href="#connecting-device">Connecting the device</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="#further-information">Further information</a></li>
<li><a href="#replacing-grapheneos-with-the-stock-os">Replacing GrapheneOS with the stock OS</a></li>
</ul>
</li>
</ul>
</nav>
<section id="prerequisites">
<h2><a href="#prerequisites">Prerequisites</a></h2>
<p>You need a computer for running the web installer with at least 2GB of free
memory available and 32GB of free storage space. The web installer can be run on an
Android phone or tablet, unlike the command-line installation.</p>
<p>You need a USB cable for attaching the device to the computer performing the
installation. 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 Ventura (13)</li>
<li>macOS Sonoma (14)</li>
<li>macOS Sequoia (15)</li>
<li>Arch Linux</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 24.04 LTS</li>
<li>Ubuntu 24.10</li>
<li>Linux Mint 20 (follow Ubuntu 20.04 LTS instructions)</li>
<li>Linux Mint 21 (follow Ubuntu 22.04 LTS instructions)</li>
<li>Linux Mint 22 (follow Ubuntu 24.04 LTS instructions)</li>
<li>Linux Mint Debian Edition 6 (follow Debian 12 instructions)</li>
<li>ChromeOS</li>
<li>GrapheneOS</li>
<li>Android 12 with Play Protect certification</li>
<li>Android 13 with Play Protect certification</li>
<li>Android 14 with Play Protect certification</li>
<li>Android 15 with Play Protect certification</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 (with Brave Shields disabled, since it caps storage usage at a low value to avoid fingerprinting available storage)</li>
</ul>
<p>On Android, disable desktop mode for the browser since it currently prevents our
web installer from detecting Android and handling needing to request permission to
reconnect to the device after each reboot. Desktop mode is enabled by default on
large tablets with at least 8GB of RAM such as the Pixel Tablet.</p>
<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 <a href="/faq#supported-devices">officially supported
devices</a>. 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 device 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 <b>Settings&#160;<span
aria-label="and then">></span> About phone/tablet</b> and repeatedly
pressing the <b>Build number</b> menu entry until developer mode is enabled.</p>
<p>Next, go to <b>Settings&#160;<span aria-label="and then">></span>
System&#160;<span aria-label="and then">></span> Developer options</b> and
toggle on the <b>OEM unlocking</b> setting. On device model variants (SKUs) which
support being sold as locked devices by carriers, enabling <b>OEM unlocking</b>
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="working-around-fwupd-bugs-on-linux-distributions">
<h2><a href="#working-around-fwupd-bug-on-linux-distributions">Working around fwupd bugs on Linux distributions</a></h2>
<p>The fwupd software often used on Linux distributions for updating firmware is
known to incorrectly connect to arbitrary devices using the fastboot protocol which
will block using them for the intended purpose. This can result in receiving an
error about the USB device already being in use (claimed) when trying to connect to
it for the intended purpose.</p>
<p>You can stop fwupd with the following command:</p>
<pre>sudo systemctl stop fwupd.service</pre>
<p>This doesn't disable the service and it will start again on reboot.</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 device into the bootloader interface. To do this, you need
to hold the volume down button while the device boots.</p>
<p>The easiest approach is to reboot the device and begin holding the volume down
button until it boots up into the bootloader interface.</p>
<p>Alternatively, turn off the device, 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>
<p>This step is not complete until your device displays a red warning triangle
and the words "Fastboot Mode". You must not press the device's power button
to activate the "Start" menu item, because the device must remain paused in
Fastboot mode for the installer to connect to it.</p>
</section>
<section id="connecting-device">
<h2><a href="#connecting-device">Connecting the device</a></h2>
<p>Connect the device 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>Current Windows 10 and Windows 11 include a generic driver usable for fastboot
and no longer require installing a driver for installation on the Pixel 4a (5G) or
later. It isn't enough for legacy 4th generation Pixels due to the driver not
handling fastbootd, so you still need the driver for those. Outdated Windows
versions will still need the driver for non-obsolete devices too. 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, which will show up as "LeMobile Android Device" due to USB ID overlap. 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>
<p>For the Pixel Tablet, disconnect it from the stand before continuing. The stand
uses USB to provide charging and audio output, but the tablet lacks support for
using both the stand and USB port at the same time.</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 and flashing the OS.
Avoid interacting with the device until the flashing script is finished. 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>During first setup, the final screen will contain a toggle regarding OEM
unlocking which is checked by default. This will disable OEM unlocking, which is
recommended.</p>
<p>If you need to enable or disable OEM unlocking in the future, it can be done
in the developer settings menu within the operating system.</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 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 generation Pixels onwards
show the full hash and you can compare it against the official GrapheneOS
verified boot key hashes below:</p>
<ul>
<li>Pixel 9a: <code>0508de44ee00bfb49ece32c418af1896391abde0f05b64f41bc9a2dfb589445b</code></li>
<li>Pixel 9 Pro Fold: <code>af4d2c6e62be0fec54f0271b9776ff061dd8392d9f51cf6ab1551d346679e24c</code></li>
<li>Pixel 9 Pro XL: <code>55d3c2323db91bb91f20d38d015e85112d038f6b6b5738fe352c1a80dba57023</code></li>
<li>Pixel 9 Pro: <code>f729cab861da1b83fdfab402fc9480758f2ae78ee0b61c1f2137dd1ab7076e86</code></li>
<li>Pixel 9: <code>9e6a8f3e0d761a780179f93acd5721ba1ab7c8c537c7761073c0a754b0e932de</code></li>
<li>Pixel 8a: <code>096b8bd6d44527a24ac1564b308839f67e78202185cbff9cfdcb10e63250bc5e</code></li>
<li>Pixel 8 Pro: <code>896db2d09d84e1d6bb747002b8a114950b946e5825772a9d48ba7eb01d118c1c</code></li>
<li>Pixel 8: <code>cd7479653aa88208f9f03034810ef9b7b0af8a9d41e2000e458ac403a2acb233</code></li>
<li>Pixel Fold: <code>ee0c9dfef6f55a878538b0dbf7e78e3bc3f1a13c8c44839b095fe26dd5fe2842</code></li>
<li>Pixel Tablet: <code>94df136e6c6aa08dc26580af46f36419b5f9baf46039db076f5295b91aaff230</code></li>
<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="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 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, you should boot the device into fastboot mode and make sure the
bootloader is unlocked. Then 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>
</main>
{% include "footer.html" %}
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

165
static/js/oneko.js Normal file
View File

@ -0,0 +1,165 @@
(function oneko() {
const nekoEl = document.createElement("div");
let nekoPosX = 32;
let nekoPosY = 32;
let mousePosX = 0;
let mousePosY = 0;
let frameCount = 0;
let idleTime = 0;
let idleAnimation = null;
let idleAnimationFrame = 0;
const nekoSpeed = 10;
const spriteSets = {
idle: [[-3, -3]],
alert: [[-7, -3]],
scratch: [
[-5, 0],
[-6, 0],
[-7, 0],
],
tired: [[-3, -2]],
sleeping: [
[-2, 0],
[-2, -1],
],
N: [
[-1, -2],
[-1, -3],
],
NE: [
[0, -2],
[0, -3],
],
E: [
[-3, 0],
[-3, -1],
],
SE: [
[-5, -1],
[-5, -2],
],
S: [
[-6, -3],
[-7, -2],
],
SW: [
[-5, -3],
[-6, -1],
],
W: [
[-4, -2],
[-4, -3],
],
NW: [
[-1, 0],
[-1, -1],
],
};
function create() {
nekoEl.id = "oneko";
nekoEl.style.width = "32px";
nekoEl.style.height = "32px";
nekoEl.style.position = "fixed";
nekoEl.style.pointerEvents = "none";
nekoEl.style.backgroundImage = "url('/oneko.gif')";
nekoEl.style.imageRendering = "pixelated";
nekoEl.style.left = "16px";
nekoEl.style.top = "16px";
document.body.appendChild(nekoEl);
document.onmousemove = (event) => {
mousePosX = event.clientX;
mousePosY = event.clientY;
};
window.onekoInterval = setInterval(frame, 100);
}
function setSprite(name, frame) {
const sprite = spriteSets[name][frame % spriteSets[name].length];
nekoEl.style.backgroundPosition = `${sprite[0] * 32}px ${
sprite[1] * 32
}px`;
}
function resetIdleAnimation() {
idleAnimation = null;
idleAnimationFrame = 0;
}
function idle() {
idleTime += 1;
// every ~ 20 seconds
if (
idleTime > 10 &&
Math.floor(Math.random() * 200) == 0 &&
idleAnimation == null
) {
idleAnimation = ["sleeping", "scratch"][
Math.floor(Math.random() * 2)
];
}
switch (idleAnimation) {
case "sleeping":
if (idleAnimationFrame < 8) {
setSprite("tired", 0);
break;
}
setSprite("sleeping", Math.floor(idleAnimationFrame / 4));
if (idleAnimationFrame > 192) {
resetIdleAnimation();
}
break;
case "scratch":
setSprite("scratch", idleAnimationFrame);
if (idleAnimationFrame > 9) {
resetIdleAnimation();
}
break;
default:
setSprite("idle", 0);
return;
}
idleAnimationFrame += 1;
}
function frame() {
frameCount += 1;
const diffX = nekoPosX - mousePosX;
const diffY = nekoPosY - mousePosY;
const distance = Math.sqrt(diffX ** 2 + diffY ** 2);
if (distance < nekoSpeed || distance < 48) {
idle();
return;
}
idleAnimation = null;
idleAnimationFrame = 0;
if (idleTime > 1) {
setSprite("alert", 0);
// count down after being alerted before moving
idleTime = Math.min(idleTime, 7);
idleTime -= 1;
return;
}
let direction = diffY / distance > 0.5 ? "N" : "";
direction += diffY / distance < -0.5 ? "S" : "";
direction += diffX / distance > 0.5 ? "W" : "";
direction += diffX / distance < -0.5 ? "E" : "";
setSprite(direction, frameCount);
nekoPosX -= (diffX / distance) * nekoSpeed;
nekoPosY -= (diffY / distance) * nekoSpeed;
nekoEl.style.left = `${nekoPosX - 16}px`;
nekoEl.style.top = `${nekoPosY - 16}px`;
}
create();
})();

View File

@ -1,106 +0,0 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt MIT
// Client-side redirects for fragments (anchors)
//
// It should be possible to do this with either HTML or server-side redirects, but it was never
// implemented or standardized. For reference:
//
// https://www.w3.org/People/Bos/redirect
// https://www.w3.org/Protocols/HTTP/Fragment/draft-bos-http-redirect-00.txt
const redirects = new Map([
// removed main page sections
["/#copyright-and-licensing", "/faq#copyright-and-licensing"],
["/#history", "/history"],
["/#roadmap", "/faq#roadmap"],
["/#upstream", "/faq#upstream"],
["/usage#default-connections", "/faq#default-connections"],
["/usage#sandboxed-google-play-esim", "/usage#esim-support"],
["/usage#sandboxed-play-services", "/usage#sandboxed-google-play"],
["/usage#sandboxed-play-services-installation", "/usage#sandboxed-google-play-installation"],
["/usage#sandboxed-play-services-limitations", "/usage#sandboxed-google-play-limitations"],
["/usage#google-camera", "/usage#pixel-camera"],
["/usage#usb-peripherals", "/usage#usb-c-port-and-pogo-pins-control"],
["/faq#dns", "/faq#custom-dns"],
["/faq#when-devices", "/faq#future-devices"],
["/features#usb-c-port-control", "/features#usb-c-port-and-pogo-pins-control"],
["/features#Two-factor-fingerprint-unlock", "/features#two-factor-fingerprint-unlock"],
["/hiring#qualitifations", "/hiring#qualifications"],
["/install/cli#fastboot-as-non-root", "/install/cli#flashing-as-non-root"],
["/install/cli#obtaining-signify", "/install/cli#obtaining-openssh"],
["/install/web#fastboot-as-non-root", "/install/web#flashing-as-non-root"],
["/install/cli#working-around-fwupd-bug-on-linux-distributions", "/install/cli#working-around-fwupd-bugs-on-linux-distributions"],
["/install/web#working-around-fwupd-bug-on-linux-distributions", "/install/web#working-around-fwupd-bugs-on-linux-distributions"],
["/build#enabling-updatable-apex-components", "/build#apex-components"],
["/build#kernel-6th-generation-pixels", "/build#kernel-6th-through-9th-generation-pixels"],
["/build#kernel-7th-generation-pixels", "/build#kernel-6th-through-9th-generation-pixels"],
["/build#kernel-6th-and-7th-generation-pixels", "/build#kernel-6th-through-9th-generation-pixels"],
["/build#kernel-8th-generation-pixels", "/build#kernel-6th-through-9th-generation-pixels"],
["/build#kernel-9th-generation-pixels", "/build#kernel-6th-through-9th-generation-pixels"],
// legacy devices
["/releases#marlin-stable", "/faq#legacy-devices"],
["/releases#marlin-beta", "/faq#legacy-devices"],
["/releases#sailfish-stable", "/faq#legacy-devices"],
["/releases#sailfish-beta", "/faq#legacy-devices"],
["/releases#taimen-stable", "/faq#legacy-devices"],
["/releases#taimen-beta", "/faq#legacy-devices"],
["/releases#walleye-stable", "/faq#legacy-devices"],
["/releases#walleye-beta", "/faq#legacy-devices"],
["/releases#bonito-stable", "/faq#legacy-devices"],
["/releases#bonito-beta", "/faq#legacy-devices"],
["/releases#sargo-stable", "/faq#legacy-devices"],
["/releases#sargo-beta", "/faq#legacy-devices"],
["/releases#crosshatch-stable", "/faq#legacy-devices"],
["/releases#crosshatch-beta", "/faq#legacy-devices"],
["/releases#blueline-stable", "/faq#legacy-devices"],
["/releases#blueline-beta", "/faq#legacy-devices"],
// legacy servers
["/articles/grapheneos-servers#apps.grapheneos.org", "/articles/grapheneos-servers#releases.grapheneos.org"],
["/articles/grapheneos-servers#time.grapheneos.org", "/articles/grapheneos-servers#grapheneos.network"],
// preserve links to CLI install guide from when it was /install
["/install/#prerequisites", "/install/cli#prerequisites"],
["/install/#enabling-oem-unlocking", "/install/cli#enabling-oem-unlocking"],
["/install/#opening-terminal", "/install/cli#opening-terminal"],
["/install/#obtaining-fastboot", "/install/cli#obtaining-fastboot"],
["/install/#standalone-platform-tools", "/install/cli#standalone-platform-tools"],
["/install/#checking-fastboot-version", "/install/cli#checking-fastboot-version"],
["/install/#fastboot-as-non-root", "/install/cli#flashing-as-non-root"],
["/install/#connecting-phone", "/install/cli#connecting-phone"],
["/install/#unlocking-the-bootloader", "/install/cli#unlocking-the-bootloader"],
["/install/#obtaining-signify", "/install/cli#obtaining-openssh"],
["/install/#obtaining-factory-images", "/install/cli#obtaining-factory-images"],
["/install/#flashing-factory-images", "/install/cli#flashing-factory-images"],
["/install/#troubleshooting", "/install/cli#troubleshooting"],
["/install/#locking-the-bootloader", "/install/cli#locking-the-bootloader"],
["/install/#post-installation", "/install/cli#post-installation"],
["/install/#booting", "/install/cli#booting"],
["/install/#disabling-oem-unlocking", "/install/cli#disabling-oem-unlocking"],
["/install/#replacing-grapheneos-with-the-stock-os", "/install/cli#replacing-grapheneos-with-the-stock-os"],
["/install/#further-information", "/install/cli#further-information"],
["/install/web#connecting-phone", "/install/web#connecting-device"],
["/install/cli#connecting-phone", "/install/cli#connecting-device"],
]);
function handleHash() {
if (window.location.hash) {
const redirect = redirects.get(window.location.pathname + window.location.hash);
if (redirect) {
window.location.replace(redirect);
}
}
}
handleHash();
addEventListener("hashchange", handleHash, false);
// @license-end

View File

@ -1,49 +0,0 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt MIT
const baseUrl = "https://releases.grapheneos.org/";
const devices = ["comet", "komodo", "caiman", "tokay", "akita", "husky", "shiba", "felix", "tangorpro", "lynx", "cheetah", "panther", "bluejay", "raven", "oriole", "barbet", "redfin", "bramble", "sunfish", "coral", "flame"];
const legacyFactoryDevices = new Set(["sunfish", "coral", "flame"]);
const channels = ["stable", "beta", "alpha"];
const delayMs = 1000 * 60 * 5;
async function updateReleases() {
const requests = [];
for (const channel of channels) {
for (const device of devices) {
requests.push(fetch(`${baseUrl}${device}-${channel}`).then(response => {
if (!response.ok) {
return Promise.reject();
}
return response.text();
}).then(text => {
const metadata = text.trim().split(" ");
const factoryFormat = legacyFactoryDevices.has(device) ? "factory" : "install";
const factoryFilename = `${device}-${factoryFormat}-${metadata[0]}.zip`;
const factoryUrl = baseUrl + factoryFilename;
const updateFilename = `${device}-ota_update-${metadata[0]}.zip`;
const updateUrl = baseUrl + updateFilename;
const release = document.getElementById(`${device}-${channel}`);
const links = release.querySelectorAll("a, span");
links[0].textContent = metadata[0];
if (links[0].nodeName == "A") {
links[0].setAttribute("href", "#" + metadata[0]);
}
links[1].setAttribute("href", factoryUrl);
links[2].setAttribute("href", factoryUrl + ".sig");
links[3].setAttribute("href", updateUrl);
}));
}
}
await Promise.allSettled(requests);
setTimeout(updateReleases, delayMs);
}
setTimeout(updateReleases, delayMs);
// @license-end

View File

@ -1,475 +0,0 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt MIT
import * as fastboot from "./fastboot/ffe7e270/fastboot.min.mjs";
const RELEASES_URL = "https://releases.grapheneos.org";
const CACHE_DB_NAME = "BlobStore";
const CACHE_DB_VERSION = 1;
const Buttons = {
UNLOCK_BOOTLOADER: "unlock-bootloader",
DOWNLOAD_RELEASE: "download-release",
FLASH_RELEASE: "flash-release",
LOCK_BOOTLOADER: "lock-bootloader",
REMOVE_CUSTOM_KEY: "remove-custom-key"
};
const InstallerState = {
DOWNLOADING_RELEASE: 0x1,
INSTALLING_RELEASE: 0x2
};
let wakeLock = null;
const requestWakeLock = async () => {
try {
wakeLock = await navigator.wakeLock.request("screen");
console.log("Wake lock has been set");
wakeLock.addEventListener("release", async () => {
console.log("Wake lock has been released");
});
} catch (err) {
// if wake lock request fails - usually system related, such as battery
throw new Error(`${err.name}, ${err.message}`);
}
};
const releaseWakeLock = async () => {
if (wakeLock !== null) {
wakeLock.release().then(() => {
wakeLock = null;
});
}
};
// reacquires the wake lock should the visibility of the document change and the wake lock is released
document.addEventListener("visibilitychange", async () => {
if (wakeLock !== null && document.visibilityState === "visible") {
await requestWakeLock();
}
});
// This wraps XHR because getting progress updates with fetch() is overly complicated.
function fetchBlobWithProgress(url, onProgress) {
let xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.responseType = "blob";
xhr.send();
return new Promise((resolve, reject) => {
xhr.onload = () => {
resolve(xhr.response);
};
xhr.onprogress = (event) => {
onProgress(event.loaded / event.total);
};
xhr.onerror = () => {
reject(`${xhr.status} ${xhr.statusText}`);
};
});
}
function setButtonState({ id, enabled }) {
const button = document.getElementById(`${id}-button`);
button.disabled = !enabled;
return button;
}
class BlobStore {
constructor() {
this.db = null;
}
async _wrapReq(request, onUpgrade = null) {
return new Promise((resolve, reject) => {
request.onsuccess = () => {
resolve(request.result);
};
request.oncomplete = () => {
resolve(request.result);
};
request.onerror = (event) => {
reject(event);
};
if (onUpgrade !== null) {
request.onupgradeneeded = onUpgrade;
}
});
}
async init() {
if (this.db === null) {
this.db = await this._wrapReq(
indexedDB.open(CACHE_DB_NAME, CACHE_DB_VERSION),
(event) => {
let db = event.target.result;
db.createObjectStore("files", { keyPath: "name" });
/* no index needed for such a small database */
}
);
}
}
async saveFile(name, blob) {
await this._wrapReq(
this.db.transaction(["files"], "readwrite").objectStore("files").add({
name: name,
blob: blob,
})
);
}
async loadFile(name) {
try {
let obj = await this._wrapReq(
this.db.transaction("files").objectStore("files").get(name)
);
return obj.blob;
} catch {
return null;
}
}
async close() {
this.db.close();
}
async download(url, onProgress = () => {}) {
let filename = url.split("/").pop();
let blob = await this.loadFile(filename);
if (blob === null) {
console.log(`Downloading ${url}`);
let blob = await fetchBlobWithProgress(url, onProgress);
console.log("File downloaded, saving...");
await this.saveFile(filename, blob);
console.log("File saved");
} else {
console.log(
`Loaded ${filename} from blob store, skipping download`
);
}
return blob;
}
}
class ButtonController {
#map;
constructor() {
this.#map = new Map();
}
setEnabled(...ids) {
ids.forEach((id) => {
// Only enable button if it won't be disabled.
if (!this.#map.has(id)) {
this.#map.set(id, /* enabled = */ true);
}
});
}
setDisabled(...ids) {
ids.forEach((id) => this.#map.set(id, /* enabled = */ false));
}
applyState() {
this.#map.forEach((enabled, id) => {
setButtonState({ id, enabled });
});
this.#map.clear();
}
}
let installerState = 0;
let device = new fastboot.FastbootDevice();
let blobStore = new BlobStore();
let buttonController = new ButtonController();
async function ensureConnected(setProgress) {
if (!device.isConnected) {
setProgress("Connecting to device...");
await device.connect();
}
}
async function unlockBootloader(setProgress) {
await ensureConnected(setProgress);
// Trying to unlock when the bootloader is already unlocked results in a FAIL,
// so don't try to do it.
if (await device.getVariable("unlocked") === "yes") {
return "Bootloader is already unlocked.";
}
setProgress("Unlocking bootloader...");
try {
await device.runCommand("flashing unlock");
} catch (error) {
// FAIL = user rejected unlock
if (error instanceof fastboot.FastbootError && error.status === "FAIL") {
throw new Error("Bootloader was not unlocked, please try again!");
} else {
throw error;
}
}
return "Bootloader unlocking triggered successfully.";
}
const supportedDevices = ["tegu", "comet", "komodo", "caiman", "tokay", "akita", "husky", "shiba", "felix", "tangorpro", "lynx", "cheetah", "panther", "bluejay", "raven", "oriole", "barbet", "redfin", "bramble", "sunfish", "coral", "flame"];
const legacyQualcommDevices = ["sunfish", "coral", "flame"];
const day1SnapshotCancelDevices = ["tegu", "comet", "komodo", "caiman", "tokay", "akita", "husky", "shiba", "felix", "tangorpro", "lynx", "cheetah", "panther", "bluejay", "raven", "oriole", "barbet", "redfin", "bramble"];
function hasOptimizedFactoryImage(product) {
return !legacyQualcommDevices.includes(product);
}
async function getLatestRelease() {
let product = await device.getVariable("product");
if (!supportedDevices.includes(product)) {
throw new Error(`device model (${product}) is not supported by the GrapheneOS web installer`);
}
let metadataResp = await fetch(`${RELEASES_URL}/${product}-stable`);
let metadata = await metadataResp.text();
let releaseId = metadata.split(" ")[0];
return [`${product}-${hasOptimizedFactoryImage(product) ? "install" : "factory"}-${releaseId}.zip`, product];
}
async function downloadRelease(setProgress) {
await requestWakeLock();
await ensureConnected(setProgress);
setProgress("Finding latest release...");
let [latestZip,] = await getLatestRelease();
// Download and cache the zip as a blob
setInstallerState({ state: InstallerState.DOWNLOADING_RELEASE, active: true });
setProgress(`Downloading ${latestZip}...`);
await blobStore.init();
try {
await blobStore.download(`${RELEASES_URL}/${latestZip}`, (progress) => {
setProgress(`Downloading ${latestZip}...`, progress);
});
} finally {
setInstallerState({ state: InstallerState.DOWNLOADING_RELEASE, active: false });
await releaseWakeLock();
}
setProgress(`Downloaded ${latestZip} release.`, 1.0);
}
async function reconnectCallback() {
let statusField = document.getElementById("flash-release-status");
statusField.textContent =
"To continue flashing, reconnect the device by tapping here:";
let reconnectButton = document.getElementById("flash-reconnect-button");
let progressBar = document.getElementById("flash-release-progress");
// Hide progress bar while waiting for reconnection
progressBar.hidden = true;
reconnectButton.hidden = false;
reconnectButton.onclick = async () => {
await device.connect();
reconnectButton.hidden = true;
progressBar.hidden = false;
};
}
async function flashRelease(setProgress) {
await requestWakeLock();
await ensureConnected(setProgress);
// Need to do this again because the user may not have clicked download if
// it was cached
setProgress("Finding latest release...");
let [latestZip, product] = await getLatestRelease();
await blobStore.init();
let blob = await blobStore.loadFile(latestZip);
if (blob === null) {
throw new Error("You need to download a release first!");
}
setProgress("Cancelling any pending OTAs...");
// Cancel snapshot update if in progress on devices which support it on all bootloader versions
if (day1SnapshotCancelDevices.includes(product)) {
let snapshotStatus = await device.getVariable("snapshot-update-status");
if (snapshotStatus !== null && snapshotStatus !== "none") {
await device.runCommand("snapshot-update:cancel");
}
}
setProgress("Flashing release...");
setInstallerState({ state: InstallerState.INSTALLING_RELEASE, active: true });
try {
await device.flashFactoryZip(blob, true, reconnectCallback,
(action, item, progress) => {
let userAction = fastboot.USER_ACTION_MAP[action];
let userItem = item === "avb_custom_key" ? "verified boot key" : item;
setProgress(`${userAction} ${userItem}...`, progress);
}
);
if (legacyQualcommDevices.includes(product)) {
setProgress("Disabling UART...");
// See https://android.googlesource.com/platform/system/core/+/eclair-release/fastboot/fastboot.c#532
// for context as to why the trailing space is needed.
await device.runCommand("oem uart disable ");
setProgress("Erasing apdp...");
// Both slots are wiped as even apdp on an inactive slot will modify /proc/cmdline
await device.runCommand("erase:apdp_a");
await device.runCommand("erase:apdp_b");
setProgress("Erasing msadp...");
await device.runCommand("erase:msadp_a");
await device.runCommand("erase:msadp_b");
}
} finally {
setInstallerState({ state: InstallerState.INSTALLING_RELEASE, active: false });
await releaseWakeLock();
}
return `Flashed ${latestZip} to device.`;
}
async function eraseNonStockKey(setProgress) {
await ensureConnected(setProgress);
setProgress("Erasing key...");
try {
await device.runCommand("erase:avb_custom_key");
} catch (error) {
console.log(error);
throw error;
}
return "Key erased.";
}
async function lockBootloader(setProgress) {
await ensureConnected(setProgress);
setProgress("Locking bootloader...");
try {
await device.runCommand("flashing lock");
} catch (error) {
// FAIL = user rejected lock
if (error instanceof fastboot.FastbootError && error.status === "FAIL") {
throw new Error("Bootloader was not locked, please try again!");
} else {
throw error;
}
}
return "Bootloader locking triggered successfully.";
}
function addButtonHook(id, callback) {
let statusContainer = document.getElementById(`${id}-status-container`);
let statusField = document.getElementById(`${id}-status`);
let progressBar = document.getElementById(`${id}-progress`);
let statusCallback = (status, progress) => {
if (statusContainer !== null) {
statusContainer.hidden = false;
}
statusField.className = "";
statusField.textContent = status;
if (progress !== undefined) {
progressBar.hidden = false;
progressBar.value = progress;
}
};
let button = setButtonState({ id, enabled: true });
button.onclick = async () => {
try {
let finalStatus = await callback(statusCallback);
if (finalStatus !== undefined) {
statusCallback(finalStatus);
}
} catch (error) {
statusCallback(`Error: ${error.message}`);
statusField.className = "error-text";
await releaseWakeLock();
// Rethrow the error so it shows up in the console
throw error;
}
};
}
function setInstallerState({ state, active }) {
if (active) {
installerState |= state;
} else {
installerState &= ~state;
}
invalidateInstallerState();
}
function isInstallerStateActive(state) {
return (installerState & state) === state;
}
function invalidateInstallerState() {
if (isInstallerStateActive(InstallerState.DOWNLOADING_RELEASE)) {
buttonController.setDisabled(Buttons.DOWNLOAD_RELEASE);
} else {
buttonController.setEnabled(Buttons.DOWNLOAD_RELEASE);
}
let disableWhileInstalling = [
Buttons.DOWNLOAD_RELEASE,
Buttons.FLASH_RELEASE,
Buttons.LOCK_BOOTLOADER,
Buttons.REMOVE_CUSTOM_KEY,
];
if (isInstallerStateActive(InstallerState.INSTALLING_RELEASE)) {
buttonController.setDisabled(...disableWhileInstalling);
} else {
buttonController.setEnabled(...disableWhileInstalling);
}
buttonController.applyState();
}
function safeToLeave() {
return installerState === 0;
}
// This doesn't really hurt, and because this page is exclusively for web install,
// we can tolerate extra logging in the console in case something goes wrong.
fastboot.setDebugLevel(2);
fastboot.configureZip({
workerScripts: {
inflate: ["/js/fastboot/ffe7e270/vendor/z-worker-pako.js", "pako_inflate.min.js"],
},
});
if ("usb" in navigator) {
addButtonHook(Buttons.UNLOCK_BOOTLOADER, unlockBootloader);
addButtonHook(Buttons.DOWNLOAD_RELEASE, downloadRelease);
addButtonHook(Buttons.FLASH_RELEASE, flashRelease);
addButtonHook(Buttons.LOCK_BOOTLOADER, lockBootloader);
addButtonHook(Buttons.REMOVE_CUSTOM_KEY, eraseNonStockKey);
} else {
console.log("WebUSB unavailable");
}
// This will create an alert box to stop the user from leaving the page during actions
window.addEventListener("beforeunload", event => {
if (!safeToLeave()) {
console.log("User tried to leave the page whilst unsafe to leave!");
event.returnValue = "";
}
});
// @license-end

25
static/laptop.svg Normal file
View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="1536"
height="912"
version="1.1"
id="svg2"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs2" />
<path
id="path1"
d="M 141,0 C 116,0 96,20 96,45 v 750 c 0,25 20,45 45,45 H 33 C 15,840 0,855 0,873 v 6 c 0,18 15,33 33,33 h 1470 c 18,0 33,-15 33,-33 v -6 c 0,-18 -15,-33 -33,-33 h -108 c 25,0 45,-20 45,-45 V 45 c 0,-25 -20,-45 -45,-45 z m 28.19922,32 H 1366.8008 C 1389.6256,32 1408,50.374418 1408,73.199219 V 758.80078 C 1408,781.62558 1389.6256,800 1366.8008,800 H 169.19922 C 146.37442,800 128,781.62558 128,758.80078 V 73.199219 C 128,50.374418 146.37442,32 169.19922,32 Z"
style="fill:#b3b3b3" />
<rect
width="384"
height="16"
x="576"
y="-856"
fill="#a5b5d3"
ry="8"
transform="scale(1,-1)"
id="rect2"
style="fill:#808080" />
</svg>

After

Width:  |  Height:  |  Size: 932 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

@ -303,7 +303,7 @@ main.normalize {
position: relative;
}
.phone-logo-img {
.laptop-logo-img {
position: absolute;
top: 48%;
left: 50%;
@ -498,11 +498,11 @@ details[open] summary {
border-color: #222;
}
.phone-img {
.laptop-img {
filter: brightness(0.87);
}
.phone-logo-img {
.laptop-logo-img {
filter: invert(87%);
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

BIN
static/oneko.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 48 KiB

51
static/package.html Normal file
View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="en" prefix="og: https://ogp.me/ns#">
<head>
<meta charset="utf-8"/>
<title>Package | Hakurei</title>
<meta name="description" content="Overview of the planterette package manager and its interactions with Hakurei."/>
<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, viewport-fit=cover"/>
<meta property="og:title" content="Planterette packaging overview"/>
<meta property="og:description" content="Overview of the planterette package manager and its interactions with Hakurei."/>
<meta property="og:type" content="website"/>
<meta property="og:image" content="https://hakurei.app/opengraph.png"/>
<meta property="og:image:width" content="512"/>
<meta property="og:image:height" content="512"/>
<meta property="og:image:alt" content="Hakurei logo"/>
<meta property="og:site_name" content="Hakurei"/>
<meta property="og:url" content="https://hakurei.app/package.html"/>
<link rel="canonical" href="https://hakurei.app/package.html"/>
<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://port.mk/@hakurei"/>
</head>
<body>
{% with current_page="package" %}
{% include "header.html" %}
{% endwith %}
<main id="package">
<h1><a href="#package">Package management</a></h1>
<p>Planterette is an experimental Android-like package manager providing
fully self-contained apps running in Hakurei containers. The planterette
software is not part of Hakurei and configures Hakurei through its public API.</p>
<p>Planterette is currently in a very early stage of development, and using it for
anything beyond experimentation or development is not recommended.</p>
<p>If you wish to work on planterette, its source code can be found under
<code>cmd/planterette</code> of Hakurei's source tree. This is subject to change.
The Nix package builder can be accessed via the <code>buildPackage</code> output
of the Nix flake, however this is pending replacement.</p>
</main>
{% include "footer.html" %}
</body>
</html>

View File

@ -1,42 +0,0 @@
<!DOCTYPE html>
<html lang="en" prefix="og: https://ogp.me/ns#">
<head>
<meta charset="utf-8"/>
<title>PDF Viewer privacy policy | GrapheneOS</title>
<meta name="description" content="Privacy policy for the GrapheneOS PDF Viewer app."/>
<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, viewport-fit=cover"/>
<meta name="twitter:site" content="@GrapheneOS"/>
<meta name="twitter:creator" content="@GrapheneOS"/>
<meta property="og:title" content="PDF Viewer privacy policy"/>
<meta property="og:description" content="Privacy policy for the GrapheneOS PDF Viewer app."/>
<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/pdfviewer-privacy-policy"/>
<link rel="canonical" href="https://grapheneos.org/pdfviewer-privacy-policy"/>
<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"/>
</head>
<body>
{% include "header.html" %}
<main id="pdfviewer-privacy-policy">
<h1><a href="#pdfviewer-privacy-policy">PDF Viewer privacy policy</a></h1>
<p>This app does not use any sensitive permissions, makes no internet connections and
does not store any data other than preferences.</p>
<p>See the <a href="https://github.com/GrapheneOS/PdfViewer">project's page on GitHub</a> for more information.</p>
</main>
{% include "footer.html" %}
</body>
</html>

View File

@ -1 +0,0 @@
<svg width="276" height="579" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M18 0C9.163 0 2 7.163 2 16v547c0 8.837 7.163 16 16 16h240c8.837 0 16-7.163 16-16V16c0-8.837-7.163-16-16-16H18Zm2 6C11.163 6 4 13.163 4 22v537c0 8.837 7.163 16 16 16h236c8.837 0 16-7.163 16-16V22c0-8.837-7.163-16-16-16H20Z" fill="#979A97"/><path fill-rule="evenodd" clip-rule="evenodd" d="M20 3C11.163 3 4 10.164 4 19v541c0 8.837 7.163 16 16 16h236c8.837 0 16-7.163 16-16V19c0-8.837-7.163-16-16-16H20Zm7 7c-8.837 0-16 7.163-16 16v527c0 8.837 7.163 16 16 16h222c8.837 0 16-7.163 16-16V26c0-8.837-7.163-16-16-16H27Z" fill="#000"/><g filter="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M20 4C11.163 4 4 11.164 4 20v539c0 6.665 4.076 12.379 9.871 14.784C9.16 571 6 565.869 6 560V20c0-8.836 7.163-16 16-16h-2Zm234 0c8.837 0 16 7.163 16 16v540c0 5.869-3.16 11-7.871 13.784C267.924 571.379 272 565.665 272 559V20c0-8.837-7.163-16-16-16h-2Z" fill="#fff"/></g><circle cx="138.5" cy="26.5" r="7.5" fill="#000"/><circle cx="138.5" cy="26.5" r="5.5" fill="#0F1415"/><circle cx="138.5" cy="26.5" r="2.5" fill="#151E1E"/><circle cx="139.5" cy="27.5" r="1.5" fill="#1B2123"/><circle cx="139.5" cy="27.5" r=".5" fill="#3E4749"/><path d="M273 181a1 1 0 0 1 1-1h1a1 1 0 0 1 1 1v33a1 1 0 0 1-1 1h-1a1 1 0 0 1-1-1v-33ZM273 252a1 1 0 0 1 1-1h1a1 1 0 0 1 1 1v68a1 1 0 0 1-1 1h-1a1 1 0 0 1-1-1v-68Z" fill="#767676"/><defs><filter id="a" x="0" y="0" width="276" height="577.784" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur stdDeviation="2" result="effect1_foregroundBlur_6_67"/></filter></defs></svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,2 +1,2 @@
User-agent: *
Sitemap: https://grapheneos.org/sitemap.xml
Sitemap: https://hakurei.app/sitemap.xml

View File

@ -1,315 +0,0 @@
<!DOCTYPE html>
<html lang="en" prefix="og: https://ogp.me/ns#">
<head>
<meta charset="utf-8"/>
<title>Source code | GrapheneOS</title>
<meta name="description" content="Source code for GrapheneOS."/>
<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, viewport-fit=cover"/>
<meta name="twitter:site" content="@GrapheneOS"/>
<meta name="twitter:creator" content="@GrapheneOS"/>
<meta property="og:title" content="GrapheneOS source code"/>
<meta property="og:description" content="Source code for GrapheneOS."/>
<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/source"/>
<link rel="canonical" href="https://grapheneos.org/source"/>
<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"/>
</head>
<body>
{% with current_page="source" %}
{% include "header.html" %}
{% endwith %}
<main id="source">
<h1><a href="#source">Source code</a></h1>
<p>GrapheneOS is an <a href="https://opensource.org/osd">open source</a> project with
an open development process.</p>
<p>The GrapheneOS sources are hosted in the
<a href="https://github.com/GrapheneOS">GrapheneOS organization on GitHub</a>. Since
there are many repositories, this page aims to provide a guide for it. See the
<a href="/contact#reporting-issues">reporting issues section on the contact page</a>
for an comparable overview of where issues should be filed.</p>
<nav id="table-of-contents">
<h2><a href="#table-of-contents">Table of contents</a></h2>
<ul>
<li><a href="#grapheneos">GrapheneOS</a></li>
<li><a href="#standalone-apps">Standalone apps</a></li>
<li><a href="#services">Services</a></li>
<li><a href="#utilities">Utilities</a></li>
<li><a href="#archive">Archive</a></li>
</ul>
</nav>
<section id="grapheneos">
<h2><a href="#grapheneos">GrapheneOS</a></h2>
<p>The operating system source tree includes hundreds of repositories. Many of
these are only used for debugging, testing or development and are not actually
part of what gets used for building a production release. The manifest repository
references all of these. Most of these are used unmodified from the Android Open
Source Project (AOSP). A few dozen of the repositories including most of the core
OS are either forked from AOSP or are unique to GrapheneOS.</p>
<p>The operating system has a unified build system, but some components like
Chromium are too complex to fit into it so they're included as prebuilts instead
of porting them to the AOSP build system. This is also done for developer
convenience and bootstrapping, to avoid needing to build all the native /
cross-compilation toolchains for each host and target platform combination, etc.
The prebuilts can all be built from source if desired. The build instructions will
be expanded to cover all of this in the future.</p>
<p>For a full list of the repositories in the OS source tree, look at the
<a href="https://github.com/GrapheneOS/platform_manifest/blob/13/default.xml">default.xml
list in the manifest repository</a>.</p>
<p>GrapheneOS forks of AOSP source tree repositories:</p>
<ul>
<li><a href="https://github.com/GrapheneOS/device_common">device_common</a></li>
<li><a href="https://github.com/GrapheneOS/device_generic_goldfish">device_generic_goldfish</a></li>
<li><a href="https://github.com/GrapheneOS/device_google_akita">device_google_akita</a></li>
<li><a href="https://github.com/GrapheneOS/device_google_bluejay">device_google_bluejay</a></li>
<li><a href="https://github.com/GrapheneOS/device_google_caimito">device_google_caimito</a></li>
<li><a href="https://github.com/GrapheneOS/device_google_comet">device_google_comet</a></li>
<li><a href="https://github.com/GrapheneOS/device_google_felix">device_google_felix</a></li>
<li><a href="https://github.com/GrapheneOS/device_google_gs-common">device_google_gs-common</a></li>
<li><a href="https://github.com/GrapheneOS/device_google_gs101">device_google_gs101</a></li>
<li><a href="https://github.com/GrapheneOS/device_google_gs101-sepolicy">device_google_gs101-sepolicy</a></li>
<li><a href="https://github.com/GrapheneOS/device_google_gs201">device_google_gs201</a></li>
<li><a href="https://github.com/GrapheneOS/device_google_gs201-sepolicy">device_google_gs201-sepolicy</a></li>
<li><a href="https://github.com/GrapheneOS/device_google_lynx">device_google_lynx</a></li>
<li><a href="https://github.com/GrapheneOS/device_google_pantah">device_google_pantah</a></li>
<li><a href="https://github.com/GrapheneOS/device_google_raviole">device_google_raviole</a></li>
<li><a href="https://github.com/GrapheneOS/device_google_shusky">device_google_shusky</a></li>
<li><a href="https://github.com/GrapheneOS/device_google_tangorpro">device_google_tangorpro</a></li>
<li><a href="https://github.com/GrapheneOS/device_google_tegu">device_google_tegu</a></li>
<li><a href="https://github.com/GrapheneOS/device_google_zuma">device_google_zuma</a></li>
<li><a href="https://github.com/GrapheneOS/device_google_zuma-sepolicy">device_google_zuma-sepolicy</a></li>
<li><a href="https://github.com/GrapheneOS/device_google_zumapro">device_google_zumapro</a></li>
<li><a href="https://github.com/GrapheneOS/device_google_zumapro-sepolicy">device_google_zumapro-sepolicy</a></li>
<li><a href="https://github.com/GrapheneOS/kernel_configs">kernel_configs</a>: Base and recommended kernel configurations. The base configurations are enforced by the VTS and are modified to permit GrapheneOS changes.</li>
<li><a href="https://github.com/GrapheneOS/platform_art">platform_art</a></li>
<li><a href="https://github.com/GrapheneOS/platform_bionic">platform_bionic</a></li>
<li><a href="https://github.com/GrapheneOS/platform_bootable_recovery">platform_bootable_recovery</a></li>
<li><a href="https://github.com/GrapheneOS/platform_build">platform_build</a></li>
<li><a href="https://github.com/GrapheneOS/platform_build_release">platform_build_release</a></li>
<li><a href="https://github.com/GrapheneOS/platform_build_soong">platform_build_soong</a></li>
<li><a href="https://github.com/GrapheneOS/platform_development">platform_development</a></li>
<li><a href="https://github.com/GrapheneOS/platform_external_boringssl">platform_external_boringssl</a></li>
<li><a href="https://github.com/GrapheneOS/platform_external_conscrypt">platform_external_conscrypt</a></li>
<li><a href="https://github.com/GrapheneOS/platform_external_selinux">platform_external_selinux</a></li>
<li><a href="https://github.com/GrapheneOS/platform_frameworks_base">platform_frameworks_base</a></li>
<li><a href="https://github.com/GrapheneOS/platform_frameworks_libs_systemui">platform_frameworks_libs_systemui</a></li>
<li><a href="https://github.com/GrapheneOS/platform_frameworks_native">platform_frameworks_native</a></li>
<li><a href="https://github.com/GrapheneOS/platform_frameworks_opt_net_wifi">platform_frameworks_opt_net_wifi</a></li>
<li><a href="https://github.com/GrapheneOS/platform_frameworks_opt_telephony">platform_frameworks_opt_telephony</a></li>
<li><a href="https://github.com/GrapheneOS/platform_hardware_google_pixel">platform_hardware_google_pixel</a></li>
<li><a href="https://github.com/GrapheneOS/platform_hardware_google_pixel-sepolicy">platform_hardware_google_pixel-sepolicy</a></li>
<li><a href="https://github.com/GrapheneOS/platform_hardware_interfaces">platform_hardware_interfaces</a></li>
<li><a href="https://github.com/GrapheneOS/platform_libcore">platform_libcore</a></li>
<li><a href="https://github.com/GrapheneOS/platform_manifest">platform_manifest</a>: Manifest for OS repositories</li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_Calendar">platform_packages_apps_Calendar</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_CellBroadcastReceiver">platform_packages_apps_CellBroadcastReceiver</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_Contacts">platform_packages_apps_Contacts</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_DeskClock">platform_packages_apps_DeskClock</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_Dialer">platform_packages_apps_Dialer</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_DocumentsUI">platform_packages_apps_DocumentsUI</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_EmergencyInfo">platform_packages_apps_EmergencyInfo</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_Gallery2">platform_packages_apps_Gallery2</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_Launcher3">platform_packages_apps_Launcher3</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_Nfc">platform_packages_apps_Nfc</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_Settings">platform_packages_apps_Settings</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_SettingsIntelligence">platform_packages_apps_SettingsIntelligence</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_StorageManager">platform_packages_apps_StorageManager</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_ThemePicker">platform_packages_apps_ThemePicker</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_WallpaperPicker2">platform_packages_apps_WallpaperPicker2</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_inputmethods_LatinIME">platform_packages_inputmethods_LatinIME</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_modules_adb">platform_packages_modules_adb</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_modules_AppSearch">platform_packages_modules_AppSearch</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_modules_Bluetooth">platform_packages_modules_Bluetooth</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_modules_common">platform_packages_modules_common</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_modules_ConfigInfrastructure">platform_packages_modules_ConfigInfrastructure</a></li>
<li><a href="https://gitlab.com/grapheneos/platform_packages_modules_Connectivity">platform_packages_modules_Connectivity</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_modules_DnsResolver">platform_packages_modules_DnsResolver</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_modules_HealthFitness">platform_packages_modules_HealthFitness</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_modules_NetworkStack">platform_packages_modules_NetworkStack</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_modules_Permission">platform_packages_modules_Permission</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_modules_RemoteKeyProvisioning">platform_packages_modules_RemoteKeyProvisioning</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_modules_Uwb">platform_packages_modules_Uwb</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_modules_Virtualization">platform_packages_modules_Virtualization</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_modules_Wifi">platform_packages_modules_Wifi</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_providers_ContactsProvider">platform_packages_providers_ContactsProvider</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_providers_DownloadProvider">platform_packages_providers_DownloadProvider</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_providers_MediaProvider">platform_packages_providers_MediaProvider</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_services_Mms">platform_packages_services_Mms</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_services_Telecomm">platform_packages_services_Telecomm</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_services_Telephony">platform_packages_services_Telephony</a></li>
<li><a href="https://github.com/GrapheneOS/platform_system_core">platform_system_core</a></li>
<li><a href="https://github.com/GrapheneOS/platform_system_extras">platform_system_extras</a></li>
<li><a href="https://github.com/GrapheneOS/platform_system_librustutils">platform_system_librustutils</a></li>
<li><a href="https://github.com/GrapheneOS/platform_system_logging">platform_system_logging</a></li>
<li><a href="https://github.com/GrapheneOS/platform_system_netd">platform_system_netd</a></li>
<li><a href="https://github.com/GrapheneOS/platform_system_sepolicy">platform_system_sepolicy</a></li>
<li><a href="https://github.com/GrapheneOS/platform_system_vold">platform_system_vold</a></li>
<li><a href="https://github.com/GrapheneOS/platform_tools_metalava">platform_tools_metalava</a></li>
</ul>
<p>GrapheneOS forks of AOSP kernel prebuilt repositories with the builds replaced with the GrapheneOS kernels built from the source repositories listed in the next section:</p>
<ul>
<li><a href="https://github.com/GrapheneOS/device_google_raviole-kernels_6.1">device_google_raviole-kernels_6.1</a>: Pixel 6 and Pixel 6 Pro kernel prebuilts.</li>
<li><a href="https://github.com/GrapheneOS/device_google_bluejay-kernels_6.1">device_google_bluejay-kernels_6.1</a>: Pixel 6a kernel prebuilts.</li>
<li><a href="https://github.com/GrapheneOS/device_google_pantah-kernels_6.1">device_google_pantah-kernels_6.1</a>: Pixel 7 and Pixel 7 Pro kernel prebuilts.</li>
<li><a href="https://github.com/GrapheneOS/device_google_lynx-kernels_6.1">device_google_lynx-kernels_6.1</a>: Pixel 7a kernel prebuilts.</li>
<li><a href="https://github.com/GrapheneOS/device_google_tangorpro-kernels_6.1">device_google_tangorpro-kernels_6.1</a>: Pixel Tablet kernel prebuilts.</li>
<li><a href="https://github.com/GrapheneOS/device_google_felix-kernels_6.1">device_google_felix-kernels_6.1</a>: Pixel Fold kernel prebuilts.</li>
<li><a href="https://github.com/GrapheneOS/device_google_shusky-kernels_6.1">device_google_shusky-kernels_6.1</a>: Pixel 8 and Pixel 8 Pro kernel prebuilts.</li>
<li><a href="https://github.com/GrapheneOS/device_google_akita-kernels_6.1">device_google_akita-kernels_6.1</a>: Pixel 8a kernel prebuilts.</li>
<li><a href="https://github.com/GrapheneOS/device_google_caimito-kernels_6.1">device_google_caimito-kernels_6.1</a>: Pixel 9, Pixel 9 Pro and Pixel 9 Pro XL kernel prebuilts.</li>
<li><a href="https://github.com/GrapheneOS/device_google_comet-kernels_6.1">device_google_comet-kernels_6.1</a>: Pixel 9 Pro Fold kernel prebuilts.</li>
<li><a href="https://github.com/GrapheneOS/device_google_tegu-kernels_6.1">device_google_tegu-kernels_6.1</a>: Pixel 9a kernel prebuilts.</li>
</ul>
<p>GrapheneOS forks of AOSP kernel repositories:</p>
<ul>
<li><a href="https://github.com/GrapheneOS/kernel_manifest-6.1">kernel_manifest-6.1</a>: Kernel manifest for the Generic Linux 6.1 kernel.</li>
<li><a href="https://github.com/GrapheneOS/kernel_common-6.1">kernel_common-6.1</a>: Linux 6.1 LTS branch.</li>
<li><a href="https://github.com/GrapheneOS/kernel_manifest-6.6">kernel_manifest-6.6</a>: Kernel manifest for the Generic Linux 6.6 kernel.</li>
<li><a href="https://github.com/GrapheneOS/kernel_common-6.6">kernel_common-6.6</a>: Linux 6.6 LTS branch.</li>
<li><a href="https://github.com/GrapheneOS/kernel_manifest-6.12">kernel_manifest-6.12</a>: Kernel manifest for the Generic Linux 6.12 kernel.</li>
<li><a href="https://github.com/GrapheneOS/kernel_common-6.12">kernel_common-6.12</a>: Linux 6.12 LTS branch.</li>
<li><a href="https://github.com/GrapheneOS/kernel_manifest-pixel">kernel_manifest-pixel</a>: Kernel manifest for the Pixel 6, Pixel 6 Pro, Pixel 6a, Pixel 7, Pixel 7 Pro, Pixel 7a, Pixel Tablet, Pixel Fold, Pixel 8, Pixel 8 Pro, Pixel 8a, Pixel 9, Pixel 9 Pro, Pixel 9 Pro XL and Pixel 9 Pro Fold.</li>
<li><a href="https://github.com/GrapheneOS/kernel_build">kernel_build</a>: Kernel build system for the Pixel 6, Pixel 6 Pro, Pixel 6a, Pixel 7, Pixel 7 Pro, Pixel 7a, Pixel Tablet, Pixel Fold, Pixel 8, Pixel 8 Pro, Pixel 8a, Pixel 9, Pixel 9 Pro, Pixel 9 Pro XL and Pixel 9 Pro Fold.</li>
<li><a href="https://github.com/GrapheneOS/kernel_devices_google_raviole">kernel_devices_google_raviole</a>: Kernel setup for the Pixel 6 and Pixel 6 Pro.</li>
<li><a href="https://github.com/GrapheneOS/kernel_devices_google_bluejay">kernel_devices_google_bluejay</a>: Kernel setup for the Pixel 6a.</li>
<li><a href="https://github.com/GrapheneOS/kernel_devices_google_pantah">kernel_devices_google_pantah</a>: Kernel setup for the Pixel 7 and Pixel 7 Pro.</li>
<li><a href="https://github.com/GrapheneOS/kernel_devices_google_lynx">kernel_devices_google_lynx</a>: Kernel setup for the Pixel 7a.</li>
<li><a href="https://github.com/GrapheneOS/kernel_devices_google_tangorpro">kernel_devices_google_tangorpro</a>: Kernel setup for the Pixel Tablet.</li>
<li><a href="https://github.com/GrapheneOS/kernel_devices_google_felix">kernel_devices_google_felix</a>: Kernel setup for the Pixel Fold.</li>
<li><a href="https://github.com/GrapheneOS/kernel_devices_google_akita">kernel_devices_google_akita</a>: Kernel setup for the Pixel 8a.</li>
<li><a href="https://github.com/GrapheneOS/kernel_devices_google_shusky">kernel_devices_google_shusky</a>: Kernel setup for the Pixel 8 and Pixel 8 Pro.</li>
<li><a href="https://github.com/GrapheneOS/kernel_devices_google_caimito">kernel_devices_google_caimito</a>: Kernel setup for the Pixel 9, Pixel 9 Pro and Pixel 9 Pro XL.</li>
<li><a href="https://github.com/GrapheneOS/kernel_devices_google_comet">kernel_devices_google_comet</a>: Kernel setup for the Pixel 9 Pro Fold.</li>
<li><a href="https://github.com/GrapheneOS/kernel_devices_google_tegu">kernel_devices_google_tegu</a>: Kernel setup for the Pixel 9a.</li>
<li><a href="https://github.com/GrapheneOS/kernel_google-modules_amplifiers">kernel_google-modules_amplifiers</a>: Kernel amplifier drivers for the Pixel 6, Pixel 6 Pro, Pixel 6a, Pixel 7, Pixel 7 Pro, Pixel 7a, Pixel Tablet, Pixel Fold, Pixel 8, Pixel 8 Pro, Pixel 8a, Pixel 9, Pixel 9 Pro, Pixel 9 Pro XL and Pixel 9 Pro Fold.</li>
<li><a href="https://github.com/GrapheneOS/kernel_google-modules_bms">kernel_google-modules_bms</a>: Kernel Battery Management System (BMS) driver for the Pixel 6, Pixel 6 Pro, Pixel 6a, Pixel 7, Pixel 7 Pro, Pixel 7a, Pixel Tablet, Pixel Fold, Pixel 8, Pixel 8 Pro, Pixel 8a, Pixel 9, Pixel 9 Pro, Pixel 9 Pro XL and Pixel 9 Pro Fold.</li>
<li><a href="https://github.com/GrapheneOS/kernel_google-modules_edgetpu_rio">kernel_google-modules_edgetpu_rio</a>: Kernel TPU driver for the Pixel 8, Pixel 8 Pro, Pixel 8a, Pixel 9, Pixel 9 Pro, Pixel 9 Pro XL and Pixel 9 Pro Fold.</li>
<li><a href="https://github.com/GrapheneOS/kernel_google-modules_gxp_gs201">kernel_google-modules_gxp_gs201</a>: Kernel GXP driver for the Pixel 7, Pixel 7 Pro, Pixel 7a, Pixel Tablet and Pixel Fold.</li>
<li><a href="https://github.com/GrapheneOS/kernel_google-modules_gxp_zuma">kernel_google-modules_gxp_zuma</a>: Kernel GXP driver for the Pixel 8, Pixel 8 Pro, Pixel 8a, Pixel 9, Pixel 9 Pro, Pixel 9 Pro XL and Pixel 9 Pro Fold.</li>
<li><a href="https://github.com/GrapheneOS/kernel_google-modules_power_reset">kernel_google-modules_power_reset</a>: Kernel reset driver for the Pixel 6, Pixel 6 Pro, Pixel 6a, Pixel 7, Pixel 7 Pro, Pixel 7a, Pixel Tablet, Pixel Fold, Pixel 8, Pixel 8 Pro, Pixel 8a, Pixel 9, Pixel 9 Pro, Pixel 9 Pro XL and Pixel 9 Pro Fold.</li>
<li><a href="https://github.com/GrapheneOS/kernel_google-modules_soc_gs">kernel_google-modules_soc_gs</a>: Kernel SoC driver for the Pixel 6, Pixel 6 Pro, Pixel 6a, Pixel 7, Pixel 7 Pro, Pixel 7a, Pixel Tablet, Pixel Fold, Pixel 8, Pixel 8 Pro, Pixel 8a, Pixel 9, Pixel 9 Pro, Pixel 9 Pro XL and Pixel 9 Pro Fold.</li>
<li><a href="https://github.com/GrapheneOS/kernel_google-modules_wlan_bcmdhd_bcm4383">kernel_google-modules_wlan_bcmdhd_bcm4383</a>: Kernel Wi-Fi/Bluetooth driver for the Pixel 8a.</li>
<li><a href="https://github.com/GrapheneOS/kernel_google-modules_wlan_bcmdhd_bcm4389">kernel_google-modules_wlan_bcmdhd_bcm4389</a>: Kernel Wi-Fi/Bluetooth driver for the Pixel 6, Pixel 6 Pro, Pixel 6a, Pixel 7, Pixel 7 Pro and Pixel Fold.</li>
<li><a href="https://github.com/GrapheneOS/kernel_google-modules_wlan_bcmdhd_bcm4390">kernel_google-modules_wlan_bcmdhd_bcm4390</a>: Kernel Wi-Fi/Bluetooth driver for the Pixel 9, Pixel 9 Pro, Pixel 9 Pro XL and Pixel 9 Pro Fold.</li>
<li><a href="https://github.com/GrapheneOS/kernel_google-modules_wlan_bcmdhd_bcm4398">kernel_google-modules_wlan_bcmdhd_bcm4398</a>: Kernel Wi-Fi/Bluetooth driver for the Pixel 8 and Pixel 8 Pro.</li>
<li><a href="https://github.com/GrapheneOS/kernel_google-modules_wlan_syna_dhd43752p">kernel_google-modules_wlan_syna_dhd43752p</a>: Kernel Wi-Fi/Bluetooth driver for the Pixel Tablet.</li>
</ul>
<p>Repositories added by GrapheneOS:</p>
<ul>
<li><a href="https://github.com/GrapheneOS/adevtool">adevtool</a></li>
<li><a href="https://github.com/GrapheneOS/branding">branding</a></li>
<li><a href="https://github.com/GrapheneOS/hardened_malloc">hardened_malloc</a></li>
<li><a href="https://github.com/GrapheneOS/platform_external_AppStore">platform_external_AppStore</a>: App Store prebuilt</li>
<li><a href="https://github.com/GrapheneOS/platform_external_Auditor">platform_external_Auditor</a>: Auditor app prebuilt</li>
<li><a href="https://github.com/GrapheneOS/platform_external_Camera">platform_external_Camera</a>: Camera app prebuilt</li>
<li><a href="https://github.com/GrapheneOS/platform_external_GmsCompatConfig">platform_external_GmsCompatConfig</a></li>
<li><a href="https://github.com/GrapheneOS/platform_external_Info">platform_external_Info</a></li>
<li><a href="https://github.com/GrapheneOS/platform_external_Messaging">platform_external_Messaging</a></li>
<li><a href="https://github.com/GrapheneOS/platform_external_PdfViewer">platform_external_PdfViewer</a>: PDF Viewer app prebuilt</li>
<li><a href="https://github.com/GrapheneOS/platform_external_talkback">platform_external_talkback</a>: TalkBack app (GrapheneOS fork) prebuilt</li>
<li><a href="https://gitlab.com/grapheneos/platform_external_vanadium">platform_external_vanadium</a>: Vanadium browser, WebView and library prebuilts</li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_AppCompatConfig">platform_packages_apps_AppCompatConfig</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_CarrierConfig2">platform_packages_apps_CarrierConfig2</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_ExactCalculator">platform_packages_apps_ExactCalculator</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_GmsCompat">platform_packages_apps_GmsCompat</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_LogViewer">platform_packages_apps_LogViewer</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_NetworkLocation">platform_packages_apps_NetworkLocation</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_Seedvault">platform_packages_apps_Seedvault</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_SetupWizard2">platform_packages_apps_SetupWizard2</a></li>
<li><a href="https://github.com/GrapheneOS/platform_packages_apps_Updater">platform_packages_apps_Updater</a>: OS update client</li>
<li><a href="https://github.com/GrapheneOS/script">script</a></li>
<li><a href="https://github.com/GrapheneOS/vendor_state">vendor_state</a></li>
</ul>
</section>
<section id="standalone-apps">
<h2><a href="#standalone-apps">Standalone apps</a></h2>
<p>These are standalone app projects developed by GrapheneOS and included in the
OS. This does not include the many apps included by AOSP without modifications by
GrapheneOS or with only minor modifications.</p>
<ul>
<li><a href="https://github.com/GrapheneOS/AppStore">App Store</a></li>
<li><a href="https://github.com/GrapheneOS/Auditor">Auditor</a></li>
<li><a href="https://github.com/GrapheneOS/Camera">Camera</a></li>
<li><a href="https://github.com/GrapheneOS/Info">Info</a></li>
<li><a href="https://github.com/GrapheneOS/Messaging">Messaging</a></li>
<li><a href="https://github.com/GrapheneOS/PdfViewer">PDF Viewer</a></li>
<li><a href="https://github.com/GrapheneOS/talkback">talkback</a>: GrapheneOS fork of the open source TalkBack screen reader</li>
<li><a href="https://github.com/GrapheneOS/Vanadium">Vanadium</a>: Privacy and security focused Chromium-based browser and WebView</li>
</ul>
</section>
<section id="services">
<h2><a href="#services">Services</a></h2>
<ul>
<li><a href="https://github.com/GrapheneOS/infrastructure">infrastructure</a>: Shared server infrastructure</li>
<li><a href="https://github.com/GrapheneOS/AttestationServer">AttestationServer</a>: attestation.app remote attestation server</li>
<li><a href="https://github.com/GrapheneOS/grapheneos.org">grapheneos.org</a>: Main website servers</li>
<li><a href="https://github.com/GrapheneOS/releases.grapheneos.org">releases.grapheneos.org</a>: OS update and app repository servers</li>
<li><a href="https://github.com/GrapheneOS/apps.grapheneos.org">apps.grapheneos.org</a>: Application repository</li>
<li><a href="https://github.com/GrapheneOS/grapheneos.network">grapheneos.network</a>: Servers for HTTP/HTTPS connectivity checks, HTTPS network time, NTP (for Qualcomm XTRA), Broadcom PSDS cache, Samsung PSDS cache, Qualcomm PSDS (XTRA) cache, SUPL proxy, attestation key provisioning proxy and Vanadium component update check/download proxy</li>
<li><a href="https://github.com/GrapheneOS/mail.grapheneos.org">mail.grapheneos.org</a>: Mail server</li>
<li><a href="https://github.com/GrapheneOS/matrix.grapheneos.org">matrix.grapheneos.org</a>: Matrix and Element Web server</li>
<li><a href="https://github.com/GrapheneOS/ns1.grapheneos.org">ns1.grapheneos.org</a>: Authoritative DNS servers</li>
<li><a href="https://github.com/GrapheneOS/discuss.grapheneos.org">discuss.grapheneos.org</a>: Discussion forum server</li>
<li><a href="https://github.com/GrapheneOS/grapheneos.social">grapheneos.social</a>: Mastodon instance</li>
</ul>
</section>
<section id="utilities">
<h2><a href="#utilities">Utilities</a></h2>
<ul>
<li><a href="https://github.com/GrapheneOS/tls-pinning">tls-pinning</a>: Utilities for setting up conservative non-leaf TLS pinning with backup pins</li>
<li><a href="https://github.com/GrapheneOS/branding-tools">branding-tools</a>: Scripting for generating branding</li>
</ul>
</section>
<section id="archive">
<h2><a href="#archive">Archive</a></h2>
<p>An archive of legacy repositories is available via the
<a href="https://github.com/GrapheneOS-Archive">GrapheneOS Archive</a>
organization. This only covers repositories archives after renaming the project to
GrapheneOS. Earlier code is mostly not available via GitHub anymore due to
<a href="/history/#history">the unfortunate events</a> leading to the rename of
the project.</p>
</section>
</main>
{% include "footer.html" %}
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -1,55 +0,0 @@
<section id="{{codename}}">
<h3><a href="#{{codename}}">{{name}}</a></h3>
<table>
<tr>
<th>Channel</th>
<th>Version</th>
<th>Downloads</th>
</tr>
<tr id="{{codename}}-stable">
<td>Stable</td>
{% if split %}
<td><span>[[{{codename}}-stable-BUILD_NUMBER]]</span></td>
{% else %}
<td><a href="#[[{{codename}}-stable-BUILD_NUMBER]]">[[{{codename}}-stable-BUILD_NUMBER]]</a></td>
{% endif %}
<td>
<ul>
<li><a href="https://releases.grapheneos.org/{{codename}}-{{install | default("install")}}-[[{{codename}}-stable-BUILD_NUMBER]].zip">Install zip</a></li>
<li><a href="https://releases.grapheneos.org/{{codename}}-{{install | default("install")}}-[[{{codename}}-stable-BUILD_NUMBER]].zip.sig">Install zip signature</a></li>
<li><a href="https://releases.grapheneos.org/{{codename}}-ota_update-[[{{codename}}-stable-BUILD_NUMBER]].zip">Signed update package</a></li>
</ul>
</td>
</tr>
<tr id="{{codename}}-beta">
<td>Beta</td>
{% if split %}
<td><span>[[{{codename}}-beta-BUILD_NUMBER]]</span></td>
{% else %}
<td><a href="#[[{{codename}}-beta-BUILD_NUMBER]]">[[{{codename}}-beta-BUILD_NUMBER]]</a></td>
{% endif %}
<td>
<ul>
<li><a href="https://releases.grapheneos.org/{{codename}}-{{install | default("install")}}-[[{{codename}}-beta-BUILD_NUMBER]].zip">Install zip</a></li>
<li><a href="https://releases.grapheneos.org/{{codename}}-{{install | default("install")}}-[[{{codename}}-beta-BUILD_NUMBER]].zip.sig">Install zip signature</a></li>
<li><a href="https://releases.grapheneos.org/{{codename}}-ota_update-[[{{codename}}-beta-BUILD_NUMBER]].zip">Signed update package</a></li>
</ul>
</td>
</tr>
<tr id="{{codename}}-alpha">
<td>Alpha</td>
{% if split %}
<td><span>[[{{codename}}-alpha-BUILD_NUMBER]]</span></td>
{% else %}
<td><a href="#[[{{codename}}-alpha-BUILD_NUMBER]]">[[{{codename}}-alpha-BUILD_NUMBER]]</a></td>
{% endif %}
<td>
<ul>
<li><a href="https://releases.grapheneos.org/{{codename}}-{{install | default("install")}}-[[{{codename}}-alpha-BUILD_NUMBER]].zip">Install zip</a></li>
<li><a href="https://releases.grapheneos.org/{{codename}}-{{install | default("install")}}-[[{{codename}}-alpha-BUILD_NUMBER]].zip.sig">Install zip signature</a></li>
<li><a href="https://releases.grapheneos.org/{{codename}}-ota_update-[[{{codename}}-alpha-BUILD_NUMBER]].zip">Signed update package</a></li>
</ul>
</td>
</tr>
</table>
</section>

View File

@ -1,16 +1,7 @@
<footer>
<a href="/"><img src="[[path|/mask-icon.svg]]" width="512" height="512" alt=""/>GrapheneOS</a>
<a href="/"><img src="[[path|/mask-icon.svg]]" width="512" height="512" alt=""/>Hakurei</a>
<ul id="social">
<li><a href="https://discuss.grapheneos.org/">Forum</a></li>
<li><a href="https://discord.com/invite/grapheneos">Discord</a></li>
<li><a href="https://t.me/GrapheneOS">Telegram</a></li>
<li><a href="https://matrix.to/#/%23community:grapheneos.org">Matrix</a></li>
<li><a href="/hiring">Hiring</a></li>
<li><a href="https://x.com/GrapheneOS">X</a></li>
<li><a href="https://grapheneos.social/@GrapheneOS">Mastodon</a></li>
<li><a href="https://bsky.app/profile/grapheneos.org">Bluesky</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>
<li><a href="https://git.gensokyo.uk/security">Gitea</a></li>
<li><a href="/discord">Discord</a></li>
</ul>
</footer>

View File

@ -1,18 +1,11 @@
<header>
<nav id="site-menu">
<ul>
<li {% if current_page == "/" %}aria-current="page"{% endif %}><a href="/"><img src="[[path|/mask-icon.svg]]" alt=""/>GrapheneOS</a></li>
<li {% if current_page == "features" %}aria-current="page"{% endif %}><a href="/features">Features</a></li>
<li {% if current_page == "install" %}aria-current="page"{% endif %}><a href="/install/">Install</a></li>
<li {% if current_page == "build" %}aria-current="page"{% endif %}><a href="/build">Build</a></li>
<li {% if current_page == "usage" %}aria-current="page"{% endif %}><a href="/usage">Usage</a></li>
<li {% if current_page == "faq" %}aria-current="page"{% endif %}><a href="/faq">FAQ</a></li>
<li {% if current_page == "releases" %}aria-current="page"{% endif %}><a href="/releases">Releases</a></li>
<li {% if current_page == "source" %}aria-current="page"{% endif %}><a href="/source">Source</a></li>
<li {% if current_page == "history" %}aria-current="page"{% endif %}><a href="/history/">History</a></li>
<li {% if current_page == "articles" %}aria-current="page"{% endif %}><a href="/articles/">Articles</a></li>
<li {% if current_page == "donate" %}aria-current="page"{% endif %}><a href="/donate">Donate</a></li>
<li {% if current_page == "contact" %}aria-current="page"{% endif %}><a href="/contact">Contact</a></li>
<li {% if current_page == "/" %}aria-current="page"{% endif %}><a href="/"><img src="[[path|/mask-icon.svg]]" alt=""/>Hakurei</a></li>
<li {% if current_page == "package" %}aria-current="page"{% endif %}><a href="/package.html">Package</a></li>
<li {% if current_page == "install" %}aria-current="page"{% endif %}><a href="/install.html">Install</a></li>
<!-- <li {% if current_page == "faq" %}aria-current="page"{% endif %}><a href="/faq.html">FAQ</a></li> -->
<li {% if current_page == "contact" %}aria-current="page"{% endif %}><a href="/contact.html">Contact</a></li>
</ul>
</nav>
</header>