@greenpandastudios/aug-cli 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +13 -0
- package/THIRD_PARTY_NOTICES.md +18 -0
- package/bin/aug.mjs +3 -0
- package/docs/api/crypto.md +351 -0
- package/docs/api/io.md +207 -0
- package/docs/api/json.md +21 -0
- package/docs/api/memory.md +109 -0
- package/docs/api/time.md +54 -0
- package/docs/api/web.md +184 -0
- package/docs/assets/benchmarks/execution.svg +2978 -0
- package/docs/assets/benchmarks/http.svg +1674 -0
- package/docs/assets/benchmarks/improvements.svg +2315 -0
- package/docs/assets/benchmarks/memory.svg +1891 -0
- package/docs/benchmark-baseline.json +1087 -0
- package/docs/benchmark-results.json +91123 -0
- package/docs/benchmarks.json +38 -0
- package/docs/compatibility.md +42 -0
- package/docs/concurrency-implementation.md +18 -0
- package/docs/diagnostics.md +97 -0
- package/docs/docker.md +35 -0
- package/docs/example-projects.json +26 -0
- package/docs/examples/approved-design/counters.md +253 -0
- package/docs/examples/approved-design/dependencies/august/0.19.0/io/contracts.md +395 -0
- package/docs/examples/approved-design/domain/app.md +165 -0
- package/docs/examples/approved-design/domain/export.md +83 -0
- package/docs/examples/approved-design/domain/models.md +80 -0
- package/docs/examples/approved-design/domain/numbers.md +248 -0
- package/docs/examples/approved-design/index.md +39 -0
- package/docs/examples/approved-design/main-yaml.md +24 -0
- package/docs/examples/approved-design/main.md +215 -0
- package/docs/examples/benchmark/index.md +33 -0
- package/docs/examples/benchmark/main-yaml.md +17 -0
- package/docs/examples/benchmark/main.md +117 -0
- package/docs/examples/cli-args/index.md +32 -0
- package/docs/examples/cli-args/main.md +107 -0
- package/docs/examples/collections/index.md +32 -0
- package/docs/examples/collections/main.md +118 -0
- package/docs/examples/collections-benchmark/index.md +34 -0
- package/docs/examples/collections-benchmark/main.md +115 -0
- package/docs/examples/cpu-benchmark/index.md +34 -0
- package/docs/examples/cpu-benchmark/main.md +90 -0
- package/docs/examples/developer-workflow/calculator.md +357 -0
- package/docs/examples/developer-workflow/dependencies/august/0.19.0/io/contracts.md +395 -0
- package/docs/examples/developer-workflow/index.md +37 -0
- package/docs/examples/developer-workflow/logging/console.md +124 -0
- package/docs/examples/developer-workflow/logging/export.md +70 -0
- package/docs/examples/developer-workflow/logging/logger.md +111 -0
- package/docs/examples/developer-workflow/main.md +172 -0
- package/docs/examples/drop/index.md +33 -0
- package/docs/examples/drop/main.md +85 -0
- package/docs/examples/drop/resource.md +95 -0
- package/docs/examples/errors/errors.md +85 -0
- package/docs/examples/errors/index.md +33 -0
- package/docs/examples/errors/main.md +92 -0
- package/docs/examples/ffi/index.md +33 -0
- package/docs/examples/ffi/main.md +75 -0
- package/docs/examples/ffi/native.md +93 -0
- package/docs/examples/generic-di/dependencies/august/0.19.0/io/contracts.md +395 -0
- package/docs/examples/generic-di/index.md +33 -0
- package/docs/examples/generic-di/main.md +111 -0
- package/docs/examples/generic-di/types.md +180 -0
- package/docs/examples/generics/index.md +33 -0
- package/docs/examples/generics/main.md +120 -0
- package/docs/examples/generics/types.md +189 -0
- package/docs/examples/hello/app/export.md +67 -0
- package/docs/examples/hello/app/greeter.md +190 -0
- package/docs/examples/hello/dependencies/august/0.19.0/io/contracts.md +395 -0
- package/docs/examples/hello/index.md +37 -0
- package/docs/examples/hello/logging/console.md +121 -0
- package/docs/examples/hello/logging/export.md +71 -0
- package/docs/examples/hello/logging/logger.md +120 -0
- package/docs/examples/hello/main.md +115 -0
- package/docs/examples/http-benchmark/index.md +35 -0
- package/docs/examples/http-benchmark/main.md +79 -0
- package/docs/examples/http-benchmark/routes.md +88 -0
- package/docs/examples/index.md +60 -0
- package/docs/examples/interceptors/app.md +250 -0
- package/docs/examples/interceptors/dependencies/august/0.19.0/io/contracts.md +395 -0
- package/docs/examples/interceptors/index.md +35 -0
- package/docs/examples/interceptors/interceptors.md +284 -0
- package/docs/examples/interceptors/logging.md +155 -0
- package/docs/examples/interceptors/main.md +162 -0
- package/docs/examples/json-benchmark/data.md +71 -0
- package/docs/examples/json-benchmark/dependencies/august/0.19.0/json/contracts.md +103 -0
- package/docs/examples/json-benchmark/index.md +35 -0
- package/docs/examples/json-benchmark/main.md +131 -0
- package/docs/examples/new-syntax/console.md +118 -0
- package/docs/examples/new-syntax/dependencies/august/0.19.0/io/contracts.md +395 -0
- package/docs/examples/new-syntax/greeter.md +145 -0
- package/docs/examples/new-syntax/index.md +36 -0
- package/docs/examples/new-syntax/logger.md +111 -0
- package/docs/examples/new-syntax/main.md +135 -0
- package/docs/examples/new-syntax/math.md +79 -0
- package/docs/examples/oidc-login/client/contracts.md +151 -0
- package/docs/examples/oidc-login/client/endpoints.md +263 -0
- package/docs/examples/oidc-login/client/export.md +107 -0
- package/docs/examples/oidc-login/client/login.md +515 -0
- package/docs/examples/oidc-login/client/logout.md +249 -0
- package/docs/examples/oidc-login/client/protocol.md +595 -0
- package/docs/examples/oidc-login/client/session.md +297 -0
- package/docs/examples/oidc-login/client/views.md +144 -0
- package/docs/examples/oidc-login/common/export.md +115 -0
- package/docs/examples/oidc-login/common/headers.md +162 -0
- package/docs/examples/oidc-login/common/keys.md +336 -0
- package/docs/examples/oidc-login/common/settings.md +116 -0
- package/docs/examples/oidc-login/common/views.md +103 -0
- package/docs/examples/oidc-login/dependencies/august/0.19.0/crypto/contracts.md +925 -0
- package/docs/examples/oidc-login/dependencies/august/0.19.0/crypto/jose.md +434 -0
- package/docs/examples/oidc-login/dependencies/august/0.19.0/json/contracts.md +103 -0
- package/docs/examples/oidc-login/dependencies/august/0.19.0/memory/store.md +374 -0
- package/docs/examples/oidc-login/dependencies/august/0.19.0/time/contracts.md +150 -0
- package/docs/examples/oidc-login/dependencies/august/0.19.0/web/contracts.md +532 -0
- package/docs/examples/oidc-login/index.md +57 -0
- package/docs/examples/oidc-login/main-yaml.md +28 -0
- package/docs/examples/oidc-login/main.md +283 -0
- package/docs/examples/oidc-login/provider/authorization.md +457 -0
- package/docs/examples/oidc-login/provider/contracts.md +267 -0
- package/docs/examples/oidc-login/provider/credentials.md +148 -0
- package/docs/examples/oidc-login/provider/discovery.md +215 -0
- package/docs/examples/oidc-login/provider/export.md +131 -0
- package/docs/examples/oidc-login/provider/token.md +364 -0
- package/docs/examples/oidc-login/provider/userinfo.md +228 -0
- package/docs/examples/oidc-login/provider/views.md +137 -0
- package/docs/examples/ownership/counter.md +140 -0
- package/docs/examples/ownership/index.md +33 -0
- package/docs/examples/ownership/main.md +90 -0
- package/docs/examples/ownership-transfer/dependencies/august/0.19.0/io/contracts.md +395 -0
- package/docs/examples/ownership-transfer/index.md +33 -0
- package/docs/examples/ownership-transfer/main.md +125 -0
- package/docs/examples/ownership-transfer/resource.md +150 -0
- package/docs/examples/packages-app/dependencies/packages/@example/aug-math/0.1.0/arithmetic.md +117 -0
- package/docs/examples/packages-app/index.md +34 -0
- package/docs/examples/packages-app/main-yaml.md +18 -0
- package/docs/examples/packages-app/main.md +80 -0
- package/docs/examples/packages-math/aug-package-json.md +24 -0
- package/docs/examples/packages-math/index.md +36 -0
- package/docs/examples/packages-math/package-json.md +25 -0
- package/docs/examples/packages-math/src/arithmetic.md +121 -0
- package/docs/examples/packages-math/src/export.md +63 -0
- package/docs/examples/startup-benchmark/index.md +34 -0
- package/docs/examples/startup-benchmark/main.md +68 -0
- package/docs/examples/visibility/counter.md +142 -0
- package/docs/examples/visibility/index.md +33 -0
- package/docs/examples/visibility/main.md +96 -0
- package/docs/examples.json +47 -0
- package/docs/getting-started.md +5 -0
- package/docs/grammar.md +136 -0
- package/docs/implementation-map.md +106 -0
- package/docs/index.md +46 -0
- package/docs/language-conformance.md +30 -0
- package/docs/language-constructs.md +1461 -0
- package/docs/language-design-audit.md +147 -0
- package/docs/maintaining-docs.md +43 -0
- package/docs/packages.md +184 -0
- package/docs/performance.md +535 -0
- package/docs/production-readiness.md +39 -0
- package/docs/reference.md +361 -0
- package/docs/release-review.md +23 -0
- package/docs/releasing.md +79 -0
- package/docs/roadmap.md +13 -0
- package/docs/specifications.md +86 -0
- package/docs/testing.md +120 -0
- package/docs/tooling.md +197 -0
- package/docs/web-implementation-plan.md +39 -0
- package/docs/web-library-gaps.md +27 -0
- package/docs/web.md +197 -0
- package/examples/approved-design/.aug-spec/august/0.19.0/io/contracts.aug +36 -0
- package/examples/approved-design/.aug-spec/august/0.19.0/io/contracts.aug.md +316 -0
- package/examples/approved-design/.aug-spec/manifest.json +14 -0
- package/examples/approved-design/counters.aug +22 -0
- package/examples/approved-design/counters.aug.md +177 -0
- package/examples/approved-design/domain/app.aug +12 -0
- package/examples/approved-design/domain/app.aug.md +97 -0
- package/examples/approved-design/domain/export.aug +5 -0
- package/examples/approved-design/domain/export.aug.md +25 -0
- package/examples/approved-design/domain/models.aug +2 -0
- package/examples/approved-design/domain/models.aug.md +30 -0
- package/examples/approved-design/domain/numbers.aug +29 -0
- package/examples/approved-design/domain/numbers.aug.md +141 -0
- package/examples/approved-design/main.aug +26 -0
- package/examples/approved-design/main.aug.md +108 -0
- package/examples/approved-design/main.yaml +8 -0
- package/examples/benchmark/.aug-spec/manifest.json +7 -0
- package/examples/benchmark/main.aug +17 -0
- package/examples/benchmark/main.aug.md +43 -0
- package/examples/benchmark/main.yaml +1 -0
- package/examples/cli-args/.aug-spec/manifest.json +7 -0
- package/examples/cli-args/main.aug +15 -0
- package/examples/cli-args/main.aug.md +38 -0
- package/examples/collections/.aug-spec/manifest.json +7 -0
- package/examples/collections/main.aug +18 -0
- package/examples/collections/main.aug.md +43 -0
- package/examples/developer-workflow/.aug-spec/august/0.19.0/io/contracts.aug +36 -0
- package/examples/developer-workflow/.aug-spec/august/0.19.0/io/contracts.aug.md +316 -0
- package/examples/developer-workflow/.aug-spec/manifest.json +13 -0
- package/examples/developer-workflow/calculator.aug +55 -0
- package/examples/developer-workflow/calculator.aug.md +228 -0
- package/examples/developer-workflow/logging/console.aug +8 -0
- package/examples/developer-workflow/logging/console.aug.md +67 -0
- package/examples/developer-workflow/logging/export.aug +2 -0
- package/examples/developer-workflow/logging/export.aug.md +19 -0
- package/examples/developer-workflow/logging/logger.aug +6 -0
- package/examples/developer-workflow/logging/logger.aug.md +57 -0
- package/examples/developer-workflow/main.aug +25 -0
- package/examples/developer-workflow/main.aug.md +79 -0
- package/examples/drop/.aug-spec/manifest.json +8 -0
- package/examples/drop/main.aug +3 -0
- package/examples/drop/main.aug.md +35 -0
- package/examples/drop/resource.aug +8 -0
- package/examples/drop/resource.aug.md +44 -0
- package/examples/errors/.aug-spec/manifest.json +8 -0
- package/examples/errors/errors.aug +6 -0
- package/examples/errors/errors.aug.md +33 -0
- package/examples/errors/main.aug +7 -0
- package/examples/errors/main.aug.md +36 -0
- package/examples/ffi/.aug-spec/manifest.json +8 -0
- package/examples/ffi/main.aug +2 -0
- package/examples/ffi/main.aug.md +27 -0
- package/examples/ffi/native.aug +6 -0
- package/examples/ffi/native.aug.md +43 -0
- package/examples/generic-di/.aug-spec/august/0.19.0/io/contracts.aug +36 -0
- package/examples/generic-di/.aug-spec/august/0.19.0/io/contracts.aug.md +316 -0
- package/examples/generic-di/.aug-spec/manifest.json +10 -0
- package/examples/generic-di/main.aug +9 -0
- package/examples/generic-di/main.aug.md +49 -0
- package/examples/generic-di/types.aug +17 -0
- package/examples/generic-di/types.aug.md +124 -0
- package/examples/generics/.aug-spec/manifest.json +8 -0
- package/examples/generics/main.aug +9 -0
- package/examples/generics/main.aug.md +58 -0
- package/examples/generics/types.aug +19 -0
- package/examples/generics/types.aug.md +132 -0
- package/examples/hello/.aug-spec/august/0.19.0/io/contracts.aug +36 -0
- package/examples/hello/.aug-spec/august/0.19.0/io/contracts.aug.md +316 -0
- package/examples/hello/.aug-spec/manifest.json +14 -0
- package/examples/hello/app/export.aug +1 -0
- package/examples/hello/app/export.aug.md +17 -0
- package/examples/hello/app/greeter.aug +22 -0
- package/examples/hello/app/greeter.aug.md +109 -0
- package/examples/hello/logging/console.aug +7 -0
- package/examples/hello/logging/console.aug.md +65 -0
- package/examples/hello/logging/export.aug +2 -0
- package/examples/hello/logging/export.aug.md +19 -0
- package/examples/hello/logging/logger.aug +9 -0
- package/examples/hello/logging/logger.aug.md +59 -0
- package/examples/hello/main.aug +9 -0
- package/examples/hello/main.aug.md +49 -0
- package/examples/interceptors/.aug-spec/august/0.19.0/io/contracts.aug +36 -0
- package/examples/interceptors/.aug-spec/august/0.19.0/io/contracts.aug.md +316 -0
- package/examples/interceptors/.aug-spec/manifest.json +12 -0
- package/examples/interceptors/app.aug +28 -0
- package/examples/interceptors/app.aug.md +162 -0
- package/examples/interceptors/interceptors.aug +40 -0
- package/examples/interceptors/interceptors.aug.md +180 -0
- package/examples/interceptors/logging.aug +12 -0
- package/examples/interceptors/logging.aug.md +96 -0
- package/examples/interceptors/main.aug +22 -0
- package/examples/interceptors/main.aug.md +76 -0
- package/examples/new-syntax/.aug-spec/august/0.19.0/io/contracts.aug +36 -0
- package/examples/new-syntax/.aug-spec/august/0.19.0/io/contracts.aug.md +316 -0
- package/examples/new-syntax/.aug-spec/manifest.json +13 -0
- package/examples/new-syntax/console.aug +7 -0
- package/examples/new-syntax/console.aug.md +63 -0
- package/examples/new-syntax/greeter.aug +10 -0
- package/examples/new-syntax/greeter.aug.md +89 -0
- package/examples/new-syntax/logger.aug +6 -0
- package/examples/new-syntax/logger.aug.md +57 -0
- package/examples/new-syntax/main.aug +12 -0
- package/examples/new-syntax/main.aug.md +64 -0
- package/examples/new-syntax/math.aug +3 -0
- package/examples/new-syntax/math.aug.md +29 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/crypto/contracts.aug +73 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/crypto/contracts.aug.md +791 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/crypto/jose.aug +68 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/crypto/jose.aug.md +266 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/json/contracts.aug +6 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/json/contracts.aug.md +55 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/memory/store.aug +45 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/memory/store.aug.md +250 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/time/contracts.aug +11 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/time/contracts.aug.md +96 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/web/contracts.aug +58 -0
- package/examples/oidc-login/.aug-spec/august/0.19.0/web/contracts.aug.md +420 -0
- package/examples/oidc-login/.aug-spec/manifest.json +40 -0
- package/examples/oidc-login/README.md +29 -0
- package/examples/oidc-login/client/contracts.aug +7 -0
- package/examples/oidc-login/client/contracts.aug.md +80 -0
- package/examples/oidc-login/client/endpoints.aug +21 -0
- package/examples/oidc-login/client/endpoints.aug.md +161 -0
- package/examples/oidc-login/client/export.aug +7 -0
- package/examples/oidc-login/client/export.aug.md +29 -0
- package/examples/oidc-login/client/login.aug +58 -0
- package/examples/oidc-login/client/login.aug.md +331 -0
- package/examples/oidc-login/client/logout.aug +18 -0
- package/examples/oidc-login/client/logout.aug.md +150 -0
- package/examples/oidc-login/client/protocol.aug +106 -0
- package/examples/oidc-login/client/protocol.aug.md +326 -0
- package/examples/oidc-login/client/session.aug +34 -0
- package/examples/oidc-login/client/session.aug.md +155 -0
- package/examples/oidc-login/client/views.aug +21 -0
- package/examples/oidc-login/client/views.aug.md +68 -0
- package/examples/oidc-login/common/export.aug +9 -0
- package/examples/oidc-login/common/export.aug.md +33 -0
- package/examples/oidc-login/common/headers.aug +11 -0
- package/examples/oidc-login/common/headers.aug.md +79 -0
- package/examples/oidc-login/common/keys.aug +37 -0
- package/examples/oidc-login/common/keys.aug.md +207 -0
- package/examples/oidc-login/common/settings.aug +4 -0
- package/examples/oidc-login/common/settings.aug.md +47 -0
- package/examples/oidc-login/common/views.aug +16 -0
- package/examples/oidc-login/common/views.aug.md +34 -0
- package/examples/oidc-login/main.aug +39 -0
- package/examples/oidc-login/main.aug.md +166 -0
- package/examples/oidc-login/main.yaml +12 -0
- package/examples/oidc-login/provider/authorization.aug +59 -0
- package/examples/oidc-login/provider/authorization.aug.md +264 -0
- package/examples/oidc-login/provider/contracts.aug +15 -0
- package/examples/oidc-login/provider/contracts.aug.md +193 -0
- package/examples/oidc-login/provider/credentials.aug +10 -0
- package/examples/oidc-login/provider/credentials.aug.md +64 -0
- package/examples/oidc-login/provider/discovery.aug +13 -0
- package/examples/oidc-login/provider/discovery.aug.md +133 -0
- package/examples/oidc-login/provider/export.aug +13 -0
- package/examples/oidc-login/provider/export.aug.md +41 -0
- package/examples/oidc-login/provider/token.aug +37 -0
- package/examples/oidc-login/provider/token.aug.md +223 -0
- package/examples/oidc-login/provider/userinfo.aug +26 -0
- package/examples/oidc-login/provider/userinfo.aug.md +104 -0
- package/examples/oidc-login/provider/views.aug +18 -0
- package/examples/oidc-login/provider/views.aug.md +63 -0
- package/examples/ownership/.aug-spec/manifest.json +8 -0
- package/examples/ownership/counter.aug +14 -0
- package/examples/ownership/counter.aug.md +85 -0
- package/examples/ownership/main.aug +4 -0
- package/examples/ownership/main.aug.md +38 -0
- package/examples/ownership-transfer/.aug-spec/august/0.19.0/io/contracts.aug +36 -0
- package/examples/ownership-transfer/.aug-spec/august/0.19.0/io/contracts.aug.md +316 -0
- package/examples/ownership-transfer/.aug-spec/manifest.json +10 -0
- package/examples/ownership-transfer/main.aug +9 -0
- package/examples/ownership-transfer/main.aug.md +63 -0
- package/examples/ownership-transfer/resource.aug +16 -0
- package/examples/ownership-transfer/resource.aug.md +89 -0
- package/examples/packages/README.md +15 -0
- package/examples/packages/app/.aug-spec/manifest.json +9 -0
- package/examples/packages/app/.aug-spec/packages/@example/aug-math/0.1.0/arithmetic.aug +9 -0
- package/examples/packages/app/.aug-spec/packages/@example/aug-math/0.1.0/arithmetic.aug.md +63 -0
- package/examples/packages/app/main.aug +2 -0
- package/examples/packages/app/main.aug.md +33 -0
- package/examples/packages/app/main.yaml +2 -0
- package/examples/packages/math/.aug-spec/manifest.json +8 -0
- package/examples/packages/math/README.md +3 -0
- package/examples/packages/math/aug-package.json +8 -0
- package/examples/packages/math/package.json +9 -0
- package/examples/packages/math/src/arithmetic.aug +8 -0
- package/examples/packages/math/src/arithmetic.aug.md +63 -0
- package/examples/packages/math/src/export.aug +1 -0
- package/examples/packages/math/src/export.aug.md +17 -0
- package/examples/visibility/.aug-spec/manifest.json +8 -0
- package/examples/visibility/counter.aug +14 -0
- package/examples/visibility/counter.aug.md +87 -0
- package/examples/visibility/main.aug +7 -0
- package/examples/visibility/main.aug.md +39 -0
- package/package.json +50 -0
- package/runtime/aug_crypto.c +121 -0
- package/runtime/aug_html.c +93 -0
- package/runtime/aug_http.c +829 -0
- package/runtime/aug_json.c +165 -0
- package/runtime/aug_runtime.c +792 -0
- package/runtime/aug_runtime.h +245 -0
- package/runtime/aug_tasks.c +172 -0
- package/runtime/aug_time.c +5 -0
- package/runtime/aug_values.c +80 -0
- package/scripts/bootstrap-native.mjs +121 -0
- package/scripts/native-dependencies.lock.json +65 -0
- package/scripts/native-home.mjs +11 -0
- package/src/actions.js +109 -0
- package/src/ast.js +19 -0
- package/src/builtins.js +93 -0
- package/src/checker.js +2896 -0
- package/src/cli.js +344 -0
- package/src/codegen.js +1159 -0
- package/src/config.js +149 -0
- package/src/continuation.js +110 -0
- package/src/di.js +24 -0
- package/src/documentation.js +27 -0
- package/src/editor.js +782 -0
- package/src/effects.js +29 -0
- package/src/fixes.js +222 -0
- package/src/formatter.js +296 -0
- package/src/freshness.js +154 -0
- package/src/help.js +212 -0
- package/src/html.js +27 -0
- package/src/http-policies.js +90 -0
- package/src/inference.js +16 -0
- package/src/interceptors.js +70 -0
- package/src/javadoc.js +67 -0
- package/src/lexer.js +199 -0
- package/src/libraries.js +31 -0
- package/src/lsp.js +180 -0
- package/src/native.js +144 -0
- package/src/navigation.js +162 -0
- package/src/openapi.js +220 -0
- package/src/ownership.js +232 -0
- package/src/package-manager.js +299 -0
- package/src/parser.js +1155 -0
- package/src/policies.js +130 -0
- package/src/project-init.js +19 -0
- package/src/project.js +292 -0
- package/src/schemas.js +62 -0
- package/src/semantic.js +255 -0
- package/src/spec.js +738 -0
- package/src/testing.js +186 -0
- package/src/types.js +10 -0
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "provider/authorization.aug · OpenID Connect login application"
|
|
3
|
+
generated: true
|
|
4
|
+
source: "examples/oidc-login/provider/authorization.aug"
|
|
5
|
+
editLink: false
|
|
6
|
+
prev: false
|
|
7
|
+
next: false
|
|
8
|
+
outline: [2, 3]
|
|
9
|
+
pageClass: aug-example-page
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# `provider/authorization.aug`
|
|
13
|
+
|
|
14
|
+
[OpenID Connect login application](../index.md) · Source and specification
|
|
15
|
+
|
|
16
|
+
::: details Files in this project
|
|
17
|
+
|
|
18
|
+
- [`main.aug`](../main.md)
|
|
19
|
+
- [`client/contracts.aug`](../client/contracts.md)
|
|
20
|
+
- [`client/endpoints.aug`](../client/endpoints.md)
|
|
21
|
+
- [`client/export.aug`](../client/export.md)
|
|
22
|
+
- [`client/login.aug`](../client/login.md)
|
|
23
|
+
- [`client/logout.aug`](../client/logout.md)
|
|
24
|
+
- [`client/protocol.aug`](../client/protocol.md)
|
|
25
|
+
- [`client/session.aug`](../client/session.md)
|
|
26
|
+
- [`client/views.aug`](../client/views.md)
|
|
27
|
+
- [`common/export.aug`](../common/export.md)
|
|
28
|
+
- [`common/headers.aug`](../common/headers.md)
|
|
29
|
+
- [`common/keys.aug`](../common/keys.md)
|
|
30
|
+
- [`common/settings.aug`](../common/settings.md)
|
|
31
|
+
- [`common/views.aug`](../common/views.md)
|
|
32
|
+
- [`provider/authorization.aug`](authorization.md)
|
|
33
|
+
- [`provider/contracts.aug`](contracts.md)
|
|
34
|
+
- [`provider/credentials.aug`](credentials.md)
|
|
35
|
+
- [`provider/discovery.aug`](discovery.md)
|
|
36
|
+
- [`provider/export.aug`](export.md)
|
|
37
|
+
- [`provider/token.aug`](token.md)
|
|
38
|
+
- [`provider/userinfo.aug`](userinfo.md)
|
|
39
|
+
- [`provider/views.aug`](views.md)
|
|
40
|
+
|
|
41
|
+
:::
|
|
42
|
+
|
|
43
|
+
::::: example-compare
|
|
44
|
+
|
|
45
|
+
:::: example-code
|
|
46
|
+
|
|
47
|
+
## Code {#code}
|
|
48
|
+
|
|
49
|
+
::: code-group
|
|
50
|
+
|
|
51
|
+
```aug [Indentation]
|
|
52
|
+
import AuthorizationRequest and AuthorizationCode and LoginForm and LoginError from contracts
|
|
53
|
+
import ProviderLogin and ProviderFailure from views
|
|
54
|
+
import verifyCredentials from credentials
|
|
55
|
+
import settings and securityHeaders and withCookie from common
|
|
56
|
+
import Crypto from august.crypto
|
|
57
|
+
import Clock from august.time
|
|
58
|
+
import ExpiringStore and StoreFull from august.memory
|
|
59
|
+
import urlEncode from august.web
|
|
60
|
+
/** Validate the registered client before offering a login form. A malformed redirect is never followed. */
|
|
61
|
+
endpoint GET "/provider/authorize" as authorize(string response_type from query, string client_id from query, string redirect_uri from query, string requestedScope from query "scope", string state from query, string nonce from query, string code_challenge from query, string code_challenge_method from query, resolve Crypto crypto, resolve Clock clock, resolve ExpiringStore<AuthorizationRequest> requests) returns HttpResponse<Html> uses crypto.random and crypto.decodeBase64url and clock.now and requests.put unless LoginError with status 400 and CryptoError with status 503 and TimeError with status 503 and StoreFull with status 503 and HttpError:
|
|
62
|
+
config = settings()
|
|
63
|
+
if client_id != config.clientId or redirect_uri != config.callback or response_type != "code" or code_challenge_method != "S256":
|
|
64
|
+
throw LoginError()
|
|
65
|
+
if requestedScope != "openid" and requestedScope != "openid profile":
|
|
66
|
+
throw LoginError()
|
|
67
|
+
if not state.isToken(min=43, max=128) or not nonce.isToken(min=43, max=128) or code_challenge.length() != 43:
|
|
68
|
+
throw LoginError()
|
|
69
|
+
try:
|
|
70
|
+
if crypto.decodeBase64url(input=code_challenge).length() != 32:
|
|
71
|
+
throw LoginError()
|
|
72
|
+
catch CryptoError error:
|
|
73
|
+
throw LoginError()
|
|
74
|
+
requestId = crypto.random(size=32).base64url()
|
|
75
|
+
browser = crypto.random(size=32).base64url()
|
|
76
|
+
csrf = crypto.random(size=32).base64url()
|
|
77
|
+
now = clock.now()
|
|
78
|
+
request = AuthorizationRequest(clientId=client_id, redirectUri=redirect_uri, state=state, nonce=nonce, challenge=code_challenge, browser=browser, csrf=csrf, expires=now + 300)
|
|
79
|
+
requests.put(key=requestId, value=request, expires=request.expires, now=now)
|
|
80
|
+
headers = withCookie(headers=securityHeaders(), name="aug_authorize", value=browser, path="/provider", maxAge=300, secure=config.secureCookies)
|
|
81
|
+
return HttpResponse(body=ProviderLogin(requestId, csrf, message="Authorize the registered August login app.", submit=handle providerLogin(input from form)), headers=headers)
|
|
82
|
+
/** The browser binding and CSRF token are checked before credentials. Each form request is consumed once. */
|
|
83
|
+
endpoint POST "/provider/login" as providerLogin(LoginForm form from form, optional string browser from cookie "aug_authorize", optional string origin from header "origin", resolve Crypto crypto, resolve Clock clock, resolve ExpiringStore<AuthorizationRequest> requests, resolve ExpiringStore<AuthorizationCode> codes) returns HttpResponse<Html> uses crypto.equal and crypto.random and crypto.passwordHash and crypto.decodeBase64url and clock.now and requests.take and codes.put unless CryptoError with status 503 and TimeError with status 503 and StoreFull with status 503 and HttpError:
|
|
84
|
+
config = settings()
|
|
85
|
+
try:
|
|
86
|
+
if origin != config.baseUrl:
|
|
87
|
+
return HttpResponse(body=ProviderFailure(message="The sign-in form must come from this app."), status=403, headers=securityHeaders())
|
|
88
|
+
match requests.take(key=form.request_id, now=clock.now()):
|
|
89
|
+
when null:
|
|
90
|
+
return HttpResponse(body=ProviderFailure(message="The sign-in request expired or was already used."), status=400, headers=securityHeaders())
|
|
91
|
+
when some request:
|
|
92
|
+
match browser:
|
|
93
|
+
when null:
|
|
94
|
+
return HttpResponse(body=ProviderFailure(message="The browser binding is missing."), status=403, headers=securityHeaders())
|
|
95
|
+
when some secret:
|
|
96
|
+
if not crypto.equal(left=secret.bytes(), right=request.browser.bytes()) or not crypto.equal(left=form.csrf.bytes(), right=request.csrf.bytes()):
|
|
97
|
+
return HttpResponse(body=ProviderFailure(message="The sign-in form could not be verified."), status=403, headers=securityHeaders())
|
|
98
|
+
if not verifyCredentials(username=form.username, password=form.password):
|
|
99
|
+
return HttpResponse(body=ProviderFailure(message="The username or password was not accepted."), status=401, headers=securityHeaders())
|
|
100
|
+
now = clock.now()
|
|
101
|
+
code = crypto.random(size=32).base64url()
|
|
102
|
+
grant = AuthorizationCode(clientId=request.clientId, redirectUri=request.redirectUri, challenge=request.challenge, nonce=request.nonce, subject="demo-ada", name="Ada", expires=now + 60)
|
|
103
|
+
codes.put(key=code, value=grant, expires=grant.expires, now=now)
|
|
104
|
+
location = request.redirectUri + "?code=" + urlEncode(input=code) + "&state=" + urlEncode(input=request.state)
|
|
105
|
+
headers = withCookie(headers=securityHeaders().with(name="location", value=location), name="aug_authorize", value="", path="/provider", maxAge=0, secure=config.secureCookies)
|
|
106
|
+
return HttpResponse(body=<p>Returning to the application.</p>, status=303, headers=headers)
|
|
107
|
+
catch HttpError error:
|
|
108
|
+
return HttpResponse(body=ProviderFailure(message="The submitted form is invalid."), status=400, headers=securityHeaders())
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
```aug [Braces]
|
|
112
|
+
import AuthorizationRequest and AuthorizationCode and LoginForm and LoginError from contracts
|
|
113
|
+
import ProviderLogin and ProviderFailure from views
|
|
114
|
+
import verifyCredentials from credentials
|
|
115
|
+
import settings and securityHeaders and withCookie from common
|
|
116
|
+
import Crypto from august.crypto
|
|
117
|
+
import Clock from august.time
|
|
118
|
+
import ExpiringStore and StoreFull from august.memory
|
|
119
|
+
import urlEncode from august.web
|
|
120
|
+
/** Validate the registered client before offering a login form. A malformed redirect is never followed. */
|
|
121
|
+
endpoint GET "/provider/authorize" as authorize(string response_type from query, string client_id from query, string redirect_uri from query, string requestedScope from query "scope", string state from query, string nonce from query, string code_challenge from query, string code_challenge_method from query, resolve Crypto crypto, resolve Clock clock, resolve ExpiringStore<AuthorizationRequest> requests) returns HttpResponse<Html> uses crypto.random and crypto.decodeBase64url and clock.now and requests.put unless LoginError with status 400 and CryptoError with status 503 and TimeError with status 503 and StoreFull with status 503 and HttpError {
|
|
122
|
+
config = settings()
|
|
123
|
+
if client_id != config.clientId or redirect_uri != config.callback or response_type != "code" or code_challenge_method != "S256" {
|
|
124
|
+
throw LoginError()
|
|
125
|
+
}
|
|
126
|
+
if requestedScope != "openid" and requestedScope != "openid profile" {
|
|
127
|
+
throw LoginError()
|
|
128
|
+
}
|
|
129
|
+
if not state.isToken(min=43, max=128) or not nonce.isToken(min=43, max=128) or code_challenge.length() != 43 {
|
|
130
|
+
throw LoginError()
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
if crypto.decodeBase64url(input=code_challenge).length() != 32 {
|
|
134
|
+
throw LoginError()
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch CryptoError error {
|
|
138
|
+
throw LoginError()
|
|
139
|
+
}
|
|
140
|
+
requestId = crypto.random(size=32).base64url()
|
|
141
|
+
browser = crypto.random(size=32).base64url()
|
|
142
|
+
csrf = crypto.random(size=32).base64url()
|
|
143
|
+
now = clock.now()
|
|
144
|
+
request = AuthorizationRequest(clientId=client_id, redirectUri=redirect_uri, state=state, nonce=nonce, challenge=code_challenge, browser=browser, csrf=csrf, expires=now + 300)
|
|
145
|
+
requests.put(key=requestId, value=request, expires=request.expires, now=now)
|
|
146
|
+
headers = withCookie(headers=securityHeaders(), name="aug_authorize", value=browser, path="/provider", maxAge=300, secure=config.secureCookies)
|
|
147
|
+
return HttpResponse(body=ProviderLogin(requestId, csrf, message="Authorize the registered August login app.", submit=handle providerLogin(input from form)), headers=headers)
|
|
148
|
+
}
|
|
149
|
+
/** The browser binding and CSRF token are checked before credentials. Each form request is consumed once. */
|
|
150
|
+
endpoint POST "/provider/login" as providerLogin(LoginForm form from form, optional string browser from cookie "aug_authorize", optional string origin from header "origin", resolve Crypto crypto, resolve Clock clock, resolve ExpiringStore<AuthorizationRequest> requests, resolve ExpiringStore<AuthorizationCode> codes) returns HttpResponse<Html> uses crypto.equal and crypto.random and crypto.passwordHash and crypto.decodeBase64url and clock.now and requests.take and codes.put unless CryptoError with status 503 and TimeError with status 503 and StoreFull with status 503 and HttpError {
|
|
151
|
+
config = settings()
|
|
152
|
+
try {
|
|
153
|
+
if origin != config.baseUrl {
|
|
154
|
+
return HttpResponse(body=ProviderFailure(message="The sign-in form must come from this app."), status=403, headers=securityHeaders())
|
|
155
|
+
}
|
|
156
|
+
match requests.take(key=form.request_id, now=clock.now()) {
|
|
157
|
+
when null {
|
|
158
|
+
return HttpResponse(body=ProviderFailure(message="The sign-in request expired or was already used."), status=400, headers=securityHeaders())
|
|
159
|
+
}
|
|
160
|
+
when some request {
|
|
161
|
+
match browser {
|
|
162
|
+
when null {
|
|
163
|
+
return HttpResponse(body=ProviderFailure(message="The browser binding is missing."), status=403, headers=securityHeaders())
|
|
164
|
+
}
|
|
165
|
+
when some secret {
|
|
166
|
+
if not crypto.equal(left=secret.bytes(), right=request.browser.bytes()) or not crypto.equal(left=form.csrf.bytes(), right=request.csrf.bytes()) {
|
|
167
|
+
return HttpResponse(body=ProviderFailure(message="The sign-in form could not be verified."), status=403, headers=securityHeaders())
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if not verifyCredentials(username=form.username, password=form.password) {
|
|
172
|
+
return HttpResponse(body=ProviderFailure(message="The username or password was not accepted."), status=401, headers=securityHeaders())
|
|
173
|
+
}
|
|
174
|
+
now = clock.now()
|
|
175
|
+
code = crypto.random(size=32).base64url()
|
|
176
|
+
grant = AuthorizationCode(clientId=request.clientId, redirectUri=request.redirectUri, challenge=request.challenge, nonce=request.nonce, subject="demo-ada", name="Ada", expires=now + 60)
|
|
177
|
+
codes.put(key=code, value=grant, expires=grant.expires, now=now)
|
|
178
|
+
location = request.redirectUri + "?code=" + urlEncode(input=code) + "&state=" + urlEncode(input=request.state)
|
|
179
|
+
headers = withCookie(headers=securityHeaders().with(name="location", value=location), name="aug_authorize", value="", path="/provider", maxAge=0, secure=config.secureCookies)
|
|
180
|
+
return HttpResponse(body=<p>Returning to the application.</p>, status=303, headers=headers)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
catch HttpError error {
|
|
185
|
+
return HttpResponse(body=ProviderFailure(message="The submitted form is invalid."), status=400, headers=securityHeaders())
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
:::
|
|
191
|
+
|
|
192
|
+
::::
|
|
193
|
+
|
|
194
|
+
:::: example-spec
|
|
195
|
+
|
|
196
|
+
## Compiled specification {#specification}
|
|
197
|
+
|
|
198
|
+
August 0.19.0. This document is compiled from checked code with deterministic wording guided by Simplified Technical English.
|
|
199
|
+
|
|
200
|
+
### In this file
|
|
201
|
+
|
|
202
|
+
- [`authorize`](authorization.md#symbol-authorize) handles `GET` `/provider/authorize` returning `HttpResponse<Html>`.
|
|
203
|
+
- [`providerLogin`](authorization.md#symbol-providerLogin) handles `POST` `/provider/login` returning `HttpResponse<Html>`.
|
|
204
|
+
|
|
205
|
+
### `authorize` {#symbol-authorize}
|
|
206
|
+
|
|
207
|
+
[source](authorization.md#code)
|
|
208
|
+
|
|
209
|
+
**Inputs**
|
|
210
|
+
|
|
211
|
+
- `response_type` (`string`) — read from the HTTP query.
|
|
212
|
+
- `client_id` (`string`) — read from the HTTP query.
|
|
213
|
+
- `redirect_uri` (`string`) — read from the HTTP query.
|
|
214
|
+
- `requestedScope` (`string`) — read from the HTTP query named `scope`.
|
|
215
|
+
- `state` (`string`) — read from the HTTP query.
|
|
216
|
+
- `nonce` (`string`) — read from the HTTP query.
|
|
217
|
+
- `code_challenge` (`string`) — read from the HTTP query.
|
|
218
|
+
- `code_challenge_method` (`string`) — read from the HTTP query.
|
|
219
|
+
- `crypto` ([`Crypto`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto)) — injected; callers omit it.
|
|
220
|
+
- `clock` ([`Clock`](../dependencies/august/0.19.0/time/contracts.md#symbol-Clock)) — injected; callers omit it.
|
|
221
|
+
- `requests` ([`ExpiringStore<AuthorizationRequest>`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore)) — injected; callers omit it.
|
|
222
|
+
|
|
223
|
+
Returns: `HttpResponse<Html>`.
|
|
224
|
+
|
|
225
|
+
Capabilities: [`crypto.random`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.random), [`crypto.decodeBase64url`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.decodeBase64url), [`clock.now`](../dependencies/august/0.19.0/time/contracts.md#symbol-Clock.now), [`requests.put`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore.put).
|
|
226
|
+
|
|
227
|
+
Can fail with `LoginError`, `CryptoError`, `TimeError`, `StoreFull`, `HttpError`. Callers must catch or propagate these errors.
|
|
228
|
+
|
|
229
|
+
HTTP route: `GET` `/provider/authorize`. Use status 200 when the handler returns a body; a returned HttpResponse can set its own status. An unhandled request failure returns status 500 and cancels its request tasks.
|
|
230
|
+
|
|
231
|
+
Declared HTTP failures: [`LoginError`](contracts.md#symbol-LoginError) returns status 400; `CryptoError` returns status 503; `TimeError` returns status 503; [`StoreFull`](../dependencies/august/0.19.0/memory/store.md#symbol-StoreFull) returns status 503.
|
|
232
|
+
|
|
233
|
+
**What it does**
|
|
234
|
+
|
|
235
|
+
- Set `config` to call [`settings`](../common/settings.md#symbol-settings).
|
|
236
|
+
- If (((`client_id` does not equal `clientId` of `config`) or (`redirect_uri` does not equal `callback` of `config`)) or (`response_type` does not equal `"code"`)) or (`code_challenge_method` does not equal `"S256"`):
|
|
237
|
+
- Fail with call [`LoginError`](contracts.md#symbol-LoginError). Transfer control to a matching catch or propagate the failure.
|
|
238
|
+
- If (`requestedScope` does not equal `"openid"`) and (`requestedScope` does not equal `"openid profile"`):
|
|
239
|
+
- Fail with call [`LoginError`](contracts.md#symbol-LoginError). Transfer control to a matching catch or propagate the failure.
|
|
240
|
+
- If (not (call `isToken` on `state` with `min` = `43`; `max` = `128`) or not (call `isToken` on `nonce` with `min` = `43`; `max` = `128`)) or (call `length` on `code_challenge` does not equal `43`):
|
|
241
|
+
- Fail with call [`LoginError`](contracts.md#symbol-LoginError). Transfer control to a matching catch or propagate the failure.
|
|
242
|
+
- Try these operations:
|
|
243
|
+
- If call `length` on call [`Crypto.decodeBase64url`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.decodeBase64url) on `crypto` with `input` = `code_challenge` does not equal `32`:
|
|
244
|
+
- Fail with call [`LoginError`](contracts.md#symbol-LoginError). Transfer control to a matching catch or propagate the failure.
|
|
245
|
+
- If they fail with `CryptoError`, name the failure `error` and recover:
|
|
246
|
+
- Fail with call [`LoginError`](contracts.md#symbol-LoginError). Transfer control to a matching catch or propagate the failure.
|
|
247
|
+
- Set `requestId` to call `base64url` on call [`Crypto.random`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.random) on `crypto` with `size` = `32`.
|
|
248
|
+
- Set `browser` to call `base64url` on call [`Crypto.random`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.random) on `crypto` with `size` = `32`.
|
|
249
|
+
- Set `csrf` to call `base64url` on call [`Crypto.random`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.random) on `crypto` with `size` = `32`.
|
|
250
|
+
- Set `now` to call [`Clock.now`](../dependencies/august/0.19.0/time/contracts.md#symbol-Clock.now) on `clock`.
|
|
251
|
+
- Set `request` to call [`AuthorizationRequest`](contracts.md#symbol-AuthorizationRequest) with `clientId` = `client_id`; `redirectUri` = `redirect_uri`; `state` = `state`; `nonce` = `nonce`; `challenge` = `code_challenge`; `browser` = `browser`; `csrf` = `csrf`; `expires` = (`now` plus `300`).
|
|
252
|
+
- Call [`ExpiringStore.put`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore.put) on `requests` with `key` = `requestId`; `value` = `request`; `expires` = `expires` of `request`; `now` = `now`.
|
|
253
|
+
- Set `headers` to call [`withCookie`](../common/headers.md#symbol-withCookie) with `headers` = call [`securityHeaders`](../common/headers.md#symbol-securityHeaders); `name` = `"aug_authorize"`; `value` = `browser`; `path` = `"/provider"`; `maxAge` = `300`; `secure` = `secureCookies` of `config`.
|
|
254
|
+
- Return call `HttpResponse` with `body` = call [`ProviderLogin`](views.md#symbol-ProviderLogin) with `requestId` = `requestId`; `csrf` = `csrf`; `message` = `"Authorize the registered August login app."`; `submit` = a deferred HTTP form action for [`providerLogin`](authorization.md#symbol-providerLogin); inputs: `1` from the checked form input supplied when the HTTP form is submitted; capture supplied values when rendering, and read form inputs when submitted; send the form to that endpoint with its declared HTTP method; `headers` = `headers`.
|
|
255
|
+
|
|
256
|
+
**Author documentation**
|
|
257
|
+
|
|
258
|
+
Validate the registered client before offering a login form. A malformed redirect is never followed.
|
|
259
|
+
|
|
260
|
+
### `providerLogin` {#symbol-providerLogin}
|
|
261
|
+
|
|
262
|
+
[source](authorization.md#code)
|
|
263
|
+
|
|
264
|
+
**Inputs**
|
|
265
|
+
|
|
266
|
+
- `form` ([`LoginForm`](contracts.md#symbol-LoginForm)) — read from the HTTP form.
|
|
267
|
+
- `browser` (`optional string`) — read from the HTTP cookie named `aug_authorize`; absent value becomes null.
|
|
268
|
+
- `origin` (`optional string`) — read from the HTTP header named `origin`; absent value becomes null.
|
|
269
|
+
- `crypto` ([`Crypto`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto)) — injected; callers omit it.
|
|
270
|
+
- `clock` ([`Clock`](../dependencies/august/0.19.0/time/contracts.md#symbol-Clock)) — injected; callers omit it.
|
|
271
|
+
- `requests` ([`ExpiringStore<AuthorizationRequest>`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore)) — injected; callers omit it.
|
|
272
|
+
- `codes` ([`ExpiringStore<AuthorizationCode>`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore)) — injected; callers omit it.
|
|
273
|
+
|
|
274
|
+
Returns: `HttpResponse<Html>`.
|
|
275
|
+
|
|
276
|
+
Capabilities: [`crypto.equal`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.equal), [`crypto.random`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.random), [`crypto.passwordHash`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.passwordHash), [`crypto.decodeBase64url`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.decodeBase64url), [`clock.now`](../dependencies/august/0.19.0/time/contracts.md#symbol-Clock.now), [`requests.take`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore.take), [`codes.put`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore.put).
|
|
277
|
+
|
|
278
|
+
Can fail with `CryptoError`, `TimeError`, `StoreFull`, `HttpError`. Callers must catch or propagate these errors.
|
|
279
|
+
|
|
280
|
+
HTTP route: `POST` `/provider/login`. Use status 200 when the handler returns a body; a returned HttpResponse can set its own status. An unhandled request failure returns status 500 and cancels its request tasks.
|
|
281
|
+
|
|
282
|
+
Declared HTTP failures: `CryptoError` returns status 503; `TimeError` returns status 503; [`StoreFull`](../dependencies/august/0.19.0/memory/store.md#symbol-StoreFull) returns status 503.
|
|
283
|
+
|
|
284
|
+
**What it does**
|
|
285
|
+
|
|
286
|
+
- Set `config` to call [`settings`](../common/settings.md#symbol-settings).
|
|
287
|
+
- Try these operations:
|
|
288
|
+
- If `origin` does not equal `baseUrl` of `config`:
|
|
289
|
+
- Return call `HttpResponse` with `body` = call [`ProviderFailure`](views.md#symbol-ProviderFailure) with `message` = `"The sign-in form must come from this app."`; `status` = `403`; `headers` = call [`securityHeaders`](../common/headers.md#symbol-securityHeaders).
|
|
290
|
+
- Select the matching case for call [`ExpiringStore.take`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore.take) on `requests` with `key` = `request_id` of `form`; `now` = call [`Clock.now`](../dependencies/august/0.19.0/time/contracts.md#symbol-Clock.now) on `clock`:
|
|
291
|
+
- A null value, including omitted optional input:
|
|
292
|
+
- Return call `HttpResponse` with `body` = call [`ProviderFailure`](views.md#symbol-ProviderFailure) with `message` = `"The sign-in request expired or was already used."`; `status` = `400`; `headers` = call [`securityHeaders`](../common/headers.md#symbol-securityHeaders).
|
|
293
|
+
- A present, non-null value, named `request`:
|
|
294
|
+
- Select the matching case for `browser`:
|
|
295
|
+
- A null value, including omitted optional input:
|
|
296
|
+
- Return call `HttpResponse` with `body` = call [`ProviderFailure`](views.md#symbol-ProviderFailure) with `message` = `"The browser binding is missing."`; `status` = `403`; `headers` = call [`securityHeaders`](../common/headers.md#symbol-securityHeaders).
|
|
297
|
+
- A present, non-null value, named `secret`:
|
|
298
|
+
- If not (call [`Crypto.equal`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.equal) on `crypto` with `left` = call `bytes` on `secret`; `right` = call `bytes` on `browser` of `request`) or not (call [`Crypto.equal`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.equal) on `crypto` with `left` = call `bytes` on `csrf` of `form`; `right` = call `bytes` on `csrf` of `request`):
|
|
299
|
+
- Return call `HttpResponse` with `body` = call [`ProviderFailure`](views.md#symbol-ProviderFailure) with `message` = `"The sign-in form could not be verified."`; `status` = `403`; `headers` = call [`securityHeaders`](../common/headers.md#symbol-securityHeaders).
|
|
300
|
+
- If not (call [`verifyCredentials`](credentials.md#symbol-verifyCredentials) with `username` = `username` of `form`; `password` = `password` of `form`; inject `crypto` from `crypto`):
|
|
301
|
+
- Return call `HttpResponse` with `body` = call [`ProviderFailure`](views.md#symbol-ProviderFailure) with `message` = `"The username or password was not accepted."`; `status` = `401`; `headers` = call [`securityHeaders`](../common/headers.md#symbol-securityHeaders).
|
|
302
|
+
- Set `now` to call [`Clock.now`](../dependencies/august/0.19.0/time/contracts.md#symbol-Clock.now) on `clock`.
|
|
303
|
+
- Set `code` to call `base64url` on call [`Crypto.random`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.random) on `crypto` with `size` = `32`.
|
|
304
|
+
- Set `grant` to call [`AuthorizationCode`](contracts.md#symbol-AuthorizationCode) with `clientId` = `clientId` of `request`; `redirectUri` = `redirectUri` of `request`; `challenge` = `challenge` of `request`; `nonce` = `nonce` of `request`; `subject` = `"demo-ada"`; `name` = `"Ada"`; `expires` = (`now` plus `60`).
|
|
305
|
+
- Call [`ExpiringStore.put`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore.put) on `codes` with `key` = `code`; `value` = `grant`; `expires` = `expires` of `grant`; `now` = `now`.
|
|
306
|
+
- Build `location` by joining these text parts without separators, in order:
|
|
307
|
+
1. `redirectUri` of `request`
|
|
308
|
+
2. `"?code="`
|
|
309
|
+
3. call [`urlEncode`](../dependencies/august/0.19.0/web/contracts.md#symbol-urlEncode) with `input` = `code`
|
|
310
|
+
4. `"&state="`
|
|
311
|
+
5. call [`urlEncode`](../dependencies/august/0.19.0/web/contracts.md#symbol-urlEncode) with `input` = `state` of `request`
|
|
312
|
+
- Set `headers` to call [`withCookie`](../common/headers.md#symbol-withCookie) with `headers` = call `with` on call [`securityHeaders`](../common/headers.md#symbol-securityHeaders) with `name` = `"location"`; `value` = `location`; `name` = `"aug_authorize"`; `value` = `""`; `path` = `"/provider"`; `maxAge` = `0`; `secure` = `secureCookies` of `config`.
|
|
313
|
+
- Return call `HttpResponse` with `body` = the HTML element `p` containing `Returning to the application.` (rendered on the server with embedded text escaped); `status` = `303`; `headers` = `headers`.
|
|
314
|
+
- If they fail with `HttpError`, name the failure `error` and recover:
|
|
315
|
+
- Return call `HttpResponse` with `body` = call [`ProviderFailure`](views.md#symbol-ProviderFailure) with `message` = `"The submitted form is invalid."`; `status` = `400`; `headers` = call [`securityHeaders`](../common/headers.md#symbol-securityHeaders).
|
|
316
|
+
|
|
317
|
+
**Author documentation**
|
|
318
|
+
|
|
319
|
+
The browser binding and CSRF token are checked before credentials. Each form request is consumed once.
|
|
320
|
+
|
|
321
|
+
### Dependencies used by this file
|
|
322
|
+
|
|
323
|
+
Only referenced types and operations appear here. Each name links to its complete specification.
|
|
324
|
+
|
|
325
|
+
#### [`Crypto`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto)
|
|
326
|
+
|
|
327
|
+
Capability interface from `august.crypto`.
|
|
328
|
+
|
|
329
|
+
- [`Crypto.decodeBase64url`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.decodeBase64url) (`input`: `string`) → `Bytes`; can fail with `CryptoError`.
|
|
330
|
+
- [`Crypto.equal`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.equal) (`left`: `Bytes`, `right`: `Bytes`) → `bool`.
|
|
331
|
+
- [`Crypto.passwordHash`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.passwordHash) (`password`: `Bytes`, `salt`: `Bytes`, `iterations`: `int`) → `Bytes`; can fail with `CryptoError`.
|
|
332
|
+
- [`Crypto.random`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.random) (`size`: `int`) → `Bytes`; can fail with `CryptoError`.
|
|
333
|
+
|
|
334
|
+
#### [`ExpiringStore`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore)
|
|
335
|
+
|
|
336
|
+
Capability interface from `august.memory`.
|
|
337
|
+
|
|
338
|
+
- [`ExpiringStore.put`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore.put) (`key`: `string`, `value`: `T`, `expires`: `int`, `now`: `int`) → `void`; can fail with `StoreFull`.
|
|
339
|
+
- [`ExpiringStore.take`](../dependencies/august/0.19.0/memory/store.md#symbol-ExpiringStore.take) (`key`: `string`, `now`: `int`) → `optional T`.
|
|
340
|
+
|
|
341
|
+
#### [`StoreFull`](../dependencies/august/0.19.0/memory/store.md#symbol-StoreFull)
|
|
342
|
+
|
|
343
|
+
Class from `august.memory`.
|
|
344
|
+
|
|
345
|
+
Used as a type or provider.
|
|
346
|
+
|
|
347
|
+
#### [`Clock`](../dependencies/august/0.19.0/time/contracts.md#symbol-Clock)
|
|
348
|
+
|
|
349
|
+
Capability interface from `august.time`.
|
|
350
|
+
|
|
351
|
+
- [`Clock.now`](../dependencies/august/0.19.0/time/contracts.md#symbol-Clock.now) (no caller inputs) → `int`; can fail with `TimeError`.
|
|
352
|
+
|
|
353
|
+
#### [`urlEncode`](../dependencies/august/0.19.0/web/contracts.md#symbol-urlEncode)
|
|
354
|
+
|
|
355
|
+
Function from `august.web`.
|
|
356
|
+
|
|
357
|
+
- [`urlEncode`](../dependencies/august/0.19.0/web/contracts.md#symbol-urlEncode) (`input`: `string`) → `string`; can fail with `HttpError`.
|
|
358
|
+
|
|
359
|
+
#### [`securityHeaders`](../common/headers.md#symbol-securityHeaders)
|
|
360
|
+
|
|
361
|
+
Function from `common`.
|
|
362
|
+
|
|
363
|
+
- [`securityHeaders`](../common/headers.md#symbol-securityHeaders) (no caller inputs) → `Headers`; can fail with `HttpError`.
|
|
364
|
+
|
|
365
|
+
#### [`withCookie`](../common/headers.md#symbol-withCookie)
|
|
366
|
+
|
|
367
|
+
Function from `common`.
|
|
368
|
+
|
|
369
|
+
- [`withCookie`](../common/headers.md#symbol-withCookie) (`headers`: `Headers`, `name`: `string`, `value`: `string`, `path`: `string`, `maxAge`: `int`, `secure`: `bool`) → `Headers`; can fail with `HttpError`.
|
|
370
|
+
|
|
371
|
+
#### [`Settings`](../common/settings.md#symbol-Settings)
|
|
372
|
+
|
|
373
|
+
Record.
|
|
374
|
+
|
|
375
|
+
- Read `baseUrl` (`string`).
|
|
376
|
+
- Read `callback` (`string`).
|
|
377
|
+
- Read `clientId` (`string`).
|
|
378
|
+
- Read `secureCookies` (`bool`).
|
|
379
|
+
|
|
380
|
+
#### [`settings`](../common/settings.md#symbol-settings)
|
|
381
|
+
|
|
382
|
+
Function from `common`.
|
|
383
|
+
|
|
384
|
+
- [`settings`](../common/settings.md#symbol-settings) (no caller inputs) → [`Settings`](../common/settings.md#symbol-Settings).
|
|
385
|
+
|
|
386
|
+
#### [`AuthorizationCode`](contracts.md#symbol-AuthorizationCode)
|
|
387
|
+
|
|
388
|
+
Record from `contracts`.
|
|
389
|
+
|
|
390
|
+
- Construct with `clientId`: `string`, `redirectUri`: `string`, `challenge`: `string`, `nonce`: `string`, `subject`: `string`, `name`: `string`, `expires`: `int` → [`AuthorizationCode`](contracts.md#symbol-AuthorizationCode).
|
|
391
|
+
- Read `expires` (`int`).
|
|
392
|
+
|
|
393
|
+
#### [`AuthorizationRequest`](contracts.md#symbol-AuthorizationRequest)
|
|
394
|
+
|
|
395
|
+
Record from `contracts`.
|
|
396
|
+
|
|
397
|
+
- Construct with `clientId`: `string`, `redirectUri`: `string`, `state`: `string`, `nonce`: `string`, `challenge`: `string`, `browser`: `string`, `csrf`: `string`, `expires`: `int` → [`AuthorizationRequest`](contracts.md#symbol-AuthorizationRequest).
|
|
398
|
+
- Read `browser` (`string`).
|
|
399
|
+
- Read `challenge` (`string`).
|
|
400
|
+
- Read `clientId` (`string`).
|
|
401
|
+
- Read `csrf` (`string`).
|
|
402
|
+
- Read `expires` (`int`).
|
|
403
|
+
- Read `nonce` (`string`).
|
|
404
|
+
- Read `redirectUri` (`string`).
|
|
405
|
+
- Read `state` (`string`).
|
|
406
|
+
|
|
407
|
+
#### [`LoginError`](contracts.md#symbol-LoginError)
|
|
408
|
+
|
|
409
|
+
Class from `contracts`.
|
|
410
|
+
|
|
411
|
+
- Construct with no caller inputs → [`LoginError`](contracts.md#symbol-LoginError).
|
|
412
|
+
|
|
413
|
+
#### [`LoginForm`](contracts.md#symbol-LoginForm)
|
|
414
|
+
|
|
415
|
+
Record from `contracts`.
|
|
416
|
+
|
|
417
|
+
- Read `csrf` (`string`).
|
|
418
|
+
- Read `password` (`string`).
|
|
419
|
+
- Read `request_id` (`string`).
|
|
420
|
+
- Read `username` (`string`).
|
|
421
|
+
|
|
422
|
+
#### [`verifyCredentials`](credentials.md#symbol-verifyCredentials)
|
|
423
|
+
|
|
424
|
+
Function from `credentials`.
|
|
425
|
+
|
|
426
|
+
- [`verifyCredentials`](credentials.md#symbol-verifyCredentials) (`username`: `string`, `password`: `string`) → `bool`; inject `crypto`: [`Crypto`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto); uses [`crypto.passwordHash`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.passwordHash), [`crypto.decodeBase64url`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.decodeBase64url), [`crypto.equal`](../dependencies/august/0.19.0/crypto/contracts.md#symbol-Crypto.equal); can fail with `CryptoError`.
|
|
427
|
+
|
|
428
|
+
#### [`ProviderFailure`](views.md#symbol-ProviderFailure)
|
|
429
|
+
|
|
430
|
+
Function from `views`.
|
|
431
|
+
|
|
432
|
+
- [`ProviderFailure`](views.md#symbol-ProviderFailure) (`message`: `string`) → `Html`.
|
|
433
|
+
|
|
434
|
+
#### [`ProviderLogin`](views.md#symbol-ProviderLogin)
|
|
435
|
+
|
|
436
|
+
Function from `views`.
|
|
437
|
+
|
|
438
|
+
- [`ProviderLogin`](views.md#symbol-ProviderLogin) (`requestId`: `string`, `csrf`: `string`, `message`: `string`, `submit`: `HttpAction`) → `Html`.
|
|
439
|
+
|
|
440
|
+
### Built-in operations used by this file
|
|
441
|
+
|
|
442
|
+
- `Bytes.base64url` (no inputs) → `string`: Encode immutable bytes as unpadded RFC 4648 URL-safe base64.
|
|
443
|
+
- `Bytes.length` (no inputs) → `int`: Read the number of elements.
|
|
444
|
+
- `Headers.with` (`name`: `string`, `value`: `string`) → `Headers`: Return new headers with one additional validated field. Header names ignore case; duplicate values remain separate. Can fail with `HttpError`.
|
|
445
|
+
- `string.bytes` (no inputs) → `Bytes`: Encode this string as immutable UTF-8 bytes.
|
|
446
|
+
- `string.isToken` (`min`: `int`, `max`: `int`) → `bool`: Require an ASCII RFC 3986 unreserved token with a bounded length.
|
|
447
|
+
- `string.length` (no inputs) → `int`: Read the number of UTF-8 bytes. Unicode text is preserved losslessly.
|
|
448
|
+
|
|
449
|
+
[Full built-in reference](https://greenpandastudios.github.io/augscript/language-constructs).
|
|
450
|
+
|
|
451
|
+
### Shared language rules
|
|
452
|
+
|
|
453
|
+
See the [language reference](https://greenpandastudios.github.io/augscript/reference) for numeric, equality, ownership, and task rules.
|
|
454
|
+
|
|
455
|
+
::::
|
|
456
|
+
|
|
457
|
+
:::::
|