Skip to main content

auth/
console_artifact.rs

1use axum::Json;
2use axum::http::{HeaderMap, HeaderValue, header};
3use platform_http::{ApiOpenApiRouter, OpenApiRouter, routes};
4use serde_json::{Value, json};
5use sha2::{Digest as _, Sha256};
6
7pub const AUTH_CONSOLE_ARTIFACT_PATH: &str = "/v1/auth/console/artifact";
8pub const AUTH_CONSOLE_RELEASE_PATH: &str = "/v1/auth/console/release";
9pub const AUTH_CONSOLE_RELEASE_PROTOCOL: &str = "lenso.console-artifact-template.v1";
10
11const AUTH_CONSOLE_ARTIFACT: &[u8] = include_bytes!("../artifacts/auth-console.tgz");
12const AUTH_CONTRACT_DOCUMENT: &str = include_str!("../artifacts/auth-business-api.v1.json");
13
14pub fn router() -> ApiOpenApiRouter {
15    OpenApiRouter::new()
16        .routes(routes!(get_console_artifact))
17        .routes(routes!(get_console_release))
18}
19
20#[utoipa::path(
21    get,
22    path = "/v1/auth/console/artifact",
23    operation_id = "auth_console_artifact",
24    tag = "auth-console",
25    responses((status = 200, description = "Exact Auth Console ESM artifact", content_type = "application/gzip"))
26)]
27async fn get_console_artifact() -> (HeaderMap, &'static [u8]) {
28    let mut headers = HeaderMap::new();
29    headers.insert(
30        header::CONTENT_TYPE,
31        HeaderValue::from_static("application/gzip"),
32    );
33    headers.insert(
34        header::CACHE_CONTROL,
35        HeaderValue::from_static("public, max-age=31536000, immutable"),
36    );
37    (headers, AUTH_CONSOLE_ARTIFACT)
38}
39
40#[utoipa::path(
41    get,
42    path = "/v1/auth/console/release",
43    operation_id = "auth_console_release",
44    tag = "auth-console",
45    responses((status = 200, description = "Auth Module-owned Console artifact release template", body = serde_json::Value, content_type = "application/json"))
46)]
47async fn get_console_release() -> Json<Value> {
48    Json(console_release_template())
49}
50
51#[must_use]
52pub fn console_release_template() -> Value {
53    let manifest = crate::module::manifest();
54    let console_manifest = manifest.console_module_manifest("^2.1.0", "^2.0.0");
55    json!({
56        "protocol": AUTH_CONSOLE_RELEASE_PROTOCOL,
57        "moduleId": manifest.module_id,
58        "version": env!("CARGO_PKG_VERSION"),
59        "manifest": manifest,
60        "artifactPath": AUTH_CONSOLE_ARTIFACT_PATH,
61        "artifact": {
62            "digest": artifact_digest(),
63            "format": "console_ui_esm",
64            "protocolMajor": 1,
65            "entry": "index.js",
66            "entries": [
67                { "name": "module", "path": "index.js" },
68                { "name": "sessions", "path": "index.js?surface=sessions" },
69                { "name": "users", "path": "index.js?surface=users" },
70                { "name": "style", "path": "assets/stylex.css" }
71            ],
72            "styleAssets": [
73                { "path": "assets/stylex.css", "order": 0 }
74            ],
75            "manifest": console_manifest,
76            "requestedPermissions": []
77        },
78        "delivery": {
79            "kind": "linked",
80            "package": "lenso-module-auth",
81            "crateVersion": env!("CARGO_PKG_VERSION"),
82            "defaultFeatures": false,
83            "features": ["redis"],
84            "binding": "auth"
85        },
86        "compatibility": {
87            "lensoRequirement": "^0.3.0",
88            "hostApiRequirement": "^2.1.0",
89            "consoleUiRequirement": "^2.0.0",
90            "rustRequirement": ">=1.94"
91        },
92        "surfaceApi": {
93            "contractDigest": crate::console_api::AUTH_CONTRACT_DIGEST,
94            "operationIds": [
95                crate::console_api::LIST_SESSIONS_OPERATION,
96                crate::console_api::LIST_USERS_OPERATION,
97                crate::console_api::REVOKE_SESSION_OPERATION,
98                crate::console_api::DISABLE_USER_OPERATION,
99                crate::console_api::ENABLE_USER_OPERATION
100            ],
101            "contractArtifact": {
102                "format": "openapi_3_1_json",
103                "document": AUTH_CONTRACT_DOCUMENT
104            }
105        }
106    })
107}
108
109fn artifact_digest() -> String {
110    let hex = Sha256::digest(AUTH_CONSOLE_ARTIFACT)
111        .iter()
112        .map(|byte| format!("{byte:02x}"))
113        .collect::<String>();
114    format!("sha256:{hex}")
115}
116
117#[cfg(test)]
118mod tests {
119    use super::*;
120
121    #[test]
122    fn release_template_binds_the_current_module_and_surface_contract() {
123        let release = console_release_template();
124        assert_eq!(release["moduleId"], "lenso/auth");
125        assert_eq!(release["version"], env!("CARGO_PKG_VERSION"));
126        assert_eq!(
127            release["artifact"]["digest"],
128            "sha256:01d607ec71232d7973cbce6787f4cd713f49eefb18002bf5764d65656708cf89"
129        );
130        assert_eq!(
131            release["surfaceApi"]["contractDigest"],
132            crate::console_api::AUTH_CONTRACT_DIGEST
133        );
134        assert_eq!(
135            release["artifact"]["manifest"],
136            serde_json::to_value(
137                crate::module::manifest().console_module_manifest("^2.1.0", "^2.0.0")
138            )
139            .unwrap()
140        );
141    }
142}