hecks 3.13.0 → 4.0.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.
- checksums.yaml +4 -4
- data/examples/pizzas/adapters/fake_processor.rb +34 -0
- data/examples/pizzas/adapters/payment_signature.rb +66 -0
- data/examples/pizzas/adapters/payment_webhook.rb +87 -0
- data/examples/pizzas/bluebook/pizzas.behaviors +33 -0
- data/examples/pizzas/bluebook/pizzas.bluebook +4 -4
- data/examples/pizzas/bluebook/pizzas.hecksagon +5 -3
- data/examples/pizzas/config.ru +22 -0
- data/lib/hecks/adapters/driven/prism.rb +0 -2
- data/lib/hecks/adapters/driven.rb +0 -2
- data/lib/hecks/adapters/driving/json.rb +1 -7
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +15 -5
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -2
- data/lib/hecks/bluebook/dsl/derivation_words.rb +58 -0
- data/lib/hecks/bluebook/dsl/translation_builder.rb +6 -37
- data/lib/hecks/bluebook/expression/ast_json.rb +0 -9
- data/lib/hecks/bluebook/hecksagon.rb +1 -1
- data/lib/hecks/bluebook/meta_validator/translation_judge/rules.rb +7 -10
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +4 -8
- data/lib/hecks/bluebook/meta_validator.rb +0 -11
- data/lib/hecks/bluebook/named_pattern.rb +33 -0
- data/lib/hecks/bluebook/translation.rb +18 -10
- data/lib/hecks/bluebook/translation_expression/evaluator.rb +63 -0
- data/lib/hecks/bluebook/translation_expression/parser.rb +127 -0
- data/lib/hecks/bluebook/translation_expression.rb +39 -0
- data/lib/hecks/bluebook/translation_plan.rb +70 -0
- data/lib/hecks/bluebook.rb +3 -0
- data/lib/hecks/chapters.rb +3 -3
- data/lib/hecks/cli/domain_stub.rb +1 -1
- data/lib/hecks/cli/interview_aggregate.rb +4 -4
- data/lib/hecks/composer/adapters/claude_composer.adapter +3 -0
- data/lib/hecks/composer/adapters/claude_composer.rb +83 -0
- data/lib/hecks/composer/adapters/fake_agent.adapter +3 -0
- data/lib/hecks/composer/adapters/fake_agent.rb +55 -0
- data/lib/hecks/composer/adapters/jev.adapter +3 -0
- data/lib/hecks/composer/adapters/jev.rb +66 -0
- data/lib/hecks/composer/agent.rb +113 -0
- data/lib/hecks/composer/assistant.rb +110 -0
- data/lib/hecks/composer/behavior_run.rb +53 -0
- data/lib/hecks/composer/bluebook/composer.bluebook +178 -0
- data/lib/hecks/composer/bluebook/composer.hecksagon +16 -0
- data/lib/hecks/composer/board.rb +65 -0
- data/lib/hecks/composer/board_edit/command_text.rb +39 -0
- data/lib/hecks/composer/board_edit/source.rb +84 -0
- data/lib/hecks/composer/board_edit.rb +144 -0
- data/lib/hecks/composer/check.rb +89 -0
- data/lib/hecks/composer/domains.rb +81 -0
- data/lib/hecks/composer/jobs.rb +134 -0
- data/lib/hecks/composer/layout.rb +37 -0
- data/lib/hecks/composer/live.rb +150 -0
- data/lib/hecks/composer/outline.rb +48 -0
- data/lib/hecks/composer/page.html +989 -0
- data/lib/hecks/composer/panels.rb +142 -0
- data/lib/hecks/composer/parse.rb +83 -0
- data/lib/hecks/composer/plain.rb +28 -0
- data/lib/hecks/composer/ports/composer_agent.port +7 -0
- data/lib/hecks/composer/session.rb +141 -0
- data/lib/hecks/composer/toolbox.rb +166 -0
- data/lib/hecks/composer/web.rb +156 -0
- data/lib/hecks/composer/workbench.rb +51 -0
- data/lib/hecks/composer/workspace.rb +81 -0
- data/lib/hecks/composer.rb +17 -0
- data/lib/hecks/corpus/adapters.rb +22 -0
- data/lib/hecks/corpus/rust.rb +1 -1
- data/lib/hecks/corpus/worlds.rb +19 -0
- data/lib/hecks/corpus.rb +5 -0
- data/lib/hecks/deploy/bluebook/deploy.bluebook +34 -34
- data/lib/hecks/forms/app/commands.rb +2 -3
- data/lib/hecks/forms/app/queries.rb +2 -3
- data/lib/hecks/forms/app/records.rb +17 -5
- data/lib/hecks/forms/command_form_renderer.rb +42 -16
- data/lib/hecks/forms/field_controls.rb +2 -2
- data/lib/hecks/forms/field_renderer.rb +1 -1
- data/lib/hecks/forms/field_shape.rb +36 -17
- data/lib/hecks/forms/index_renderer.rb +2 -1
- data/lib/hecks/forms/page.rb +1 -1
- data/lib/hecks/forms/params.rb +0 -13
- data/lib/hecks/forms/query_form_renderer.rb +7 -6
- data/lib/hecks/forms/record_renderer.rb +11 -7
- data/lib/hecks/forms/rule_words.rb +100 -0
- data/lib/hecks/forms/value_object_shape.rb +2 -1
- data/lib/hecks/framework/bluebook/change.bluebook +2 -2
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +0 -3
- data/lib/hecks/fuzzing/domain_generator/block_rendering.rb +1 -1
- data/lib/hecks/fuzzing/isolated_boot/worlds.rb +3 -6
- data/lib/hecks/fuzzing/replay/filters.rb +2 -6
- data/lib/hecks/gate/stages.yml +25 -0
- data/lib/hecks/grammar/evolve/seeds.rb +0 -6
- data/lib/hecks/grammar/evolve.rb +0 -3
- data/lib/hecks/grammar/translation.bluebook +1 -1
- data/lib/hecks/hecks/adapters/codebase/composing.rb +56 -0
- data/lib/hecks/hecks/adapters/codebase/source_tree.rb +3 -1
- data/lib/hecks/hecks/adapters/journal_store/changes.rb +0 -26
- data/lib/hecks/hecks/adapters/journal_store/examination.rb +2 -23
- data/lib/hecks/hecks/adapters/journal_store/readings.rb +3 -11
- data/lib/hecks/hecks/adapters/journal_store.rb +0 -11
- data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +4 -11
- data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +0 -9
- data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +0 -4
- data/lib/hecks/hecks/codebase.behaviors +6 -0
- data/lib/hecks/hecks/codebase.bluebook +58 -37
- data/lib/hecks/hecks/composer.behaviors +68 -0
- data/lib/hecks/hecks/context_map.hecksagon +1 -1
- data/lib/hecks/hecks/custodian.behaviors +0 -6
- data/lib/hecks/hecks/custodian.bluebook +15 -92
- data/lib/hecks/hecks/hecks.bluebook +2 -2
- data/lib/hecks/hecks/hecks.hecksagon +2 -2
- data/lib/hecks/hecks/hecks.world +1 -1
- data/lib/hecks/hecks/rehearsal.bluebook +10 -16
- data/lib/hecks/hecks/tooling.bluebook +22 -22
- data/lib/hecks/kernel_capabilities/templates.rb +4 -4
- data/lib/hecks/kernel_capabilities.rb +1 -1
- data/lib/hecks/language/bluebook/aggregate.bluebook +1 -0
- data/lib/hecks/language/bluebook/command.bluebook +1 -0
- data/lib/hecks/language/bluebook/entity.bluebook +1 -0
- data/lib/hecks/language/bluebook/query.bluebook +1 -0
- data/lib/hecks/language/bluebook/shape.bluebook +8 -7
- data/lib/hecks/language/bluebook/vocabulary.bluebook +2 -3
- data/lib/hecks/language/hecksagon/port_operation.bluebook +1 -0
- data/lib/hecks/language/translation/translation_aggregate.bluebook +21 -24
- data/lib/hecks/ports/access_control.rb +2 -2
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +3 -41
- data/lib/hecks/ports/persistence/plugins/era/lineage/coverage.rb +7 -7
- data/lib/hecks/ports/persistence/plugins/era/lineage/rewrite.rb +25 -2
- data/lib/hecks/ports/persistence/plugins/era/lineage/rules.rb +4 -4
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +17 -25
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/base_sql.rb +0 -12
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/domain_rename.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +2 -22
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +0 -1
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +9 -3
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +3 -29
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/refusals.rb +2 -26
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +6 -33
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +2 -4
- data/lib/hecks/ports/persistence/plugins/era/translation/expression_sql.rb +52 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +23 -29
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/translation.rb +0 -1
- data/lib/hecks/ports/persistence/plugins/era.rb +3 -6
- data/lib/hecks/ports.rb +0 -1
- data/lib/hecks/projection_files.rb +3 -1
- data/lib/hecks/projections/deploy/templates/lambda/nat_comment_oauth.tmpl +1 -1
- data/lib/hecks/projections/glossary/entries.rb +10 -4
- data/lib/hecks/projections/glossary/groups.rb +42 -0
- data/lib/hecks/projections/glossary/html/page.rb +7 -2
- data/lib/hecks/projections/glossary/html/parser.rb +1 -1
- data/lib/hecks/projections/glossary/html/sections.rb +31 -11
- data/lib/hecks/projections/glossary/html.rb +1 -2
- data/lib/hecks/projections/glossary/markdown.rb +31 -28
- data/lib/hecks/projections/glossary/mermaid.rb +3 -0
- data/lib/hecks/projections/glossary/page.css +143 -153
- data/lib/hecks/projections/glossary/page.js +63 -3
- data/lib/hecks/projections/glossary/sentences/actions.rb +88 -0
- data/lib/hecks/projections/glossary/sentences/paths.rb +77 -0
- data/lib/hecks/projections/glossary/sentences/queries.rb +90 -0
- data/lib/hecks/projections/glossary/sentences/value_objects.rb +32 -5
- data/lib/hecks/projections/glossary/sentences.rb +13 -3
- data/lib/hecks/projections/glossary/slugs.rb +4 -1
- data/lib/hecks/projections/glossary.rb +2 -1
- data/lib/hecks/projections/plain_english.rb +97 -0
- data/lib/hecks/projections/rust_vocabulary/arguments.rb +2 -2
- data/lib/hecks/projections/rust_vocabulary/enum_body.rb +20 -25
- data/lib/hecks/projections/rust_vocabulary/tests.rb +2 -2
- data/lib/hecks/projections/rust_vocabulary.rb +14 -6
- data/lib/hecks/projections/site/cms_editor/color.rb +0 -6
- data/lib/hecks/projections/statements/actions.rb +99 -0
- data/lib/hecks/projections/statements/relationships.rb +86 -0
- data/lib/hecks/projections/statements.rb +15 -24
- data/lib/hecks/projector/exporter/adapters.rb +112 -0
- data/lib/hecks/projector/exporter/translations.rb +18 -35
- data/lib/hecks/projector/exporter/worlds.rb +103 -0
- data/lib/hecks/projector/exporter.rb +5 -1
- data/lib/hecks/quality_control/adapters/agent.rb +6 -7
- data/lib/hecks/quality_control/adapters/agent_profile.rb +16 -114
- data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +1 -1
- data/lib/hecks/quality_control/quality_control.bluebook +51 -51
- data/lib/hecks/runtime/loader/boot_steps.rb +0 -20
- data/lib/hecks/runtime/outbox.rb +2 -9
- data/lib/hecks/runtime/port_operation_interpreter.rb +1 -9
- data/lib/hecks/runtime/remote_dispatcher.rb +2 -2
- data/lib/hecks/runtime/value.rb +13 -0
- data/lib/hecks/rust_build/project_rust/target_ir.rb +23 -4
- data/lib/hecks/rust_build/wasm.rb +0 -12
- data/lib/hecks/rust_build/write_if_changed.rb +12 -12
- data/lib/hecks/rust_format.rb +77 -0
- data/lib/hecks/site/bluebook/site.bluebook +5 -5
- data/lib/hecks/sme/bluebook/sme.bluebook +12 -12
- data/lib/hecks/tickets/bluebook/tickets.bluebook +3 -3
- data/lib/hecks/tools/fuzz_sweep/findings.rb +3 -9
- data/lib/hecks/tools/fuzz_sweep.rb +1 -3
- data/lib/hecks/tools/translation_audit/verdicts.rb +3 -28
- data/lib/hecks/tools/translation_audit.rb +8 -10
- data/lib/hecks/tools/translation_scaffold/reporting.rb +1 -1
- data/lib/hecks/version.rb +1 -1
- data/lib/hecks/vocabulary.rb +2 -1
- data/lib/hecks.rb +3 -0
- data/prebuilt/{58208399bada10b0db99928c48e38789288fc58f7b71a72b21bfa386680e32ed.marshal → 02c09c73b272c1fb5a9ae6d87bb5e5e529208e00f6b4b597dc2c0fd70a9c0964.marshal} +0 -0
- data/prebuilt/{2b59737fbdbd5f44edda0fddce2611f45d76087b3a7c782d1f1a17ea58c77948.marshal → bb84a835cf6a15136bad5ca03aa5bf93a5b92f5f72444618d3ef2412b987fb32.marshal} +0 -0
- data/prebuilt/verdicts-f1f10da14c8e8f01b4c9b7e3e2d74be8cd2bf4676364ed17fa16975d2a076d75.json +1 -0
- data/rust/Cargo.toml +40 -0
- data/rust/build/Cargo.toml +36 -0
- data/rust/build/clippy.toml +4 -0
- data/rust/build/src/adapters_pass.rs +196 -0
- data/rust/build/src/binding_pass.rs +54 -13
- data/rust/build/src/build_artifact.rs +23 -5
- data/rust/build/src/cargo_sync.rs +69 -26
- data/rust/build/src/lineage_pass.rs +101 -87
- data/rust/build/src/main.rs +11 -2
- data/rust/build/src/pipeline.rs +80 -19
- data/rust/build/src/reserved_names.rs +6 -50
- data/rust/build/src/resolve.rs +82 -35
- data/rust/build/src/rustfmt.rs +100 -0
- data/rust/build/src/seams_pass.rs +85 -16
- data/rust/build/src/subprocess.rs +30 -6
- data/rust/build/src/tmp.rs +5 -2
- data/rust/build/src/translation_pass.rs +72 -22
- data/rust/build/src/world_pass.rs +109 -0
- data/rust/clippy.toml +4 -0
- data/rust/codegen/Cargo.toml +36 -0
- data/rust/codegen/clippy.toml +4 -0
- data/rust/codegen/src/asks.rs +40 -14
- data/rust/codegen/src/attr.rs +2 -2
- data/rust/codegen/src/bridging.rs +676 -117
- data/rust/codegen/src/commands.rs +979 -373
- data/rust/codegen/src/constraints.rs +88 -25
- data/rust/codegen/src/dependency_planning.rs +128 -34
- data/rust/codegen/src/domain_generator.rs +300 -170
- data/rust/codegen/src/exemplar.rs +87 -32
- data/rust/codegen/src/expr_emitter.rs +54 -6
- data/rust/codegen/src/fielded.rs +193 -41
- data/rust/codegen/src/hecks_naming.rs +124 -16
- data/rust/codegen/src/hecks_naming_tests.rs +81 -0
- data/rust/codegen/src/json.rs +80 -44
- data/rust/codegen/src/json_codec.rs +585 -149
- data/rust/codegen/src/literal.rs +104 -138
- data/rust/codegen/src/main.rs +145 -52
- data/rust/codegen/src/manifest.rs +76 -14
- data/rust/codegen/src/mutations.rs +1212 -239
- data/rust/codegen/src/naming.rs +111 -60
- data/rust/codegen/src/optional_pass.rs +90 -28
- data/rust/codegen/src/ports.rs +5 -4
- data/rust/codegen/src/prelude.rs +139 -49
- data/rust/codegen/src/queries.rs +601 -226
- data/rust/codegen/src/reactions.rs +268 -74
- data/rust/codegen/src/read_models.rs +606 -205
- data/rust/codegen/src/reference_specs.rs +16 -3
- data/rust/codegen/src/registry.rs +128 -79
- data/rust/codegen/src/reserved_names.rs +6 -50
- data/rust/codegen/src/shared.rs +71 -22
- data/rust/codegen/src/sidecars.rs +15 -5
- data/rust/codegen/src/skip_reason.rs +8 -2
- data/rust/codegen/src/types.rs +306 -108
- data/rust/host/Cargo.lock +1 -0
- data/rust/host/Cargo.toml +40 -4
- data/rust/host/HECKS_RELEASE +1 -1
- data/rust/host/clippy.toml +4 -0
- data/rust/host/src/api.rs +698 -218
- data/rust/host/src/auth.rs +491 -214
- data/rust/host/src/b64.rs +91 -0
- data/rust/host/src/bin/expr_harness.rs +6 -2
- data/rust/host/src/bin/lineage_harness.rs +47 -11
- data/rust/host/src/bin/mint_harness.rs +70 -37
- data/rust/host/src/bin/validate_harness.rs +16 -8
- data/rust/host/src/boot.rs +144 -68
- data/rust/host/src/boundary_fuzz/api.rs +130 -32
- data/rust/host/src/boundary_fuzz/auth.rs +108 -23
- data/rust/host/src/boundary_fuzz/expr_json.rs +85 -11
- data/rust/host/src/boundary_fuzz/ir.rs +164 -12
- data/rust/host/src/boundary_fuzz/server.rs +283 -36
- data/rust/host/src/boundary_fuzz/web.rs +56 -8
- data/rust/host/src/checkout.rs +78 -32
- data/rust/host/src/clock.rs +8 -0
- data/rust/host/src/commerce_ir.rs +333 -95
- data/rust/host/src/crypto.rs +33 -0
- data/rust/host/src/dispatch.rs +990 -331
- data/rust/host/src/expr_json.rs +1021 -273
- data/rust/host/src/extension.rs +24 -4
- data/rust/host/src/field_hints.rs +11 -7
- data/rust/host/src/fuzz_support.rs +85 -13
- data/rust/host/src/host.rs +100 -0
- data/rust/host/src/http.rs +22 -0
- data/rust/host/src/ir.rs +326 -16
- data/rust/host/src/journal.rs +277 -176
- data/rust/host/src/lambda_client.rs +219 -53
- data/rust/host/src/lib.rs +16 -4
- data/rust/host/src/log.rs +62 -11
- data/rust/host/src/mint.rs +1153 -326
- data/rust/host/src/needs.rs +185 -44
- data/rust/host/src/payments/keystore.rs +197 -45
- data/rust/host/src/payments/roles.rs +191 -0
- data/rust/host/src/payments/tests.rs +1445 -275
- data/rust/host/src/payments.rs +409 -121
- data/rust/host/src/platform_signin/attack_tests.rs +5 -5
- data/rust/host/src/platform_signin/config.rs +11 -11
- data/rust/host/src/platform_signin/cookie.rs +2 -2
- data/rust/host/src/platform_signin/extension.rs +2 -1
- data/rust/host/src/platform_signin/handler.rs +9 -8
- data/rust/host/src/platform_signin/jti.rs +4 -2
- data/rust/host/src/platform_signin/jwks.rs +2 -1
- data/rust/host/src/platform_signin/jws.rs +2 -37
- data/rust/host/src/platform_signin/known_answer_tests.rs +5 -1
- data/rust/host/src/platform_signin/mode_tests.rs +5 -3
- data/rust/host/src/platform_signin/pages.rs +20 -20
- data/rust/host/src/platform_signin/session.rs +8 -1
- data/rust/host/src/platform_signin/settings.rs +6 -6
- data/rust/host/src/platform_signin/strict_json.rs +12 -9
- data/rust/host/src/platform_signin/verify.rs +41 -41
- data/rust/host/src/platform_signin/wiring_support.rs +13 -18
- data/rust/host/src/presentation.rs +207 -63
- data/rust/host/src/presentation_write.rs +502 -187
- data/rust/host/src/query_step.rs +69 -18
- data/rust/host/src/rate_limit.rs +541 -142
- data/rust/host/src/reference_transform.rs +77 -25
- data/rust/host/src/reference_validate.rs +443 -104
- data/rust/host/src/resend.rs +190 -55
- data/rust/host/src/secrets.rs +116 -21
- data/rust/host/src/server.rs +483 -104
- data/rust/host/src/storage_shape.rs +88 -21
- data/rust/host/src/test_pg.rs +17 -7
- data/rust/host/src/ui_schema.rs +495 -207
- data/rust/host/src/wasm_runner.rs +21 -6
- data/rust/host/src/web/commerce.rs +101 -23
- data/rust/host/src/web/newsletter/cooldown.rs +10 -3
- data/rust/host/src/web/newsletter/template.rs +26 -7
- data/rust/host/src/web/newsletter/tests.rs +112 -23
- data/rust/host/src/web/newsletter.rs +209 -59
- data/rust/host/src/web/newsletter_send.rs +251 -79
- data/rust/host/src/web/registration_receipt/tests.rs +16 -4
- data/rust/host/src/web/registration_receipt.rs +100 -24
- data/rust/host/src/web/registrations.rs +1384 -332
- data/rust/host/src/web/resend_webhook.rs +138 -80
- data/rust/host/src/web.rs +2416 -508
- data/rust/lsp/Cargo.toml +36 -0
- data/rust/lsp/clippy.toml +4 -0
- data/rust/lsp/src/json.rs +29 -22
- data/rust/lsp/src/main.rs +81 -31
- data/rust/lsp/src/outline.rs +23 -7
- data/rust/lsp/src/rpc.rs +17 -4
- data/rust/parser/Cargo.toml +36 -0
- data/rust/parser/clippy.toml +4 -0
- data/rust/parser/src/build/closed_sets.rs +6 -1
- data/rust/parser/src/build/identity.rs +4 -3
- data/rust/parser/src/build/mod.rs +1 -0
- data/rust/parser/src/build/named_pattern.rs +26 -0
- data/rust/parser/src/build/naming.rs +2 -80
- data/rust/parser/src/build/pattern_subset.rs +6 -8
- data/rust/parser/src/build/query_derive.rs +3 -1
- data/rust/parser/src/build/query_inference.rs +14 -5
- data/rust/parser/src/build/read_model.rs +4 -1
- data/rust/parser/src/build/references.rs +4 -3
- data/rust/parser/src/canonical.rs +34 -15
- data/rust/parser/src/emit.rs +187 -105
- data/rust/parser/src/expr/ast_json.rs +134 -42
- data/rust/parser/src/expr/evaluator.rs +27 -9
- data/rust/parser/src/expr/mod.rs +54 -13
- data/rust/parser/src/expr/resolver.rs +299 -92
- data/rust/parser/src/ir.rs +35 -3
- data/rust/parser/src/keywords.rs +7168 -510
- data/rust/parser/src/lex.rs +11 -25
- data/rust/parser/src/lib.rs +1 -0
- data/rust/parser/src/main.rs +65 -6
- data/rust/parser/src/parse/adapter.rs +157 -0
- data/rust/parser/src/parse/aggregate.rs +19 -10
- data/rust/parser/src/parse/chapter.rs +16 -17
- data/rust/parser/src/parse/command.rs +35 -16
- data/rust/parser/src/parse/domain_port.rs +4 -7
- data/rust/parser/src/parse/entity.rs +21 -11
- data/rust/parser/src/parse/hecksagon.rs +10 -4
- data/rust/parser/src/parse/lifecycle.rs +9 -5
- data/rust/parser/src/parse/mod.rs +43 -91
- data/rust/parser/src/parse/needs.rs +21 -12
- data/rust/parser/src/parse/policy.rs +2 -2
- data/rust/parser/src/parse/process_manager.rs +9 -11
- data/rust/parser/src/parse/query.rs +8 -4
- data/rust/parser/src/parse/read_model.rs +57 -16
- data/rust/parser/src/parse/value_object.rs +7 -2
- data/rust/parser/src/parse/world.rs +322 -0
- data/rust/parser/src/ruby_value.rs +7 -6
- data/rust/src/exemplar/json.rs +4 -4
- data/rust/src/exemplar/mutations.rs +18 -0
- data/rust/src/exemplar/read_models.rs +1 -10
- data/rust/src/kernel/attribute_shapes/composite.rs +54 -14
- data/rust/src/kernel/attribute_shapes/list.rs +2 -2
- data/rust/src/kernel/attribute_shapes/mod.rs +8 -8
- data/rust/src/kernel/attribute_shapes/scalar.rs +2 -2
- data/rust/src/kernel/cli.rs +229 -112
- data/rust/src/kernel/dispatch.rs +323 -115
- data/rust/src/kernel/dispatch_guard_tests.rs +327 -65
- data/rust/src/kernel/expr.rs +203 -86
- data/rust/src/kernel/expression_operators/arithmetic.rs +138 -25
- data/rust/src/kernel/expression_operators/comparison.rs +87 -2
- data/rust/src/kernel/expression_operators/enumeration.rs +106 -22
- data/rust/src/kernel/expression_operators/logical.rs +9 -3
- data/rust/src/kernel/expression_operators/membership.rs +3 -1
- data/rust/src/kernel/expression_operators/mod.rs +34 -21
- data/rust/src/kernel/expression_operators/pattern_match.rs +46 -11
- data/rust/src/kernel/expression_operators/positional.rs +84 -30
- data/rust/src/kernel/expression_operators/presence.rs +52 -13
- data/rust/src/kernel/expression_operators/sign_test.rs +3 -1
- data/rust/src/kernel/expression_operators/sized.rs +24 -8
- data/rust/src/kernel/expression_operators/text.rs +120 -27
- data/rust/src/kernel/expression_operators/to_string.rs +10 -4
- data/rust/src/kernel/json.rs +230 -148
- data/rust/src/kernel/mod.rs +46 -33
- data/rust/src/kernel/named_query.rs +63 -15
- data/rust/src/kernel/needs.rs +112 -25
- data/rust/src/kernel/orchestrate.rs +980 -581
- data/rust/src/kernel/orchestrate_guard_tests.rs +538 -140
- data/rust/src/kernel/pattern.rs +107 -34
- data/rust/src/kernel/query_comparators.rs +118 -41
- data/rust/src/kernel/query_ordering.rs +13 -5
- data/rust/src/kernel/read_model.rs +479 -181
- data/rust/src/kernel/reference_lookup.rs +122 -26
- data/rust/src/kernel/repository.rs +293 -66
- data/rust/src/kernel/routing.rs +58 -42
- data/rust/src/kernel/ruby_float.rs +139 -0
- data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +57 -57
- data/rust/src/kernel/vocab/entity_dispatch_order.rs +54 -54
- data/rust/src/kernel/vocab/field_hint.rs +19 -25
- data/rust/src/kernel/vocab/mod.rs +6 -6
- data/rust/src/kernel/vocab/query_comparator.rs +23 -24
- data/rust/src/kernel/vocab/refusal_template.rs +501 -297
- data/rust/src/lib.rs +50 -0
- data/rust/src/main.rs +4 -1
- data/rust/web/Cargo.toml +36 -0
- data/rust/web/clippy.toml +4 -0
- metadata +85 -15
- data/examples/pizzas/bluebook/hecksagon/mock_stripe_payment_adapter.rb +0 -36
- data/lib/hecks/adapters/driven/google_authentication.adapter +0 -3
- data/lib/hecks/adapters/driven/google_authentication.rb +0 -99
- data/lib/hecks/adapters/driven/mock_stripe_adapter.adapter +0 -3
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +0 -32
- data/lib/hecks/ports/authentication.port +0 -6
- data/lib/hecks/ports/authentication.rb +0 -67
- data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +0 -255
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +0 -22
- data/prebuilt/verdicts-48318ca172edd21443b1ad02801c697fff100b746e828f09db987647641a5df2.json +0 -1
- data/rust/host/src/approval.rs +0 -652
|
@@ -303,7 +303,7 @@ fn rejects_a_tampered_signature_one_bit_flipped_and_every_wrong_length() {
|
|
|
303
303
|
wrong.len()
|
|
304
304
|
);
|
|
305
305
|
}
|
|
306
|
-
let mut longer = bytes
|
|
306
|
+
let mut longer = bytes;
|
|
307
307
|
longer.extend_from_slice(&[0, 0]);
|
|
308
308
|
assert_eq!(
|
|
309
309
|
raw_token_reason(Some(&format!(
|
|
@@ -441,11 +441,11 @@ fn rejects_claims_of_the_wrong_json_type() {
|
|
|
441
441
|
Reason::Malformed
|
|
442
442
|
);
|
|
443
443
|
assert_eq!(
|
|
444
|
-
refused_with(|s| set(s, "exp", json!(
|
|
444
|
+
refused_with(|s| set(s, "exp", json!(1_800_000_060.0))),
|
|
445
445
|
Reason::Malformed
|
|
446
446
|
);
|
|
447
447
|
assert_eq!(
|
|
448
|
-
refused_with(|s| set(s, "iat", json!(
|
|
448
|
+
refused_with(|s| set(s, "iat", json!(1_800_000_000.5))),
|
|
449
449
|
Reason::Malformed
|
|
450
450
|
);
|
|
451
451
|
assert_eq!(
|
|
@@ -911,7 +911,7 @@ fn bad_env(s: &mut Scenario) {
|
|
|
911
911
|
set(s, "env", json!("staging"));
|
|
912
912
|
}
|
|
913
913
|
fn float_exp(s: &mut Scenario) {
|
|
914
|
-
set(s, "exp", json!(
|
|
914
|
+
set(s, "exp", json!(1_800_000_060.5));
|
|
915
915
|
}
|
|
916
916
|
fn not_yet_valid(s: &mut Scenario) {
|
|
917
917
|
set(s, "nbf", json!(NOW + 100));
|
|
@@ -1048,7 +1048,7 @@ fn every_single_character_mutation_of_a_good_token_is_answered_without_panicking
|
|
|
1048
1048
|
continue;
|
|
1049
1049
|
}
|
|
1050
1050
|
let mut mutated = good.clone();
|
|
1051
|
-
mutated.replace_range(position
|
|
1051
|
+
mutated.replace_range(position..=position, &replacement.to_string());
|
|
1052
1052
|
let request = SigninRequest {
|
|
1053
1053
|
token: Some(&mutated),
|
|
1054
1054
|
state: Some(STATE),
|
|
@@ -62,19 +62,19 @@ pub enum ConfigProblem {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
impl ConfigProblem {
|
|
65
|
-
fn describe(self) -> &'static str {
|
|
65
|
+
const fn describe(self) -> &'static str {
|
|
66
66
|
match self {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
Self::Missing => "is not set",
|
|
68
|
+
Self::NotHttps => "must be an https URL",
|
|
69
|
+
Self::CredentialsInUrl => "must not carry credentials",
|
|
70
|
+
Self::PathQueryOrFragment => {
|
|
71
71
|
"must not carry a path, query or fragment (no trailing slash)"
|
|
72
72
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
73
|
+
Self::BadHost => "must name a plain lowercase host and an optional port",
|
|
74
|
+
Self::UpperCase => "must be lowercase",
|
|
75
|
+
Self::BadShape => "has an invalid shape",
|
|
76
|
+
Self::WrongHostForIssuer => "must be on the issuer's host",
|
|
77
|
+
Self::NotAnEnvironment => "must be production or staging",
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
}
|
|
@@ -135,7 +135,7 @@ impl PlatformSigninConfig {
|
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
fn fail(variable: &'static str, problem: ConfigProblem) -> ConfigError {
|
|
138
|
+
const fn fail(variable: &'static str, problem: ConfigProblem) -> ConfigError {
|
|
139
139
|
ConfigError { variable, problem }
|
|
140
140
|
}
|
|
141
141
|
|
|
@@ -101,7 +101,7 @@ fn parse_value(value: &str) -> Option<SigninCookie> {
|
|
|
101
101
|
})
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
fn is_url_safe(byte: u8) -> bool {
|
|
104
|
+
const fn is_url_safe(byte: u8) -> bool {
|
|
105
105
|
byte.is_ascii_alphanumeric() || byte == b'-' || byte == b'_'
|
|
106
106
|
}
|
|
107
107
|
|
|
@@ -121,7 +121,7 @@ mod tests {
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
fn pairs(items: &[&str]) -> Vec<String> {
|
|
124
|
-
items.iter().map(
|
|
124
|
+
items.iter().map(std::string::ToString::to_string).collect()
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
#[test]
|
|
@@ -50,7 +50,7 @@ pub struct PlatformSignin {
|
|
|
50
50
|
|
|
51
51
|
impl PlatformSignin {
|
|
52
52
|
/// Wraps a handler that is already built.
|
|
53
|
-
pub fn new(handler: SigninHandler) -> Self {
|
|
53
|
+
pub const fn new(handler: SigninHandler) -> Self {
|
|
54
54
|
Self { handler }
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -181,6 +181,7 @@ impl HostExtension for RefusedSettings {
|
|
|
181
181
|
|
|
182
182
|
/// The extensions that platform sign-in contributes for these settings: none when it is off, the
|
|
183
183
|
/// flow when it is on, and a boot refusal when the settings are wrong.
|
|
184
|
+
#[allow(clippy::implicit_hasher)] // reason: the settings map always comes from this crate's own default-hashed env reader
|
|
184
185
|
pub fn extensions_for(vars: &HashMap<String, String>) -> Vec<Arc<dyn HostExtension>> {
|
|
185
186
|
match PlatformSignin::from_env_map(vars) {
|
|
186
187
|
Ok(None) => Vec::new(),
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
//! The token, the nonce, the state and the cookie are never written to a log, and an email only as
|
|
17
17
|
//! a short hash. A refusal logs its stable code.
|
|
18
18
|
|
|
19
|
+
use std::fmt::Write;
|
|
19
20
|
use std::sync::Arc;
|
|
20
21
|
|
|
21
22
|
use serde_json::{json, Value};
|
|
@@ -38,7 +39,7 @@ pub trait TokenVerifier: Send + Sync {
|
|
|
38
39
|
|
|
39
40
|
impl<K: KeySource + Send + Sync> TokenVerifier for Verifier<K> {
|
|
40
41
|
fn verify(&self, request: &SigninRequest<'_>, now: i64) -> Result<VerifiedClaims, Refusal> {
|
|
41
|
-
|
|
42
|
+
Self::verify(self, request, now)
|
|
42
43
|
}
|
|
43
44
|
}
|
|
44
45
|
|
|
@@ -72,10 +73,7 @@ pub fn fresh_value() -> String {
|
|
|
72
73
|
|
|
73
74
|
/// Reads the system clock.
|
|
74
75
|
pub fn system_clock() -> i64 {
|
|
75
|
-
|
|
76
|
-
.duration_since(std::time::UNIX_EPOCH)
|
|
77
|
-
.map(|elapsed| elapsed.as_secs() as i64)
|
|
78
|
-
.unwrap_or(0)
|
|
76
|
+
crate::clock::unix_now()
|
|
79
77
|
}
|
|
80
78
|
|
|
81
79
|
/// What a callback request carried, already separated from any headers.
|
|
@@ -125,7 +123,7 @@ impl SigninHandler {
|
|
|
125
123
|
}
|
|
126
124
|
|
|
127
125
|
/// Returns the validated settings.
|
|
128
|
-
pub fn settings(&self) -> &SigninSettings {
|
|
126
|
+
pub const fn settings(&self) -> &SigninSettings {
|
|
129
127
|
&self.settings
|
|
130
128
|
}
|
|
131
129
|
|
|
@@ -235,7 +233,7 @@ impl SigninHandler {
|
|
|
235
233
|
|
|
236
234
|
/// The page a verifier refusal earns: the browser's own cookie and state are told apart, the rest
|
|
237
235
|
/// share one answer so the page teaches nothing about which later check failed.
|
|
238
|
-
fn failure_for(reason: Reason) -> Failure {
|
|
236
|
+
const fn failure_for(reason: Reason) -> Failure {
|
|
239
237
|
match reason {
|
|
240
238
|
Reason::MissingCookie => Failure::Cookie,
|
|
241
239
|
Reason::StateMismatch => Failure::State,
|
|
@@ -246,6 +244,9 @@ fn failure_for(reason: Reason) -> Failure {
|
|
|
246
244
|
/// The first four bytes of the lowercased email's SHA-256, enough to tell people apart in a log.
|
|
247
245
|
fn short_hash(email: &str) -> String {
|
|
248
246
|
let digest = Sha256::digest(email.to_lowercase().as_bytes());
|
|
249
|
-
let hex
|
|
247
|
+
let hex = digest.iter().take(4).fold(String::new(), |mut hex, b| {
|
|
248
|
+
let _ = write!(hex, "{b:02x}"); // writing to a String cannot fail
|
|
249
|
+
hex
|
|
250
|
+
});
|
|
250
251
|
format!("h:{hex}")
|
|
251
252
|
}
|
|
@@ -63,7 +63,7 @@ impl JtiStore {
|
|
|
63
63
|
// forever would be a lock-out, so a poisoned lock is simply taken over.
|
|
64
64
|
self.seen
|
|
65
65
|
.lock()
|
|
66
|
-
.unwrap_or_else(
|
|
66
|
+
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
/// Counts the identifiers still remembered at `now`; expired ones are not counted.
|
|
@@ -176,7 +176,9 @@ mod tests {
|
|
|
176
176
|
})
|
|
177
177
|
})
|
|
178
178
|
.collect();
|
|
179
|
-
handles
|
|
179
|
+
for handle in handles {
|
|
180
|
+
handle.join().unwrap();
|
|
181
|
+
}
|
|
180
182
|
assert_eq!(winners.load(Ordering::SeqCst), 1, "round {round}");
|
|
181
183
|
}
|
|
182
184
|
}
|
|
@@ -201,7 +201,7 @@ impl<F: JwksFetcher> JwksCache<F> {
|
|
|
201
201
|
// The state is only ever replaced whole, so a panic elsewhere cannot leave it half-written.
|
|
202
202
|
self.state
|
|
203
203
|
.lock()
|
|
204
|
-
.unwrap_or_else(
|
|
204
|
+
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
fn is_stale(&self, state: &CacheState, now: i64) -> bool {
|
|
@@ -445,6 +445,7 @@ mod tests {
|
|
|
445
445
|
(JwksCache::new(fetcher), calls)
|
|
446
446
|
}
|
|
447
447
|
|
|
448
|
+
#[allow(clippy::unnecessary_wraps)] // reason: a scripted fetch answer has the fetcher's Result type
|
|
448
449
|
fn one_key(x: &str) -> Result<String, FetchFailed> {
|
|
449
450
|
Ok(document(&[format!(
|
|
450
451
|
r#"{{"kty":"OKP","crv":"Ed25519","x":"{x}"}}"#
|
|
@@ -14,22 +14,9 @@
|
|
|
14
14
|
|
|
15
15
|
use super::strict_json::{self, JsonObject};
|
|
16
16
|
|
|
17
|
-
const ALPHABET: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
18
|
-
|
|
19
17
|
/// Encodes bytes as unpadded base64url (RFC 4648 section 5).
|
|
20
18
|
pub fn encode_base64url(bytes: &[u8]) -> String {
|
|
21
|
-
|
|
22
|
-
for chunk in bytes.chunks(3) {
|
|
23
|
-
let word = chunk
|
|
24
|
-
.iter()
|
|
25
|
-
.enumerate()
|
|
26
|
-
.fold(0u32, |acc, (i, b)| acc | (*b as u32) << (16 - 8 * i));
|
|
27
|
-
let characters = chunk.len() + 1;
|
|
28
|
-
for i in 0..characters {
|
|
29
|
-
out.push(ALPHABET[((word >> (18 - 6 * i)) & 0x3f) as usize] as char);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
out
|
|
19
|
+
crate::b64::url_encode(bytes)
|
|
33
20
|
}
|
|
34
21
|
|
|
35
22
|
/// Decodes canonical unpadded base64url.
|
|
@@ -37,29 +24,7 @@ pub fn encode_base64url(bytes: &[u8]) -> String {
|
|
|
37
24
|
/// Returns `None` for padding, any character outside the URL-safe alphabet, a length that no byte
|
|
38
25
|
/// string encodes to, and spare trailing bits that are not zero.
|
|
39
26
|
pub fn decode_base64url(text: &str) -> Option<Vec<u8>> {
|
|
40
|
-
|
|
41
|
-
return None;
|
|
42
|
-
}
|
|
43
|
-
let mut out = Vec::with_capacity(text.len() / 4 * 3 + 2);
|
|
44
|
-
let (mut accumulator, mut bits) = (0u32, 0u32);
|
|
45
|
-
for byte in text.bytes() {
|
|
46
|
-
accumulator = accumulator << 6 | sextet(byte)?;
|
|
47
|
-
bits += 6;
|
|
48
|
-
if bits >= 8 {
|
|
49
|
-
bits -= 8;
|
|
50
|
-
out.push((accumulator >> bits) as u8);
|
|
51
|
-
accumulator &= (1 << bits) - 1;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
// Spare bits must be zero, or a second spelling would decode to the same bytes.
|
|
55
|
-
(accumulator == 0).then_some(out)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
fn sextet(byte: u8) -> Option<u32> {
|
|
59
|
-
ALPHABET
|
|
60
|
-
.iter()
|
|
61
|
-
.position(|candidate| *candidate == byte)
|
|
62
|
-
.map(|index| index as u32)
|
|
27
|
+
crate::b64::url_decode(text)
|
|
63
28
|
}
|
|
64
29
|
|
|
65
30
|
/// Why a token text was refused before any claim was read.
|
|
@@ -32,7 +32,11 @@ fn document() -> Value {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
fn hex(digest: &[u8]) -> String {
|
|
35
|
-
|
|
35
|
+
use std::fmt::Write;
|
|
36
|
+
digest.iter().fold(String::new(), |mut out, b| {
|
|
37
|
+
let _ = write!(out, "{b:02x}"); // writing to a String cannot fail
|
|
38
|
+
out
|
|
39
|
+
})
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
fn text<'a>(value: &'a Value, name: &str) -> &'a str {
|
|
@@ -69,13 +69,14 @@ fn an_unset_switch_installs_nothing() {
|
|
|
69
69
|
let mut vars = env_map("alongside");
|
|
70
70
|
vars.remove("PLATFORM_SIGNIN");
|
|
71
71
|
assert!(extensions_for(&vars).is_empty());
|
|
72
|
-
assert!(extensions_for(&
|
|
72
|
+
assert!(extensions_for(&std::collections::HashMap::default()).is_empty());
|
|
73
73
|
assert!(PlatformSignin::from_env_map(&vars).unwrap().is_none());
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
#[test]
|
|
77
77
|
fn the_default_extension_list_is_unchanged_when_the_switch_is_unset() {
|
|
78
|
-
let installed =
|
|
78
|
+
let installed =
|
|
79
|
+
crate::extension::default_extensions_from(&std::collections::HashMap::default());
|
|
79
80
|
assert_eq!(installed.len(), 1);
|
|
80
81
|
assert!(installed[0]
|
|
81
82
|
.rate_rules()
|
|
@@ -95,7 +96,8 @@ fn a_switched_on_site_adds_exactly_one_extension() {
|
|
|
95
96
|
async fn off_means_the_new_paths_reach_the_hosts_own_handling() {
|
|
96
97
|
// With no extension installed the loop in `web::render` finds nobody; this pins what a
|
|
97
98
|
// request for the new path meets instead: the hosts own routes, which know nothing of it.
|
|
98
|
-
let installed =
|
|
99
|
+
let installed =
|
|
100
|
+
crate::extension::default_extensions_from(&std::collections::HashMap::default());
|
|
99
101
|
assert_eq!(installed.len(), 1);
|
|
100
102
|
assert!(installed
|
|
101
103
|
.iter()
|
|
@@ -28,40 +28,40 @@ pub enum Failure {
|
|
|
28
28
|
|
|
29
29
|
impl Failure {
|
|
30
30
|
/// Every code the flow can show, in a fixed order.
|
|
31
|
-
pub const ALL: [
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
pub const ALL: [Self; 6] = [
|
|
32
|
+
Self::Cookie,
|
|
33
|
+
Self::State,
|
|
34
|
+
Self::Params,
|
|
35
|
+
Self::Token,
|
|
36
|
+
Self::Unlinked,
|
|
37
|
+
Self::Unavailable,
|
|
38
38
|
];
|
|
39
39
|
|
|
40
40
|
/// Returns the stable code shown on the page and logged.
|
|
41
|
-
pub fn code(self) -> &'static str {
|
|
41
|
+
pub const fn code(self) -> &'static str {
|
|
42
42
|
match self {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
Self::Cookie => "platform_cookie",
|
|
44
|
+
Self::State => "platform_state",
|
|
45
|
+
Self::Params => "platform_params",
|
|
46
|
+
Self::Token => "platform_token",
|
|
47
|
+
Self::Unlinked => "google_unlinked",
|
|
48
|
+
Self::Unavailable => "platform_unavailable",
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/// Returns the HTTP status.
|
|
53
|
-
pub fn status(self) -> u16 {
|
|
53
|
+
pub const fn status(self) -> u16 {
|
|
54
54
|
match self {
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
Self::Unlinked => 403,
|
|
56
|
+
Self::Unavailable => 500,
|
|
57
57
|
_ => 400,
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
fn message(self) -> &'static str {
|
|
61
|
+
const fn message(self) -> &'static str {
|
|
62
62
|
match self {
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
Self::Unlinked => "This account does not have access to this site.",
|
|
64
|
+
Self::Unavailable => "Sign-in is unavailable. Please try again later.",
|
|
65
65
|
_ => "This sign-in link is not valid or has expired. Please start again from the site you came from.",
|
|
66
66
|
}
|
|
67
67
|
}
|
|
@@ -123,7 +123,14 @@ pub struct HostMembers<'a> {
|
|
|
123
123
|
#[async_trait]
|
|
124
124
|
impl MemberDirectory for HostMembers<'_> {
|
|
125
125
|
async fn identity_for(&self, issuer: &str, subject: &str) -> anyhow::Result<Option<String>> {
|
|
126
|
-
auth::resolve_identity_anywhere(
|
|
126
|
+
auth::resolve_identity_anywhere(
|
|
127
|
+
self.client,
|
|
128
|
+
self.wasm_path,
|
|
129
|
+
self.domain_ir,
|
|
130
|
+
issuer,
|
|
131
|
+
subject,
|
|
132
|
+
)
|
|
133
|
+
.await
|
|
127
134
|
}
|
|
128
135
|
|
|
129
136
|
async fn session_for_identity(&self, identity_id: &str) -> anyhow::Result<Option<Session>> {
|
|
@@ -74,8 +74,8 @@ pub enum SettingsError {
|
|
|
74
74
|
impl fmt::Display for SettingsError {
|
|
75
75
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
76
76
|
match self {
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
Self::Config(error) => write!(f, "{error}"),
|
|
78
|
+
Self::Setting { variable, problem } => write!(f, "{variable} {problem}"),
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
}
|
|
@@ -84,10 +84,10 @@ impl std::error::Error for SettingsError {}
|
|
|
84
84
|
|
|
85
85
|
impl SettingsError {
|
|
86
86
|
/// Returns the name of the variable at fault.
|
|
87
|
-
pub fn variable(&self) -> &'static str {
|
|
87
|
+
pub const fn variable(&self) -> &'static str {
|
|
88
88
|
match self {
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
Self::Config(error) => error.variable,
|
|
90
|
+
Self::Setting { variable, .. } => variable,
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
}
|
|
@@ -117,7 +117,7 @@ impl SigninSettings {
|
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
fn setting(variable: &'static str, problem: &'static str) -> SettingsError {
|
|
120
|
+
const fn setting(variable: &'static str, problem: &'static str) -> SettingsError {
|
|
121
121
|
SettingsError::Setting { variable, problem }
|
|
122
122
|
}
|
|
123
123
|
|
|
@@ -19,7 +19,7 @@ pub enum Json {
|
|
|
19
19
|
/// Any number that is not an integer literal (a fraction or an exponent).
|
|
20
20
|
Number,
|
|
21
21
|
Str(String),
|
|
22
|
-
Array(Vec<
|
|
22
|
+
Array(Vec<Self>),
|
|
23
23
|
Object(JsonObject),
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -258,21 +258,24 @@ impl Parser<'_> {
|
|
|
258
258
|
self.digits()?;
|
|
259
259
|
}
|
|
260
260
|
let integer_end = self.at;
|
|
261
|
-
let
|
|
262
|
-
if self.peek() == Some(b'.') {
|
|
261
|
+
let has_fraction = if self.peek() == Some(b'.') {
|
|
263
262
|
self.at += 1;
|
|
264
263
|
self.digits()?;
|
|
265
|
-
|
|
266
|
-
}
|
|
267
|
-
|
|
264
|
+
true
|
|
265
|
+
} else {
|
|
266
|
+
false
|
|
267
|
+
};
|
|
268
|
+
let has_exponent = if matches!(self.peek(), Some(b'e' | b'E')) {
|
|
268
269
|
self.at += 1;
|
|
269
270
|
if matches!(self.peek(), Some(b'+' | b'-')) {
|
|
270
271
|
self.at += 1;
|
|
271
272
|
}
|
|
272
273
|
self.digits()?;
|
|
273
|
-
|
|
274
|
-
}
|
|
275
|
-
|
|
274
|
+
true
|
|
275
|
+
} else {
|
|
276
|
+
false
|
|
277
|
+
};
|
|
278
|
+
if has_fraction || has_exponent {
|
|
276
279
|
return Some(Json::Number);
|
|
277
280
|
}
|
|
278
281
|
let text = std::str::from_utf8(&self.bytes[integer_start..integer_end]).ok()?;
|
|
@@ -74,53 +74,53 @@ pub enum Reason {
|
|
|
74
74
|
|
|
75
75
|
impl Reason {
|
|
76
76
|
/// Every reason, in the order the checks run.
|
|
77
|
-
pub const ALL: [
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
77
|
+
pub const ALL: [Self; 18] = [
|
|
78
|
+
Self::MissingCookie,
|
|
79
|
+
Self::StateMismatch,
|
|
80
|
+
Self::TooLarge,
|
|
81
|
+
Self::Malformed,
|
|
82
|
+
Self::BadAlg,
|
|
83
|
+
Self::UnknownKid,
|
|
84
|
+
Self::BadSignature,
|
|
85
|
+
Self::BadIss,
|
|
86
|
+
Self::BadAud,
|
|
87
|
+
Self::BadEnv,
|
|
88
|
+
Self::MissingClaim,
|
|
89
|
+
Self::NotYetValid,
|
|
90
|
+
Self::Expired,
|
|
91
|
+
Self::Lifetime,
|
|
92
|
+
Self::NonceMismatch,
|
|
93
|
+
Self::Replay,
|
|
94
|
+
Self::EmailUnverified,
|
|
95
|
+
Self::SubjectMismatch,
|
|
96
96
|
];
|
|
97
97
|
|
|
98
98
|
/// Returns the stable lowercase code, such as `"bad_aud"`.
|
|
99
|
-
pub fn code(self) -> &'static str {
|
|
99
|
+
pub const fn code(self) -> &'static str {
|
|
100
100
|
match self {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
101
|
+
Self::MissingCookie => "missing_cookie",
|
|
102
|
+
Self::StateMismatch => "state_mismatch",
|
|
103
|
+
Self::TooLarge => "too_large",
|
|
104
|
+
Self::Malformed => "malformed",
|
|
105
|
+
Self::BadAlg => "bad_alg",
|
|
106
|
+
Self::UnknownKid => "unknown_kid",
|
|
107
|
+
Self::BadSignature => "bad_signature",
|
|
108
|
+
Self::BadIss => "bad_iss",
|
|
109
|
+
Self::BadAud => "bad_aud",
|
|
110
|
+
Self::BadEnv => "bad_env",
|
|
111
|
+
Self::MissingClaim => "missing_claim",
|
|
112
|
+
Self::NotYetValid => "not_yet_valid",
|
|
113
|
+
Self::Expired => "expired",
|
|
114
|
+
Self::Lifetime => "lifetime",
|
|
115
|
+
Self::NonceMismatch => "nonce_mismatch",
|
|
116
|
+
Self::Replay => "replay",
|
|
117
|
+
Self::EmailUnverified => "email_unverified",
|
|
118
|
+
Self::SubjectMismatch => "subject_mismatch",
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
/// Finds the reason that has this code.
|
|
123
|
-
pub fn from_code(code: &str) -> Option<
|
|
123
|
+
pub fn from_code(code: &str) -> Option<Self> {
|
|
124
124
|
Self::ALL.into_iter().find(|reason| reason.code() == code)
|
|
125
125
|
}
|
|
126
126
|
}
|
|
@@ -133,7 +133,7 @@ pub struct Refusal {
|
|
|
133
133
|
|
|
134
134
|
impl Refusal {
|
|
135
135
|
/// Returns the stable reason code.
|
|
136
|
-
pub fn code(&self) -> &'static str {
|
|
136
|
+
pub const fn code(&self) -> &'static str {
|
|
137
137
|
self.reason.code()
|
|
138
138
|
}
|
|
139
139
|
}
|
|
@@ -221,7 +221,7 @@ impl<K: KeySource> Verifier<K> {
|
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
/// Exposes the single-use record, so a caller can share or inspect it.
|
|
224
|
-
pub fn jti_store(&self) -> &JtiStore {
|
|
224
|
+
pub const fn jti_store(&self) -> &JtiStore {
|
|
225
225
|
&self.jti_store
|
|
226
226
|
}
|
|
227
227
|
|
|
@@ -5,7 +5,7 @@ use std::collections::HashMap;
|
|
|
5
5
|
use std::sync::{Arc, Mutex};
|
|
6
6
|
|
|
7
7
|
use async_trait::async_trait;
|
|
8
|
-
use serde_json::
|
|
8
|
+
use serde_json::Value;
|
|
9
9
|
|
|
10
10
|
use super::config::PlatformSigninConfig;
|
|
11
11
|
use super::handler::{CallbackRequest, Random, SigninHandler, SigninLog};
|
|
@@ -235,17 +235,17 @@ pub fn request_for(step: &Value) -> CallbackRequest {
|
|
|
235
235
|
if let Some(state) = step["state"].as_str() {
|
|
236
236
|
query.push(format!("state={}", encode(state)));
|
|
237
237
|
}
|
|
238
|
-
let cookie_pairs =
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
238
|
+
let cookie_pairs =
|
|
239
|
+
step.get("cookie")
|
|
240
|
+
.filter(|c| !c.is_null())
|
|
241
|
+
.map_or_else(Vec::new, |cookie| {
|
|
242
|
+
let part = |n: &str| cookie.get(n).and_then(Value::as_str);
|
|
243
|
+
let value = part("state").map_or_else(
|
|
244
|
+
|| part("nonce").unwrap_or("").to_string(),
|
|
245
|
+
|state| format!("{}.{state}", part("nonce").unwrap_or("")),
|
|
246
|
+
);
|
|
247
|
+
vec![format!("__Host-signin={value}")]
|
|
248
|
+
});
|
|
249
249
|
CallbackRequest {
|
|
250
250
|
raw_query: query.join("&"),
|
|
251
251
|
cookie_pairs,
|
|
@@ -257,7 +257,7 @@ pub fn scripted_random(values: &[&str]) -> Random {
|
|
|
257
257
|
let queue = Mutex::new(
|
|
258
258
|
values
|
|
259
259
|
.iter()
|
|
260
|
-
.map(
|
|
260
|
+
.map(std::string::ToString::to_string)
|
|
261
261
|
.collect::<std::collections::VecDeque<_>>(),
|
|
262
262
|
);
|
|
263
263
|
Box::new(move || queue.lock().unwrap().pop_front().expect("a scripted value"))
|
|
@@ -312,8 +312,3 @@ pub fn single(doc: &Value, name: &str) -> Value {
|
|
|
312
312
|
.unwrap_or_else(|| panic!("vector {name}"))
|
|
313
313
|
.clone()
|
|
314
314
|
}
|
|
315
|
-
|
|
316
|
-
#[allow(dead_code)]
|
|
317
|
-
fn _unused() -> Value {
|
|
318
|
-
json!({})
|
|
319
|
-
}
|