@greenpandastudios/aug-cli 0.19.0 → 0.20.1
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/README.md +9 -6
- package/THIRD_PARTY_NOTICES.md +4 -0
- package/bin/aug.mjs +12 -2
- package/docs/about.md +27 -0
- package/docs/api/crypto.md +103 -69
- package/docs/api/io.md +35 -33
- package/docs/api/json.md +3 -3
- package/docs/api/memory.md +23 -19
- package/docs/api/time.md +10 -9
- package/docs/api/web.md +33 -38
- package/docs/compatibility.md +3 -3
- package/docs/contributing-benchmarks.md +38 -0
- package/docs/dev-containers.md +95 -0
- package/docs/diagnostics.md +15 -5
- package/docs/docker.md +174 -12
- package/docs/editor.md +35 -0
- package/docs/example-projects.json +206 -24
- package/docs/examples/approved-design/counters.md +34 -126
- package/docs/examples/approved-design/dependencies/august/0.20.1/io/contracts.md +178 -0
- package/docs/examples/approved-design/domain/app.md +13 -77
- package/docs/examples/approved-design/domain/export.md +5 -19
- package/docs/examples/approved-design/domain/models.md +4 -23
- package/docs/examples/approved-design/domain/numbers.md +24 -114
- package/docs/examples/approved-design/index.md +16 -7
- package/docs/examples/approved-design/main.md +19 -96
- package/docs/examples/benchmark/index.md +6 -5
- package/docs/examples/benchmark/main.md +7 -35
- package/docs/examples/cli-args/index.md +6 -5
- package/docs/examples/cli-args/main.md +6 -31
- package/docs/examples/collections/index.md +6 -5
- package/docs/examples/collections/main.md +7 -35
- package/docs/examples/collections-benchmark/index.md +6 -5
- package/docs/examples/collections-benchmark/main.md +7 -35
- package/docs/examples/cpu-benchmark/index.md +6 -5
- package/docs/examples/cpu-benchmark/main.md +5 -24
- package/docs/examples/developer-workflow/calculator.md +39 -186
- package/docs/examples/developer-workflow/dependencies/august/0.20.1/io/contracts.md +178 -0
- package/docs/examples/developer-workflow/index.md +16 -7
- package/docs/examples/developer-workflow/logging/console.md +10 -56
- package/docs/examples/developer-workflow/logging/export.md +4 -14
- package/docs/examples/developer-workflow/logging/logger.md +7 -43
- package/docs/examples/developer-workflow/main.md +17 -69
- package/docs/examples/drop/index.md +6 -5
- package/docs/examples/drop/main.md +7 -27
- package/docs/examples/drop/resource.md +7 -30
- package/docs/examples/errors/errors.md +7 -27
- package/docs/examples/errors/index.md +6 -5
- package/docs/examples/errors/main.md +7 -28
- package/docs/examples/ffi/index.md +6 -5
- package/docs/examples/ffi/main.md +6 -20
- package/docs/examples/ffi/native.md +8 -34
- package/docs/examples/generic-di/dependencies/august/0.20.1/io/contracts.md +178 -0
- package/docs/examples/generic-di/index.md +6 -5
- package/docs/examples/generic-di/main.md +9 -39
- package/docs/examples/generic-di/types.md +23 -92
- package/docs/examples/generics/index.md +6 -5
- package/docs/examples/generics/main.md +10 -47
- package/docs/examples/generics/types.md +25 -100
- package/docs/examples/hello/app/export.md +4 -12
- package/docs/examples/hello/app/greeter.md +13 -91
- package/docs/examples/hello/dependencies/august/0.20.1/io/contracts.md +178 -0
- package/docs/examples/hello/index.md +17 -6
- package/docs/examples/hello/logging/console.md +10 -54
- package/docs/examples/hello/logging/export.md +4 -14
- package/docs/examples/hello/logging/logger.md +7 -45
- package/docs/examples/hello/main.md +9 -39
- package/docs/examples/http-benchmark/index.md +6 -5
- package/docs/examples/http-benchmark/main.md +6 -20
- package/docs/examples/http-benchmark/routes.md +9 -31
- package/docs/examples/index.md +46 -29
- package/docs/examples/interceptors/app.md +20 -139
- package/docs/examples/interceptors/dependencies/august/0.20.1/io/contracts.md +178 -0
- package/docs/examples/interceptors/index.md +6 -5
- package/docs/examples/interceptors/interceptors.md +24 -148
- package/docs/examples/interceptors/logging.md +13 -76
- package/docs/examples/interceptors/main.md +10 -65
- package/docs/examples/json-benchmark/data.md +4 -20
- package/docs/examples/json-benchmark/dependencies/packages/@git/url_2d3c37c690c0fa115be1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md +67 -0
- package/docs/examples/json-benchmark/index.md +7 -5
- package/docs/examples/json-benchmark/main-yaml.md +20 -0
- package/docs/examples/json-benchmark/main.md +10 -49
- package/docs/examples/new-syntax/console.md +10 -52
- package/docs/examples/new-syntax/dependencies/august/0.20.1/io/contracts.md +178 -0
- package/docs/examples/new-syntax/greeter.md +13 -71
- package/docs/examples/new-syntax/index.md +6 -5
- package/docs/examples/new-syntax/logger.md +7 -43
- package/docs/examples/new-syntax/main.md +10 -53
- package/docs/examples/new-syntax/math.md +6 -24
- package/docs/examples/oidc-login/client/contracts.md +10 -61
- package/docs/examples/oidc-login/client/endpoints.md +32 -154
- package/docs/examples/oidc-login/client/export.md +5 -23
- package/docs/examples/oidc-login/client/login.md +234 -344
- package/docs/examples/oidc-login/client/logout.md +38 -143
- package/docs/examples/oidc-login/client/protocol.md +183 -304
- package/docs/examples/oidc-login/client/session.md +41 -149
- package/docs/examples/oidc-login/client/views.md +13 -58
- package/docs/examples/oidc-login/common/export.md +6 -26
- package/docs/examples/oidc-login/common/headers.md +42 -72
- package/docs/examples/oidc-login/common/keys.md +40 -164
- package/docs/examples/oidc-login/common/settings.md +24 -40
- package/docs/examples/oidc-login/common/views.md +7 -28
- package/docs/examples/oidc-login/dependencies/packages/@git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md +205 -0
- package/docs/examples/oidc-login/dependencies/packages/@git/url_2d3c37c690c0fa115be1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md +67 -0
- package/docs/examples/oidc-login/dependencies/packages/@git/url_897efafd565158fc4908/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md +267 -0
- package/docs/examples/oidc-login/dependencies/packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md +415 -0
- package/docs/examples/oidc-login/dependencies/packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/jose.md +271 -0
- package/docs/examples/oidc-login/dependencies/packages/@git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md +89 -0
- package/docs/examples/oidc-login/index.md +8 -7
- package/docs/examples/oidc-login/main-yaml.md +7 -0
- package/docs/examples/oidc-login/main.md +26 -153
- package/docs/examples/oidc-login/provider/authorization.md +232 -275
- package/docs/examples/oidc-login/provider/contracts.md +24 -146
- package/docs/examples/oidc-login/provider/credentials.md +24 -57
- package/docs/examples/oidc-login/provider/discovery.md +48 -122
- package/docs/examples/oidc-login/provider/export.md +11 -37
- package/docs/examples/oidc-login/provider/token.md +159 -237
- package/docs/examples/oidc-login/provider/userinfo.md +47 -102
- package/docs/examples/oidc-login/provider/views.md +13 -53
- package/docs/examples/ownership/counter.md +17 -63
- package/docs/examples/ownership/index.md +6 -5
- package/docs/examples/ownership/main.md +7 -30
- package/docs/examples/ownership-transfer/dependencies/august/0.20.1/io/contracts.md +178 -0
- package/docs/examples/ownership-transfer/index.md +6 -5
- package/docs/examples/ownership-transfer/main.md +10 -52
- package/docs/examples/ownership-transfer/resource.md +15 -67
- package/docs/examples/packages-app/dependencies/packages/@example/aug-math/0.1.0/arithmetic.md +12 -50
- package/docs/examples/packages-app/index.md +7 -6
- package/docs/examples/packages-app/main.md +7 -25
- package/docs/examples/packages-math/aug-package-json.md +1 -1
- package/docs/examples/packages-math/index.md +7 -6
- package/docs/examples/packages-math/src/arithmetic.md +12 -50
- package/docs/examples/packages-math/src/export.md +4 -12
- package/docs/examples/startup-benchmark/index.md +6 -5
- package/docs/examples/startup-benchmark/main.md +5 -17
- package/docs/examples/visibility/counter.md +19 -67
- package/docs/examples/visibility/index.md +6 -5
- package/docs/examples/visibility/main.md +7 -31
- package/docs/examples/weather-api/forecasts.md +168 -0
- package/docs/examples/weather-api/index.md +42 -0
- package/docs/examples/weather-api/main-yaml.md +21 -0
- package/docs/examples/weather-api/main.md +65 -0
- package/docs/examples.json +10 -0
- package/docs/getting-started.md +105 -2
- package/docs/grammar.md +6 -4
- package/docs/guides/change-a-module.md +64 -0
- package/docs/guides/index.md +27 -0
- package/docs/index.md +51 -29
- package/docs/language-conformance.md +1 -1
- package/docs/language-constructs.md +22 -22
- package/docs/language-design-audit.md +1 -1
- package/docs/learn/data-and-errors.md +77 -0
- package/docs/learn/index.md +30 -0
- package/docs/learn/modules-and-dependencies.md +73 -0
- package/docs/learn/state-and-tests.md +71 -0
- package/docs/learn/values-and-functions.md +62 -0
- package/docs/lesson-failures.json +8 -0
- package/docs/maintaining-docs.md +16 -4
- package/docs/packages.md +72 -126
- package/docs/performance.md +13 -41
- package/docs/production-readiness.md +5 -4
- package/docs/public/downloads/approved-design.zip +0 -0
- package/docs/public/downloads/benchmark.zip +0 -0
- package/docs/public/downloads/cli-args.zip +0 -0
- package/docs/public/downloads/collections-benchmark.zip +0 -0
- package/docs/public/downloads/collections.zip +0 -0
- package/docs/public/downloads/cpu-benchmark.zip +0 -0
- package/docs/public/downloads/developer-workflow.zip +0 -0
- package/docs/public/downloads/drop.zip +0 -0
- package/docs/public/downloads/errors.zip +0 -0
- package/docs/public/downloads/ffi.zip +0 -0
- package/docs/public/downloads/generic-di.zip +0 -0
- package/docs/public/downloads/generics.zip +0 -0
- package/docs/public/downloads/hello.zip +0 -0
- package/docs/public/downloads/http-benchmark.zip +0 -0
- package/docs/public/downloads/interceptors.zip +0 -0
- package/docs/public/downloads/json-benchmark.zip +0 -0
- package/docs/public/downloads/new-syntax.zip +0 -0
- package/docs/public/downloads/oidc-login.zip +0 -0
- package/docs/public/downloads/ownership-transfer.zip +0 -0
- package/docs/public/downloads/ownership.zip +0 -0
- package/docs/public/downloads/packages-app.zip +0 -0
- package/docs/public/downloads/packages-math.zip +0 -0
- package/docs/public/downloads/startup-benchmark.zip +0 -0
- package/docs/public/downloads/visibility.zip +0 -0
- package/docs/public/downloads/weather-api.zip +0 -0
- package/docs/reference.md +23 -17
- package/docs/releasing.md +29 -15
- package/docs/research/code-to-natural-language.md +108 -0
- package/docs/research/ecosystem-workflow.md +41 -0
- package/docs/research/wiki-editorial-design.md +71 -0
- package/docs/roadmap.md +1 -1
- package/docs/specifications.md +27 -11
- package/docs/testing.md +19 -5
- package/docs/tooling.md +25 -12
- package/docs/weather-api.md +65 -0
- package/docs/web.md +50 -18
- package/docs/writing-docs.md +49 -0
- package/examples/{hello/.aug-spec/august/0.19.0 → approved-design/.aug-spec/august/0.20.1}/io/contracts.aug +4 -3
- package/examples/approved-design/.aug-spec/august/0.20.1/io/contracts.aug.md +82 -0
- package/examples/approved-design/.aug-spec/manifest.json +3 -3
- package/examples/approved-design/counters.aug +5 -4
- package/examples/approved-design/counters.aug.md +25 -132
- package/examples/approved-design/domain/app.aug +2 -1
- package/examples/approved-design/domain/app.aug.md +10 -80
- package/examples/approved-design/domain/export.aug +1 -0
- package/examples/approved-design/domain/export.aug.md +4 -20
- package/examples/approved-design/domain/models.aug +1 -0
- package/examples/approved-design/domain/models.aug.md +3 -25
- package/examples/approved-design/domain/numbers.aug +3 -2
- package/examples/approved-design/domain/numbers.aug.md +19 -116
- package/examples/approved-design/main.aug +1 -0
- package/examples/approved-design/main.aug.md +12 -95
- package/examples/benchmark/.aug-spec/manifest.json +1 -1
- package/examples/benchmark/main.aug +1 -0
- package/examples/benchmark/main.aug.md +6 -36
- package/examples/cli-args/.aug-spec/manifest.json +1 -1
- package/examples/cli-args/main.aug +1 -0
- package/examples/cli-args/main.aug.md +5 -32
- package/examples/collections/.aug-spec/manifest.json +1 -1
- package/examples/collections/main.aug +1 -0
- package/examples/collections/main.aug.md +6 -36
- package/examples/{generic-di/.aug-spec/august/0.19.0 → developer-workflow/.aug-spec/august/0.20.1}/io/contracts.aug +4 -3
- package/examples/developer-workflow/.aug-spec/august/0.20.1/io/contracts.aug.md +82 -0
- package/examples/developer-workflow/.aug-spec/manifest.json +3 -3
- package/examples/developer-workflow/calculator.aug +3 -2
- package/examples/developer-workflow/calculator.aug.md +28 -189
- package/examples/developer-workflow/logging/console.aug +2 -1
- package/examples/developer-workflow/logging/console.aug.md +7 -57
- package/examples/developer-workflow/logging/export.aug +1 -0
- package/examples/developer-workflow/logging/export.aug.md +3 -15
- package/examples/developer-workflow/logging/logger.aug +1 -0
- package/examples/developer-workflow/logging/logger.aug.md +6 -46
- package/examples/developer-workflow/main.aug +1 -0
- package/examples/developer-workflow/main.aug.md +10 -68
- package/examples/drop/.aug-spec/manifest.json +1 -1
- package/examples/drop/main.aug +1 -0
- package/examples/drop/main.aug.md +6 -28
- package/examples/drop/resource.aug +1 -0
- package/examples/drop/resource.aug.md +6 -34
- package/examples/errors/.aug-spec/manifest.json +1 -1
- package/examples/errors/errors.aug +2 -1
- package/examples/errors/errors.aug.md +4 -27
- package/examples/errors/main.aug +1 -0
- package/examples/errors/main.aug.md +6 -29
- package/examples/ffi/.aug-spec/manifest.json +1 -1
- package/examples/ffi/main.aug +1 -0
- package/examples/ffi/main.aug.md +5 -21
- package/examples/ffi/native.aug +2 -1
- package/examples/ffi/native.aug.md +5 -35
- package/examples/{approved-design/.aug-spec/august/0.19.0 → generic-di/.aug-spec/august/0.20.1}/io/contracts.aug +4 -3
- package/examples/generic-di/.aug-spec/august/0.20.1/io/contracts.aug.md +82 -0
- package/examples/generic-di/.aug-spec/manifest.json +3 -3
- package/examples/generic-di/main.aug +1 -0
- package/examples/generic-di/main.aug.md +8 -40
- package/examples/generic-di/types.aug +3 -2
- package/examples/generic-di/types.aug.md +18 -97
- package/examples/generics/.aug-spec/manifest.json +1 -1
- package/examples/generics/main.aug +1 -0
- package/examples/generics/main.aug.md +9 -48
- package/examples/generics/types.aug +4 -3
- package/examples/generics/types.aug.md +18 -104
- package/examples/{developer-workflow/.aug-spec/august/0.19.0 → hello/.aug-spec/august/0.20.1}/io/contracts.aug +4 -3
- package/examples/hello/.aug-spec/august/0.20.1/io/contracts.aug.md +82 -0
- package/examples/hello/.aug-spec/manifest.json +3 -3
- package/examples/hello/app/export.aug +1 -0
- package/examples/hello/app/export.aug.md +3 -13
- package/examples/hello/app/greeter.aug +2 -1
- package/examples/hello/app/greeter.aug.md +10 -94
- package/examples/hello/logging/console.aug +2 -1
- package/examples/hello/logging/console.aug.md +7 -55
- package/examples/hello/logging/export.aug +1 -0
- package/examples/hello/logging/export.aug.md +3 -15
- package/examples/hello/logging/logger.aug +1 -0
- package/examples/hello/logging/logger.aug.md +6 -48
- package/examples/hello/main.aug +1 -0
- package/examples/hello/main.aug.md +8 -40
- package/examples/interceptors/.aug-spec/august/0.20.1/io/contracts.aug +37 -0
- package/examples/interceptors/.aug-spec/august/0.20.1/io/contracts.aug.md +82 -0
- package/examples/interceptors/.aug-spec/manifest.json +3 -3
- package/examples/interceptors/app.aug +3 -2
- package/examples/interceptors/app.aug.md +15 -141
- package/examples/interceptors/interceptors.aug +3 -2
- package/examples/interceptors/interceptors.aug.md +19 -152
- package/examples/interceptors/logging.aug +2 -1
- package/examples/interceptors/logging.aug.md +10 -79
- package/examples/interceptors/main.aug +1 -0
- package/examples/interceptors/main.aug.md +9 -66
- package/examples/new-syntax/.aug-spec/august/0.20.1/io/contracts.aug +37 -0
- package/examples/new-syntax/.aug-spec/august/0.20.1/io/contracts.aug.md +82 -0
- package/examples/new-syntax/.aug-spec/manifest.json +3 -3
- package/examples/new-syntax/console.aug +2 -1
- package/examples/new-syntax/console.aug.md +7 -53
- package/examples/new-syntax/greeter.aug +2 -1
- package/examples/new-syntax/greeter.aug.md +10 -74
- package/examples/new-syntax/logger.aug +1 -0
- package/examples/new-syntax/logger.aug.md +6 -46
- package/examples/new-syntax/main.aug +1 -0
- package/examples/new-syntax/main.aug.md +9 -54
- package/examples/new-syntax/math.aug +2 -1
- package/examples/new-syntax/math.aug.md +3 -24
- package/examples/oidc-login/.aug-spec/manifest.json +13 -13
- package/examples/oidc-login/.aug-spec/packages/@git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.aug.md +71 -0
- package/examples/oidc-login/.aug-spec/packages/@git/url_2d3c37c690c0fa115be1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.aug.md +17 -0
- package/examples/oidc-login/.aug-spec/packages/@git/url_897efafd565158fc4908/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.aug.md +125 -0
- package/examples/oidc-login/.aug-spec/{august/0.19.0/crypto → packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40}/contracts.aug +12 -11
- package/examples/oidc-login/.aug-spec/packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.aug.md +244 -0
- package/examples/oidc-login/.aug-spec/{august/0.19.0/crypto → packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40}/jose.aug +6 -5
- package/examples/oidc-login/.aug-spec/packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/jose.aug.md +71 -0
- package/examples/oidc-login/.aug-spec/packages/@git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.aug.md +30 -0
- package/examples/oidc-login/aug.lock.json +100 -0
- package/examples/oidc-login/client/contracts.aug +1 -0
- package/examples/oidc-login/client/contracts.aug.md +9 -66
- package/examples/oidc-login/client/endpoints.aug +6 -5
- package/examples/oidc-login/client/endpoints.aug.md +13 -145
- package/examples/oidc-login/client/export.aug +1 -0
- package/examples/oidc-login/client/export.aug.md +4 -24
- package/examples/oidc-login/client/login.aug +7 -6
- package/examples/oidc-login/client/login.aug.md +25 -303
- package/examples/oidc-login/client/logout.aug +5 -4
- package/examples/oidc-login/client/logout.aug.md +13 -135
- package/examples/oidc-login/client/protocol.aug +7 -6
- package/examples/oidc-login/client/protocol.aug.md +36 -283
- package/examples/oidc-login/client/session.aug +5 -4
- package/examples/oidc-login/client/session.aug.md +12 -139
- package/examples/oidc-login/client/views.aug +3 -2
- package/examples/oidc-login/client/views.aug.md +8 -57
- package/examples/oidc-login/common/export.aug +1 -0
- package/examples/oidc-login/common/export.aug.md +5 -27
- package/examples/oidc-login/common/headers.aug +4 -3
- package/examples/oidc-login/common/headers.aug.md +9 -67
- package/examples/oidc-login/common/keys.aug +6 -5
- package/examples/oidc-login/common/keys.aug.md +29 -165
- package/examples/oidc-login/common/settings.aug +2 -1
- package/examples/oidc-login/common/settings.aug.md +5 -39
- package/examples/oidc-login/common/views.aug +2 -1
- package/examples/oidc-login/common/views.aug.md +4 -28
- package/examples/oidc-login/main.aug +6 -16
- package/examples/oidc-login/main.aug.md +17 -146
- package/examples/oidc-login/main.yaml +7 -0
- package/examples/oidc-login/provider/authorization.aug +7 -6
- package/examples/oidc-login/provider/authorization.aug.md +23 -238
- package/examples/oidc-login/provider/contracts.aug +1 -0
- package/examples/oidc-login/provider/contracts.aug.md +23 -158
- package/examples/oidc-login/provider/credentials.aug +3 -2
- package/examples/oidc-login/provider/credentials.aug.md +9 -53
- package/examples/oidc-login/provider/discovery.aug +4 -3
- package/examples/oidc-login/provider/discovery.aug.md +11 -118
- package/examples/oidc-login/provider/export.aug +1 -0
- package/examples/oidc-login/provider/export.aug.md +6 -34
- package/examples/oidc-login/provider/token.aug +6 -5
- package/examples/oidc-login/provider/token.aug.md +16 -204
- package/examples/oidc-login/provider/userinfo.aug +4 -3
- package/examples/oidc-login/provider/userinfo.aug.md +10 -92
- package/examples/oidc-login/provider/views.aug +3 -2
- package/examples/oidc-login/provider/views.aug.md +8 -52
- package/examples/ownership/.aug-spec/manifest.json +1 -1
- package/examples/ownership/counter.aug +3 -2
- package/examples/ownership/counter.aug.md +12 -66
- package/examples/ownership/main.aug +1 -0
- package/examples/ownership/main.aug.md +6 -31
- package/examples/ownership-transfer/.aug-spec/august/0.20.1/io/contracts.aug +37 -0
- package/examples/ownership-transfer/.aug-spec/august/0.20.1/io/contracts.aug.md +82 -0
- package/examples/ownership-transfer/.aug-spec/manifest.json +3 -3
- package/examples/ownership-transfer/main.aug +1 -0
- package/examples/ownership-transfer/main.aug.md +9 -53
- package/examples/ownership-transfer/resource.aug +2 -1
- package/examples/ownership-transfer/resource.aug.md +12 -71
- package/examples/packages/app/.aug-spec/manifest.json +1 -1
- package/examples/packages/app/.aug-spec/packages/@example/aug-math/0.1.0/arithmetic.aug +2 -1
- package/examples/packages/app/.aug-spec/packages/@example/aug-math/0.1.0/arithmetic.aug.md +9 -51
- package/examples/packages/app/main.aug +1 -0
- package/examples/packages/app/main.aug.md +6 -26
- package/examples/packages/math/.aug-spec/manifest.json +1 -1
- package/examples/packages/math/aug-package.json +1 -1
- package/examples/packages/math/src/arithmetic.aug +2 -1
- package/examples/packages/math/src/arithmetic.aug.md +9 -51
- package/examples/packages/math/src/export.aug +1 -0
- package/examples/packages/math/src/export.aug.md +3 -13
- package/examples/visibility/.aug-spec/manifest.json +1 -1
- package/examples/visibility/counter.aug +4 -3
- package/examples/visibility/counter.aug.md +12 -68
- package/examples/visibility/main.aug +1 -0
- package/examples/visibility/main.aug.md +6 -32
- package/examples/weather-api/.aug-spec/manifest.json +8 -0
- package/examples/weather-api/AGENTS.md +17 -0
- package/examples/weather-api/README.md +19 -0
- package/examples/weather-api/forecasts.aug +47 -0
- package/examples/weather-api/forecasts.aug.md +32 -0
- package/examples/weather-api/main.aug +4 -0
- package/examples/weather-api/main.aug.md +15 -0
- package/examples/weather-api/main.yaml +5 -0
- package/examples/weather-api/weather.http +5 -0
- package/package.json +3 -4
- package/scripts/bootstrap-native.mjs +181 -106
- package/scripts/native-setup.mjs +98 -0
- package/scripts/native-toolchain.mjs +28 -0
- package/src/builtins.js +1 -1
- package/src/checker.js +259 -72
- package/src/cli.js +114 -20
- package/src/codegen.js +1 -1
- package/src/config.js +1 -1
- package/src/contracts.js +10 -0
- package/src/editor.js +71 -16
- package/src/fixes.js +90 -2
- package/src/formatter.js +19 -8
- package/src/git-packages.js +110 -0
- package/src/help.js +24 -23
- package/src/http-contracts.js +14 -0
- package/src/http-policies.js +5 -5
- package/src/libraries.js +1 -1
- package/src/lsp.js +14 -5
- package/src/native.js +19 -13
- package/src/navigation.js +4 -2
- package/src/openapi.js +5 -4
- package/src/package-locking.js +45 -0
- package/src/package-manager.js +251 -67
- package/src/parser.js +13 -5
- package/src/policies.js +3 -3
- package/src/project-init.js +78 -4
- package/src/project.js +9 -7
- package/src/semantic.js +46 -2
- package/src/snippets.js +59 -0
- package/src/spec-hints.js +56 -0
- package/src/spec-tree.js +241 -0
- package/src/spec.js +626 -303
- package/docs/examples/approved-design/dependencies/august/0.19.0/io/contracts.md +0 -395
- package/docs/examples/developer-workflow/dependencies/august/0.19.0/io/contracts.md +0 -395
- package/docs/examples/generic-di/dependencies/august/0.19.0/io/contracts.md +0 -395
- package/docs/examples/hello/dependencies/august/0.19.0/io/contracts.md +0 -395
- package/docs/examples/interceptors/dependencies/august/0.19.0/io/contracts.md +0 -395
- package/docs/examples/json-benchmark/dependencies/august/0.19.0/json/contracts.md +0 -103
- package/docs/examples/new-syntax/dependencies/august/0.19.0/io/contracts.md +0 -395
- package/docs/examples/oidc-login/dependencies/august/0.19.0/crypto/contracts.md +0 -925
- package/docs/examples/oidc-login/dependencies/august/0.19.0/crypto/jose.md +0 -434
- package/docs/examples/oidc-login/dependencies/august/0.19.0/json/contracts.md +0 -103
- package/docs/examples/oidc-login/dependencies/august/0.19.0/memory/store.md +0 -374
- package/docs/examples/oidc-login/dependencies/august/0.19.0/time/contracts.md +0 -150
- package/docs/examples/oidc-login/dependencies/august/0.19.0/web/contracts.md +0 -532
- package/docs/examples/ownership-transfer/dependencies/august/0.19.0/io/contracts.md +0 -395
- package/examples/approved-design/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
- package/examples/developer-workflow/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
- package/examples/generic-di/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
- package/examples/hello/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
- package/examples/interceptors/.aug-spec/august/0.19.0/io/contracts.aug +0 -36
- package/examples/interceptors/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
- package/examples/new-syntax/.aug-spec/august/0.19.0/io/contracts.aug +0 -36
- package/examples/new-syntax/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
- package/examples/oidc-login/.aug-spec/august/0.19.0/crypto/contracts.aug.md +0 -791
- package/examples/oidc-login/.aug-spec/august/0.19.0/crypto/jose.aug.md +0 -266
- package/examples/oidc-login/.aug-spec/august/0.19.0/json/contracts.aug.md +0 -55
- package/examples/oidc-login/.aug-spec/august/0.19.0/memory/store.aug.md +0 -250
- package/examples/oidc-login/.aug-spec/august/0.19.0/time/contracts.aug.md +0 -96
- package/examples/oidc-login/.aug-spec/august/0.19.0/web/contracts.aug.md +0 -420
- package/examples/ownership-transfer/.aug-spec/august/0.19.0/io/contracts.aug +0 -36
- package/examples/ownership-transfer/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
- /package/examples/oidc-login/.aug-spec/{august/0.19.0/memory → packages/@git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301}/store.aug +0 -0
- /package/examples/oidc-login/.aug-spec/{august/0.19.0/json → packages/@git/url_2d3c37c690c0fa115be1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301}/contracts.aug +0 -0
- /package/examples/oidc-login/.aug-spec/{august/0.19.0/web → packages/@git/url_897efafd565158fc4908/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301}/contracts.aug +0 -0
- /package/examples/oidc-login/.aug-spec/{august/0.19.0/time → packages/@git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301}/contracts.aug +0 -0
|
@@ -49,16 +49,17 @@ pageClass: aug-example-page
|
|
|
49
49
|
::: code-group
|
|
50
50
|
|
|
51
51
|
```aug [Indentation]
|
|
52
|
+
// aug-spec: "authorization.aug.md" explains this file. Read it before changes; refresh with aug spec.
|
|
52
53
|
import AuthorizationRequest and AuthorizationCode and LoginForm and LoginError from contracts
|
|
53
54
|
import ProviderLogin and ProviderFailure from views
|
|
54
55
|
import verifyCredentials from credentials
|
|
55
56
|
import settings and securityHeaders and withCookie from common
|
|
56
|
-
import Crypto from
|
|
57
|
-
import Clock from
|
|
58
|
-
import ExpiringStore and StoreFull from
|
|
59
|
-
import urlEncode from
|
|
57
|
+
import Crypto from crypto
|
|
58
|
+
import Clock from time
|
|
59
|
+
import ExpiringStore and StoreFull from memory
|
|
60
|
+
import urlEncode from web
|
|
60
61
|
/** 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)
|
|
62
|
+
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) unless LoginError with status 400 and CryptoError with status 503 and TimeError with status 503 and StoreFull with status 503 and HttpError:
|
|
62
63
|
config = settings()
|
|
63
64
|
if client_id != config.clientId or redirect_uri != config.callback or response_type != "code" or code_challenge_method != "S256":
|
|
64
65
|
throw LoginError()
|
|
@@ -75,50 +76,135 @@ endpoint GET "/provider/authorize" as authorize(string response_type from query,
|
|
|
75
76
|
browser = crypto.random(size=32).base64url()
|
|
76
77
|
csrf = crypto.random(size=32).base64url()
|
|
77
78
|
now = clock.now()
|
|
78
|
-
request = AuthorizationRequest(
|
|
79
|
+
request = AuthorizationRequest(
|
|
80
|
+
clientId=client_id,
|
|
81
|
+
redirectUri=redirect_uri,
|
|
82
|
+
state=state,
|
|
83
|
+
nonce=nonce,
|
|
84
|
+
challenge=code_challenge,
|
|
85
|
+
browser=browser,
|
|
86
|
+
csrf=csrf,
|
|
87
|
+
expires=now + 300
|
|
88
|
+
)
|
|
79
89
|
requests.put(key=requestId, value=request, expires=request.expires, now=now)
|
|
80
|
-
headers = withCookie(
|
|
81
|
-
|
|
90
|
+
headers = withCookie(
|
|
91
|
+
headers=securityHeaders(),
|
|
92
|
+
name="aug_authorize",
|
|
93
|
+
value=browser,
|
|
94
|
+
path="/provider",
|
|
95
|
+
maxAge=300,
|
|
96
|
+
secure=config.secureCookies
|
|
97
|
+
)
|
|
98
|
+
return HttpResponse(
|
|
99
|
+
body=ProviderLogin(
|
|
100
|
+
requestId,
|
|
101
|
+
csrf,
|
|
102
|
+
message="Authorize the registered August login app.",
|
|
103
|
+
submit=handle providerLogin(input from form)
|
|
104
|
+
),
|
|
105
|
+
headers=headers
|
|
106
|
+
)
|
|
82
107
|
/** 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)
|
|
108
|
+
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) unless CryptoError with status 503 and TimeError with status 503 and StoreFull with status 503 and HttpError:
|
|
84
109
|
config = settings()
|
|
85
110
|
try:
|
|
86
111
|
if origin != config.baseUrl:
|
|
87
|
-
return HttpResponse(
|
|
112
|
+
return HttpResponse(
|
|
113
|
+
body=ProviderFailure(message="The sign-in form must come from this app."),
|
|
114
|
+
status=403,
|
|
115
|
+
headers=securityHeaders()
|
|
116
|
+
)
|
|
88
117
|
match requests.take(key=form.request_id, now=clock.now()):
|
|
89
118
|
when null:
|
|
90
|
-
return HttpResponse(
|
|
119
|
+
return HttpResponse(
|
|
120
|
+
body=ProviderFailure(
|
|
121
|
+
message="The sign-in request expired or was already used."
|
|
122
|
+
),
|
|
123
|
+
status=400,
|
|
124
|
+
headers=securityHeaders()
|
|
125
|
+
)
|
|
91
126
|
when some request:
|
|
92
127
|
match browser:
|
|
93
128
|
when null:
|
|
94
|
-
return HttpResponse(
|
|
129
|
+
return HttpResponse(
|
|
130
|
+
body=ProviderFailure(
|
|
131
|
+
message="The browser binding is missing."
|
|
132
|
+
),
|
|
133
|
+
status=403,
|
|
134
|
+
headers=securityHeaders()
|
|
135
|
+
)
|
|
95
136
|
when some secret:
|
|
96
|
-
if not crypto.equal(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
137
|
+
if not crypto.equal(
|
|
138
|
+
left=secret.bytes(),
|
|
139
|
+
right=request.browser.bytes()
|
|
140
|
+
) or not crypto.equal(
|
|
141
|
+
left=form.csrf.bytes(),
|
|
142
|
+
right=request.csrf.bytes()
|
|
143
|
+
):
|
|
144
|
+
return HttpResponse(
|
|
145
|
+
body=ProviderFailure(
|
|
146
|
+
message="The sign-in form could not be verified."
|
|
147
|
+
),
|
|
148
|
+
status=403,
|
|
149
|
+
headers=securityHeaders()
|
|
150
|
+
)
|
|
151
|
+
if not verifyCredentials(
|
|
152
|
+
username=form.username,
|
|
153
|
+
password=form.password
|
|
154
|
+
):
|
|
155
|
+
return HttpResponse(
|
|
156
|
+
body=ProviderFailure(
|
|
157
|
+
message="The username or password was not accepted."
|
|
158
|
+
),
|
|
159
|
+
status=401,
|
|
160
|
+
headers=securityHeaders()
|
|
161
|
+
)
|
|
100
162
|
now = clock.now()
|
|
101
163
|
code = crypto.random(size=32).base64url()
|
|
102
|
-
grant = AuthorizationCode(
|
|
164
|
+
grant = AuthorizationCode(
|
|
165
|
+
clientId=request.clientId,
|
|
166
|
+
redirectUri=request.redirectUri,
|
|
167
|
+
challenge=request.challenge,
|
|
168
|
+
nonce=request.nonce,
|
|
169
|
+
subject="demo-ada",
|
|
170
|
+
name="Ada",
|
|
171
|
+
expires=now + 60
|
|
172
|
+
)
|
|
103
173
|
codes.put(key=code, value=grant, expires=grant.expires, now=now)
|
|
104
174
|
location = request.redirectUri + "?code=" + urlEncode(input=code) + "&state=" + urlEncode(input=request.state)
|
|
105
|
-
headers = withCookie(
|
|
106
|
-
|
|
175
|
+
headers = withCookie(
|
|
176
|
+
headers=securityHeaders().with(name="location", value=location),
|
|
177
|
+
name="aug_authorize",
|
|
178
|
+
value="",
|
|
179
|
+
path="/provider",
|
|
180
|
+
maxAge=0,
|
|
181
|
+
secure=config.secureCookies
|
|
182
|
+
)
|
|
183
|
+
return HttpResponse(
|
|
184
|
+
body=<p>Returning to the application.</p>,
|
|
185
|
+
status=303,
|
|
186
|
+
headers=headers
|
|
187
|
+
)
|
|
107
188
|
catch HttpError error:
|
|
108
|
-
return HttpResponse(
|
|
189
|
+
return HttpResponse(
|
|
190
|
+
body=ProviderFailure(message="The submitted form is invalid."),
|
|
191
|
+
status=400,
|
|
192
|
+
headers=securityHeaders()
|
|
193
|
+
)
|
|
109
194
|
```
|
|
110
195
|
|
|
111
196
|
```aug [Braces]
|
|
197
|
+
// aug-spec: "authorization.aug.md" explains this file. Read it before changes; refresh with aug spec.
|
|
112
198
|
import AuthorizationRequest and AuthorizationCode and LoginForm and LoginError from contracts
|
|
113
199
|
import ProviderLogin and ProviderFailure from views
|
|
114
200
|
import verifyCredentials from credentials
|
|
115
201
|
import settings and securityHeaders and withCookie from common
|
|
116
|
-
import Crypto from
|
|
117
|
-
import Clock from
|
|
118
|
-
import ExpiringStore and StoreFull from
|
|
119
|
-
import urlEncode from
|
|
202
|
+
import Crypto from crypto
|
|
203
|
+
import Clock from time
|
|
204
|
+
import ExpiringStore and StoreFull from memory
|
|
205
|
+
import urlEncode from web
|
|
120
206
|
/** 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)
|
|
207
|
+
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) unless LoginError with status 400 and CryptoError with status 503 and TimeError with status 503 and StoreFull with status 503 and HttpError {
|
|
122
208
|
config = settings()
|
|
123
209
|
if client_id != config.clientId or redirect_uri != config.callback or response_type != "code" or code_challenge_method != "S256" {
|
|
124
210
|
throw LoginError()
|
|
@@ -141,48 +227,132 @@ endpoint GET "/provider/authorize" as authorize(string response_type from query,
|
|
|
141
227
|
browser = crypto.random(size=32).base64url()
|
|
142
228
|
csrf = crypto.random(size=32).base64url()
|
|
143
229
|
now = clock.now()
|
|
144
|
-
request = AuthorizationRequest(
|
|
230
|
+
request = AuthorizationRequest(
|
|
231
|
+
clientId=client_id,
|
|
232
|
+
redirectUri=redirect_uri,
|
|
233
|
+
state=state,
|
|
234
|
+
nonce=nonce,
|
|
235
|
+
challenge=code_challenge,
|
|
236
|
+
browser=browser,
|
|
237
|
+
csrf=csrf,
|
|
238
|
+
expires=now + 300
|
|
239
|
+
)
|
|
145
240
|
requests.put(key=requestId, value=request, expires=request.expires, now=now)
|
|
146
|
-
headers = withCookie(
|
|
147
|
-
|
|
241
|
+
headers = withCookie(
|
|
242
|
+
headers=securityHeaders(),
|
|
243
|
+
name="aug_authorize",
|
|
244
|
+
value=browser,
|
|
245
|
+
path="/provider",
|
|
246
|
+
maxAge=300,
|
|
247
|
+
secure=config.secureCookies
|
|
248
|
+
)
|
|
249
|
+
return HttpResponse(
|
|
250
|
+
body=ProviderLogin(
|
|
251
|
+
requestId,
|
|
252
|
+
csrf,
|
|
253
|
+
message="Authorize the registered August login app.",
|
|
254
|
+
submit=handle providerLogin(input from form)
|
|
255
|
+
),
|
|
256
|
+
headers=headers
|
|
257
|
+
)
|
|
148
258
|
}
|
|
149
259
|
/** 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)
|
|
260
|
+
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) unless CryptoError with status 503 and TimeError with status 503 and StoreFull with status 503 and HttpError {
|
|
151
261
|
config = settings()
|
|
152
262
|
try {
|
|
153
263
|
if origin != config.baseUrl {
|
|
154
|
-
return HttpResponse(
|
|
264
|
+
return HttpResponse(
|
|
265
|
+
body=ProviderFailure(message="The sign-in form must come from this app."),
|
|
266
|
+
status=403,
|
|
267
|
+
headers=securityHeaders()
|
|
268
|
+
)
|
|
155
269
|
}
|
|
156
270
|
match requests.take(key=form.request_id, now=clock.now()) {
|
|
157
271
|
when null {
|
|
158
|
-
return HttpResponse(
|
|
272
|
+
return HttpResponse(
|
|
273
|
+
body=ProviderFailure(
|
|
274
|
+
message="The sign-in request expired or was already used."
|
|
275
|
+
),
|
|
276
|
+
status=400,
|
|
277
|
+
headers=securityHeaders()
|
|
278
|
+
)
|
|
159
279
|
}
|
|
160
280
|
when some request {
|
|
161
281
|
match browser {
|
|
162
282
|
when null {
|
|
163
|
-
return HttpResponse(
|
|
283
|
+
return HttpResponse(
|
|
284
|
+
body=ProviderFailure(
|
|
285
|
+
message="The browser binding is missing."
|
|
286
|
+
),
|
|
287
|
+
status=403,
|
|
288
|
+
headers=securityHeaders()
|
|
289
|
+
)
|
|
164
290
|
}
|
|
165
291
|
when some secret {
|
|
166
|
-
if not crypto.equal(
|
|
167
|
-
|
|
292
|
+
if not crypto.equal(
|
|
293
|
+
left=secret.bytes(),
|
|
294
|
+
right=request.browser.bytes()
|
|
295
|
+
) or not crypto.equal(
|
|
296
|
+
left=form.csrf.bytes(),
|
|
297
|
+
right=request.csrf.bytes()
|
|
298
|
+
) {
|
|
299
|
+
return HttpResponse(
|
|
300
|
+
body=ProviderFailure(
|
|
301
|
+
message="The sign-in form could not be verified."
|
|
302
|
+
),
|
|
303
|
+
status=403,
|
|
304
|
+
headers=securityHeaders()
|
|
305
|
+
)
|
|
168
306
|
}
|
|
169
307
|
}
|
|
170
308
|
}
|
|
171
|
-
if not verifyCredentials(
|
|
172
|
-
|
|
309
|
+
if not verifyCredentials(
|
|
310
|
+
username=form.username,
|
|
311
|
+
password=form.password
|
|
312
|
+
) {
|
|
313
|
+
return HttpResponse(
|
|
314
|
+
body=ProviderFailure(
|
|
315
|
+
message="The username or password was not accepted."
|
|
316
|
+
),
|
|
317
|
+
status=401,
|
|
318
|
+
headers=securityHeaders()
|
|
319
|
+
)
|
|
173
320
|
}
|
|
174
321
|
now = clock.now()
|
|
175
322
|
code = crypto.random(size=32).base64url()
|
|
176
|
-
grant = AuthorizationCode(
|
|
323
|
+
grant = AuthorizationCode(
|
|
324
|
+
clientId=request.clientId,
|
|
325
|
+
redirectUri=request.redirectUri,
|
|
326
|
+
challenge=request.challenge,
|
|
327
|
+
nonce=request.nonce,
|
|
328
|
+
subject="demo-ada",
|
|
329
|
+
name="Ada",
|
|
330
|
+
expires=now + 60
|
|
331
|
+
)
|
|
177
332
|
codes.put(key=code, value=grant, expires=grant.expires, now=now)
|
|
178
333
|
location = request.redirectUri + "?code=" + urlEncode(input=code) + "&state=" + urlEncode(input=request.state)
|
|
179
|
-
headers = withCookie(
|
|
180
|
-
|
|
334
|
+
headers = withCookie(
|
|
335
|
+
headers=securityHeaders().with(name="location", value=location),
|
|
336
|
+
name="aug_authorize",
|
|
337
|
+
value="",
|
|
338
|
+
path="/provider",
|
|
339
|
+
maxAge=0,
|
|
340
|
+
secure=config.secureCookies
|
|
341
|
+
)
|
|
342
|
+
return HttpResponse(
|
|
343
|
+
body=<p>Returning to the application.</p>,
|
|
344
|
+
status=303,
|
|
345
|
+
headers=headers
|
|
346
|
+
)
|
|
181
347
|
}
|
|
182
348
|
}
|
|
183
349
|
}
|
|
184
350
|
catch HttpError error {
|
|
185
|
-
return HttpResponse(
|
|
351
|
+
return HttpResponse(
|
|
352
|
+
body=ProviderFailure(message="The submitted form is invalid."),
|
|
353
|
+
status=400,
|
|
354
|
+
headers=securityHeaders()
|
|
355
|
+
)
|
|
186
356
|
}
|
|
187
357
|
}
|
|
188
358
|
```
|
|
@@ -195,262 +365,49 @@ endpoint POST "/provider/login" as providerLogin(LoginForm form from form, optio
|
|
|
195
365
|
|
|
196
366
|
## Compiled specification {#specification}
|
|
197
367
|
|
|
198
|
-
|
|
368
|
+
Plain handler results default to HTTP 200 unless another status is declared. HttpResponse values choose their own status. Unhandled request failures return HTTP 500 and cancel the request tasks.
|
|
199
369
|
|
|
200
|
-
###
|
|
370
|
+
### `authorize` · [source](authorization.md#code) {#symbol-authorize}
|
|
201
371
|
|
|
202
|
-
|
|
203
|
-
- [`providerLogin`](authorization.md#symbol-providerLogin) handles `POST` `/provider/login` returning `HttpResponse<Html>`.
|
|
372
|
+
`authorize` handles `GET /provider/authorize`. Validate the registered client before offering a login form. A malformed redirect is never followed.
|
|
204
373
|
|
|
205
|
-
|
|
374
|
+
It reads `response_type`, `client_id`, `redirect_uri`, `scope`, `state`, `nonce`, `code_challenge`, and `code_challenge_method` from the HTTP query. `scope` is called `requestedScope` here. It gets `crypto` ([`Crypto`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto)), `clock` ([`Clock`](../dependencies/packages/%40git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md#symbol-Clock)), and `requests` ([`ExpiringStore<AuthorizationRequest>`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-ExpiringStore)) from dependency injection. The handler responds with HTTP 400 for [`LoginError`](contracts.md#symbol-LoginError), HTTP 503 for `CryptoError`, HTTP 503 for `TimeError`, and HTTP 503 for [`StoreFull`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-StoreFull).
|
|
206
375
|
|
|
207
|
-
[
|
|
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.
|
|
376
|
+
It can also raise `HttpError`. It gets `config` from [`settings`](../common/settings.md#symbol-settings). It checks that `client_id` equals `config.clientId` and `redirect_uri` equals `config.callback` and `response_type` equals `"code"` and `code_challenge_method` equals `"S256"`, `requestedScope` is either `"openid"` or `"openid profile"`, and `state` is a URL-safe ASCII token with `43` to `128` characters and `nonce` is a URL-safe ASCII token with `43` to `128` characters and the byte length of `code_challenge` equals `43`. It raises a [`LoginError`](contracts.md#symbol-LoginError) at the first failed check.
|
|
222
377
|
|
|
223
|
-
|
|
378
|
+
It checks that the byte length of [`crypto.decodeBase64url`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto.decodeBase64url) with `input` from `code_challenge` equals `32`. It raises a [`LoginError`](contracts.md#symbol-LoginError) at the first failed check. If this work raises `CryptoError`, it raises a [`LoginError`](contracts.md#symbol-LoginError). It sets `requestId`, `browser`, and `csrf` separately, each to the URL-safe base64 encoding of [`crypto.random`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto.random) with `size` `32`.
|
|
224
379
|
|
|
225
|
-
|
|
380
|
+
It sets `now` to [`clock.now`](../dependencies/packages/%40git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md#symbol-Clock.now). It sets `request` to an [`AuthorizationRequest`](contracts.md#symbol-AuthorizationRequest) with `clientId` from `client_id`, `redirectUri` from `redirect_uri`, `state`, `nonce`, `challenge` from `code_challenge`, `browser`, `csrf`, and `expires` from `now` plus `300`. It calls [`requests.put`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-ExpiringStore.put) with `key` from `requestId`, `value` from `request`, `request.expires`, and `now`. It sets `headers` to [`withCookie`](../common/headers.md#symbol-withCookie) with `headers` from [`securityHeaders`](../common/headers.md#symbol-securityHeaders), `name` `"aug_authorize"`, `value` from `browser`, `path` `"/provider"`, `maxAge` `300`, and `secure` from `config.secureCookies`.
|
|
226
381
|
|
|
227
|
-
|
|
382
|
+
It returns HTTP 200 with [`ProviderLogin`](views.md#symbol-ProviderLogin) with `requestId`, `csrf`, `message` `"Authorize the registered August login app."`, and `submit` from a form action that sends `POST /provider/login` to [`providerLogin`](authorization.md#symbol-providerLogin) on submission and `headers` headers.
|
|
228
383
|
|
|
229
|
-
|
|
384
|
+
### `providerLogin` · [source](authorization.md#code) {#symbol-providerLogin}
|
|
230
385
|
|
|
231
|
-
|
|
386
|
+
`providerLogin` handles `POST /provider/login`. The browser binding and CSRF token are checked before credentials. Each form request is consumed once.
|
|
232
387
|
|
|
233
|
-
|
|
388
|
+
It takes `form` as [`LoginForm`](contracts.md#symbol-LoginForm) from the HTTP form, `browser` as `optional string` from the HTTP cookie `aug_authorize`, and `origin` as `optional string` from the HTTP header `origin`. It gets `crypto` ([`Crypto`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto)), `clock` ([`Clock`](../dependencies/packages/%40git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md#symbol-Clock)), `requests` ([`ExpiringStore<AuthorizationRequest>`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-ExpiringStore)), and `codes` ([`ExpiringStore<AuthorizationCode>`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-ExpiringStore)) from dependency injection. Omitted optional inputs are null. The handler responds with HTTP 503 for `CryptoError`, HTTP 503 for `TimeError`, and HTTP 503 for [`StoreFull`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-StoreFull).
|
|
234
389
|
|
|
235
|
-
|
|
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`.
|
|
390
|
+
It can also raise `HttpError`.
|
|
255
391
|
|
|
256
|
-
|
|
392
|
+
It gets `config` from [`settings`](../common/settings.md#symbol-settings). If `origin` does not equal `config.baseUrl`, it returns HTTP 403 with [`ProviderFailure`](views.md#symbol-ProviderFailure) showing `"The sign-in form must come from this app."` and [`securityHeaders`](../common/headers.md#symbol-securityHeaders) headers. It obtains [`requests.take`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-ExpiringStore.take) with `key` from `form.request_id` and `now` from [`clock.now`](../dependencies/packages/%40git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md#symbol-Clock.now). If no value is found, it returns HTTP 400 with [`ProviderFailure`](views.md#symbol-ProviderFailure) showing `"The sign-in request expired or was already used."` and [`securityHeaders`](../common/headers.md#symbol-securityHeaders) headers.
|
|
257
393
|
|
|
258
|
-
|
|
394
|
+
The non-null result becomes `request`. If `browser` is null, it returns HTTP 403 with [`ProviderFailure`](views.md#symbol-ProviderFailure) showing `"The browser binding is missing."` and [`securityHeaders`](../common/headers.md#symbol-securityHeaders) headers. The non-null `browser` becomes `secret`. If [`crypto.equal`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto.equal) with `left` from the UTF-8 bytes of `secret` and `right` from the UTF-8 bytes of `request.browser` returns false or [`crypto.equal`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto.equal) with `left` from the UTF-8 bytes of `form.csrf` and `right` from the UTF-8 bytes of `request.csrf` returns false, it returns HTTP 403 with [`ProviderFailure`](views.md#symbol-ProviderFailure) showing `"The sign-in form could not be verified."` and [`securityHeaders`](../common/headers.md#symbol-securityHeaders) headers.
|
|
259
395
|
|
|
260
|
-
|
|
396
|
+
If [`verifyCredentials`](credentials.md#symbol-verifyCredentials) with `form.username` and `form.password` using injected `crypto` returns false, it returns HTTP 401 with [`ProviderFailure`](views.md#symbol-ProviderFailure) showing `"The username or password was not accepted."` and [`securityHeaders`](../common/headers.md#symbol-securityHeaders) headers. It sets `now` to [`clock.now`](../dependencies/packages/%40git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md#symbol-Clock.now). It sets `code` to the URL-safe base64 encoding of [`crypto.random`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto.random) with `size` `32`. It sets `grant` to an [`AuthorizationCode`](contracts.md#symbol-AuthorizationCode) with `request.clientId`, `request.redirectUri`, `request.challenge`, `request.nonce`, `subject` `"demo-ada"`, `name` `"Ada"`, and `expires` from `now` plus `60`.
|
|
261
397
|
|
|
262
|
-
[
|
|
398
|
+
It calls [`codes.put`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-ExpiringStore.put) with `key` from `code`, `value` from `grant`, `grant.expires`, and `now`. It builds `location` as the text `{request.redirectUri}?code={urlEncode with input from code}&state={urlEncode with input from request.state}`. It sets `headers` to [`withCookie`](../common/headers.md#symbol-withCookie) with `headers` from [`securityHeaders`](../common/headers.md#symbol-securityHeaders) with the header `"location"` set to `location`, `name` `"aug_authorize"`, `value` `""`, `path` `"/provider"`, `maxAge` `0`, and `secure` from `config.secureCookies`. It returns HTTP 303 with a paragraph containing `Returning to the application.` with escaped text and `headers` headers.
|
|
263
399
|
|
|
264
|
-
|
|
400
|
+
If this work raises `HttpError`, it returns HTTP 400 with [`ProviderFailure`](views.md#symbol-ProviderFailure) showing `"The submitted form is invalid."` and [`securityHeaders`](../common/headers.md#symbol-securityHeaders) headers.
|
|
265
401
|
|
|
266
|
-
|
|
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.
|
|
402
|
+
### Dependencies
|
|
273
403
|
|
|
274
|
-
|
|
404
|
+
It uses [`ExpiringStore`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-ExpiringStore) ([`put`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-ExpiringStore.put) and [`take`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-ExpiringStore.take)) and [`StoreFull`](../dependencies/packages/%40git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md#symbol-StoreFull) from `memory`. It uses [`urlEncode`](../dependencies/packages/%40git/url_897efafd565158fc4908/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md#symbol-urlEncode) from `web`. It uses [`Crypto`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto) ([`decodeBase64url`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto.decodeBase64url), [`equal`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto.equal), [`passwordHash`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto.passwordHash), and [`random`](../dependencies/packages/%40git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md#symbol-Crypto.random)) from `crypto`. It uses [`Clock`](../dependencies/packages/%40git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md#symbol-Clock) ([`now`](../dependencies/packages/%40git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md#symbol-Clock.now)) from `time`.
|
|
275
405
|
|
|
276
|
-
|
|
406
|
+
It uses [`securityHeaders`](../common/headers.md#symbol-securityHeaders), [`withCookie`](../common/headers.md#symbol-withCookie), and [`settings`](../common/settings.md#symbol-settings) from `common`. It uses [`Settings`](../common/settings.md#symbol-Settings) (`baseUrl`, `callback`, `clientId`, and `secureCookies`). It uses [`AuthorizationCode`](contracts.md#symbol-AuthorizationCode) (`expires`), [`AuthorizationRequest`](contracts.md#symbol-AuthorizationRequest) (`browser`, `challenge`, `clientId`, `csrf`, `expires`, `nonce`, `redirectUri`, and `state`), [`LoginError`](contracts.md#symbol-LoginError), and [`LoginForm`](contracts.md#symbol-LoginForm) (`csrf`, `password`, `request_id`, and `username`) from `contracts`. It uses [`verifyCredentials`](credentials.md#symbol-verifyCredentials) from `credentials`.
|
|
277
407
|
|
|
278
|
-
|
|
408
|
+
It uses [`ProviderFailure`](views.md#symbol-ProviderFailure) and [`ProviderLogin`](views.md#symbol-ProviderLogin) from `views`.
|
|
279
409
|
|
|
280
|
-
|
|
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.
|
|
410
|
+
Built-in operations follow the [language reference](https://greenpandastudios.github.io/augscript/language-constructs).
|
|
454
411
|
|
|
455
412
|
::::
|
|
456
413
|
|