diff --git a/.ember-cli b/.ember-cli
index ee64cfed2a8..fdc746c3cc4 100644
--- a/.ember-cli
+++ b/.ember-cli
@@ -5,5 +5,6 @@
Setting `disableAnalytics` to true will prevent any data from being sent.
*/
- "disableAnalytics": false
+ "disableAnalytics": false,
+ "port": 4201
}
diff --git a/.env.sample b/.env.sample
index 58f047ed21e..4884de8b392 100644
--- a/.env.sample
+++ b/.env.sample
@@ -72,3 +72,7 @@ export GH_CLIENT_SECRET=
# Credentials for connecting to the Sentry error reporting service.
# export SENTRY_DSN_API=
export SENTRY_ENV_API=local
+
+# GitHub users that are admins on this instance, separated by commas. Whitespace
+# will be ignored.
+export GH_ADMIN_USERS=
diff --git a/Caddyfile b/Caddyfile
new file mode 100644
index 00000000000..63fe8535083
--- /dev/null
+++ b/Caddyfile
@@ -0,0 +1,8 @@
+http://localhost:4200, http://127.0.0.1:4200 {
+ @backend {
+ path /api/* /admin/* /git/*
+ }
+
+ reverse_proxy @backend 127.0.0.1:8888
+ reverse_proxy 127.0.0.1:4201
+}
diff --git a/Cargo.lock b/Cargo.lock
index 3b0584fb21e..3c634b5a6cf 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -335,6 +335,18 @@ dependencies = [
"syn 2.0.15",
]
+[[package]]
+name = "axum-template"
+version = "0.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f926c4ca412af0a88bd119a6d214b026a0c98d8c763eaead70032628d3d0a549"
+dependencies = [
+ "axum",
+ "handlebars",
+ "serde",
+ "thiserror",
+]
+
[[package]]
name = "backtrace"
version = "0.3.67"
@@ -447,6 +459,7 @@ dependencies = [
"aws-sigv4",
"axum",
"axum-extra",
+ "axum-template",
"base64 0.13.1",
"cargo-registry-index",
"cargo-registry-markdown",
@@ -465,6 +478,7 @@ dependencies = [
"flate2",
"futures-channel",
"futures-util",
+ "handlebars",
"hex",
"http",
"http-body",
@@ -474,6 +488,7 @@ dependencies = [
"indicatif",
"insta",
"ipnetwork",
+ "lazy_static",
"lettre",
"minijinja",
"moka",
@@ -485,6 +500,7 @@ dependencies = [
"reqwest",
"retry",
"ring",
+ "rust-embed",
"scheduled-thread-pool",
"semver",
"sentry",
@@ -1285,6 +1301,22 @@ dependencies = [
"tracing",
]
+[[package]]
+name = "handlebars"
+version = "4.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "035ef95d03713f2c347a72547b7cd38cbc9af7cd51e6099fb62d586d4a6dee3a"
+dependencies = [
+ "log",
+ "pest",
+ "pest_derive",
+ "rust-embed",
+ "serde",
+ "serde_json",
+ "thiserror",
+ "walkdir",
+]
+
[[package]]
name = "hashbrown"
version = "0.12.3"
@@ -2550,6 +2582,40 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "rust-embed"
+version = "6.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b68543d5527e158213414a92832d2aab11a84d2571a5eb021ebe22c43aab066"
+dependencies = [
+ "rust-embed-impl",
+ "rust-embed-utils",
+ "walkdir",
+]
+
+[[package]]
+name = "rust-embed-impl"
+version = "6.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d4e0f0ced47ded9a68374ac145edd65a6c1fa13a96447b873660b2a568a0fd7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "rust-embed-utils",
+ "syn 1.0.109",
+ "walkdir",
+]
+
+[[package]]
+name = "rust-embed-utils"
+version = "7.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "512b0ab6853f7e14e3c8754acb43d6f748bb9ced66aa5915a6553ac8213f7731"
+dependencies = [
+ "sha2",
+ "walkdir",
+]
+
[[package]]
name = "rustc-demangle"
version = "0.1.23"
diff --git a/Cargo.toml b/Cargo.toml
index aa0c3082766..734c32445c2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -26,6 +26,7 @@ anyhow = "=1.0.70"
aws-sigv4 = "=0.55.1"
axum = { version = "=0.6.16", features = ["headers", "macros", "matched-path"] }
axum-extra = { version = "=0.7.4", features = ["cookie-signed"] }
+axum-template = { version = "0.15.1", features = ["handlebars"] }
base64 = "=0.13.1"
cargo-registry-index = { path = "cargo-registry-index" }
cargo-registry-markdown = { path = "cargo-registry-markdown" }
@@ -43,6 +44,7 @@ dotenv = "=0.15.0"
flate2 = "=1.0.25"
futures-channel = { version = "=0.3.28", default-features = false }
futures-util = "=0.3.28"
+handlebars = { version = "4.3.6", features = ["dir_source", "rust-embed"] }
hex = "=0.4.3"
http = "=0.2.9"
http-body = "=0.4.5"
@@ -50,7 +52,7 @@ hyper = { version = "=0.14.26", features = ["backports", "client", "deprecated",
indexmap = { version = "=1.9.3", features = ["serde-1"] }
indicatif = "=0.17.3"
ipnetwork = "=0.20.0"
-tikv-jemallocator = { version = "=0.5.0", features = ['unprefixed_malloc_on_supported_platforms', 'profiling'] }
+lazy_static = "1.4.0"
lettre = { version = "=0.10.4", default-features = false, features = ["file-transport", "smtp-transport", "native-tls", "hostname", "builder"] }
minijinja = "=0.31.1"
moka = { version = "=0.10.2", features = ["future"] }
@@ -62,6 +64,7 @@ rand = "=0.8.5"
reqwest = { version = "=0.11.16", features = ["blocking", "gzip", "json"] }
retry = "=2.0.0"
ring = "=0.16.20"
+rust-embed = { version = "6.6.1" }
scheduled-thread-pool = "=0.2.7"
semver = { version = "=1.0.17", features = ["serde"] }
sentry = { version = "=0.30.0", features = ["tracing", "tower", "tower-http"] }
@@ -73,6 +76,7 @@ tar = "=0.4.38"
tempfile = "=3.5.0"
thiserror = "=1.0.40"
threadpool = "=1.8.1"
+tikv-jemallocator = { version = "=0.5.0", features = ['unprefixed_malloc_on_supported_platforms', 'profiling'] }
tokio = { version = "=1.27.0", features = ["net", "signal", "io-std", "io-util", "rt-multi-thread", "macros"]}
toml = "=0.7.3"
tower = "=0.4.13"
diff --git a/admin/templates/components/datetime.hbs b/admin/templates/components/datetime.hbs
new file mode 100644
index 00000000000..eeaee423825
--- /dev/null
+++ b/admin/templates/components/datetime.hbs
@@ -0,0 +1 @@
+{{this.human}}
\ No newline at end of file
diff --git a/admin/templates/components/page.hbs b/admin/templates/components/page.hbs
new file mode 100644
index 00000000000..00f1abac0b1
--- /dev/null
+++ b/admin/templates/components/page.hbs
@@ -0,0 +1,27 @@
+{{#if this.paginated}}
+
+{{/if}}
\ No newline at end of file
diff --git a/admin/templates/components/user.hbs b/admin/templates/components/user.hbs
new file mode 100644
index 00000000000..4d5c3d6e169
--- /dev/null
+++ b/admin/templates/components/user.hbs
@@ -0,0 +1,13 @@
+
+ {{#if this.avatar}}
+
+ {{~/if~}}
+ {{~this.username}}
+
\ No newline at end of file
diff --git a/admin/templates/crates.hbs b/admin/templates/crates.hbs
new file mode 100644
index 00000000000..2d654dc9178
--- /dev/null
+++ b/admin/templates/crates.hbs
@@ -0,0 +1,97 @@
+{{#*inline "body"}}
+
+
{{> title}}
+
+
+
+
+
+
+ Crate |
+ Version |
+ Published |
+ |
+
+
+
+ {{#each this.versions}}
+
+
+
+
+ |
+ {{this.num}} |
+
+ {{> components/datetime this.created_at}}
+ by
+ {{> components/user this.publisher }}
+ |
+
+ {{#if this.yanked}}
+
+ {{else}}
+
+ {{/if}}
+ |
+
+ {{/each}}
+
+
+
+ {{> components/page this.page}}
+
+
+{{/inline}}
+
+{{#*inline "title"}}Crates{{/inline}}
+
+{{> page}}
\ No newline at end of file
diff --git a/admin/templates/page.hbs b/admin/templates/page.hbs
new file mode 100644
index 00000000000..61ff0f0242f
--- /dev/null
+++ b/admin/templates/page.hbs
@@ -0,0 +1,31 @@
+
+
+
+
+
+ {{> title}} :: crates.io
+
+
+
+
+
+
+
+ {{> body}}
+
+
+
\ No newline at end of file
diff --git a/app/components/header.hbs b/app/components/header.hbs
index 1426d929173..2056704362d 100644
--- a/app/components/header.hbs
+++ b/app/components/header.hbs
@@ -29,6 +29,9 @@
Dashboard
Account Settings
Owner Invites
+ {{#if this.session.currentUser.admin }}
+ Site Admin
+ {{/if}}