capsium 0.1.2 → 0.3.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/.gitignore +1 -0
- data/.rubocop.yml +46 -7
- data/CHANGELOG.md +183 -0
- data/Gemfile +6 -0
- data/LICENSE +21 -0
- data/README.adoc +496 -127
- data/Rakefile +8 -1
- data/bin/console +1 -1
- data/capsium.gemspec +12 -19
- data/exe/capsium +1 -1
- data/lib/capsium/cli/convert.rb +18 -0
- data/lib/capsium/cli/formatting.rb +27 -0
- data/lib/capsium/cli/package.rb +148 -0
- data/lib/capsium/cli/reactor.rb +33 -0
- data/lib/capsium/cli.rb +4 -96
- data/lib/capsium/converters/jekyll.rb +5 -7
- data/lib/capsium/converters.rb +7 -0
- data/lib/capsium/package/authentication.rb +38 -0
- data/lib/capsium/package/authentication_config.rb +78 -0
- data/lib/capsium/package/cipher.rb +197 -0
- data/lib/capsium/package/composition.rb +77 -0
- data/lib/capsium/package/dataset.rb +67 -34
- data/lib/capsium/package/dependency_resolver.rb +61 -0
- data/lib/capsium/package/encryption_config.rb +38 -0
- data/lib/capsium/package/manifest.rb +33 -22
- data/lib/capsium/package/manifest_config.rb +52 -7
- data/lib/capsium/package/merged_view.rb +168 -0
- data/lib/capsium/package/metadata.rb +4 -8
- data/lib/capsium/package/metadata_config.rb +97 -9
- data/lib/capsium/package/preparation.rb +81 -0
- data/lib/capsium/package/routes.rb +39 -41
- data/lib/capsium/package/routes_config.rb +174 -44
- data/lib/capsium/package/security.rb +140 -0
- data/lib/capsium/package/security_config.rb +60 -0
- data/lib/capsium/package/signer.rb +201 -0
- data/lib/capsium/package/storage.rb +20 -45
- data/lib/capsium/package/storage_config.rb +128 -3
- data/lib/capsium/package/store.rb +109 -0
- data/lib/capsium/package/testing/config_test.rb +70 -0
- data/lib/capsium/package/testing/context.rb +11 -0
- data/lib/capsium/package/testing/data_validation_test.rb +63 -0
- data/lib/capsium/package/testing/file_test.rb +45 -0
- data/lib/capsium/package/testing/report.rb +33 -0
- data/lib/capsium/package/testing/route_test.rb +64 -0
- data/lib/capsium/package/testing/test_case.rb +60 -0
- data/lib/capsium/package/testing/test_suite.rb +86 -0
- data/lib/capsium/package/testing.rb +20 -0
- data/lib/capsium/package/validator.rb +160 -0
- data/lib/capsium/package/verification.rb +32 -0
- data/lib/capsium/package/version.rb +204 -0
- data/lib/capsium/package.rb +92 -106
- data/lib/capsium/packager.rb +75 -6
- data/lib/capsium/reactor/authenticator.rb +180 -0
- data/lib/capsium/reactor/deploy.rb +71 -0
- data/lib/capsium/reactor/htpasswd.rb +154 -0
- data/lib/capsium/reactor/introspection.rb +91 -0
- data/lib/capsium/reactor/oauth2.rb +106 -0
- data/lib/capsium/reactor/serving.rb +75 -0
- data/lib/capsium/reactor/session.rb +82 -0
- data/lib/capsium/reactor.rb +93 -43
- data/lib/capsium/thor_ext.rb +1 -1
- data/lib/capsium/version.rb +1 -1
- data/lib/capsium.rb +7 -9
- data/sig/capsium/package/authentication.rbs +23 -0
- data/sig/capsium/package/authentication_config.rbs +71 -0
- data/sig/capsium/package/cipher.rbs +51 -0
- data/sig/capsium/package/composition.rbs +20 -0
- data/sig/capsium/package/dataset.rbs +28 -0
- data/sig/capsium/package/dependency_resolver.rbs +49 -0
- data/sig/capsium/package/encryption_config.rbs +35 -0
- data/sig/capsium/package/manifest.rbs +34 -0
- data/sig/capsium/package/manifest_config.rbs +38 -0
- data/sig/capsium/package/merged_view.rbs +46 -0
- data/sig/capsium/package/metadata.rbs +26 -0
- data/sig/capsium/package/metadata_config.rbs +49 -0
- data/sig/capsium/package/preparation.rbs +23 -0
- data/sig/capsium/package/routes.rbs +37 -0
- data/sig/capsium/package/routes_config.rbs +107 -0
- data/sig/capsium/package/security.rbs +72 -0
- data/sig/capsium/package/security_config.rbs +57 -0
- data/sig/capsium/package/signer.rbs +59 -0
- data/sig/capsium/package/storage.rbs +28 -0
- data/sig/capsium/package/storage_config.rbs +85 -0
- data/sig/capsium/package/store.rbs +37 -0
- data/sig/capsium/package/testing/config_test.rbs +21 -0
- data/sig/capsium/package/testing/context.rbs +14 -0
- data/sig/capsium/package/testing/data_validation_test.rbs +22 -0
- data/sig/capsium/package/testing/file_test.rbs +17 -0
- data/sig/capsium/package/testing/report.rbs +20 -0
- data/sig/capsium/package/testing/route_test.rbs +22 -0
- data/sig/capsium/package/testing/test_case.rbs +41 -0
- data/sig/capsium/package/testing/test_suite.rbs +20 -0
- data/sig/capsium/package/testing.rbs +7 -0
- data/sig/capsium/package/validator.rbs +29 -0
- data/sig/capsium/package/verification.rbs +24 -0
- data/sig/capsium/package/version.rbs +39 -0
- data/sig/capsium/package.rbs +61 -0
- data/sig/capsium/packager.rbs +32 -0
- data/sig/capsium/reactor/authenticator.rbs +40 -0
- data/sig/capsium/reactor/deploy.rbs +34 -0
- data/sig/capsium/reactor/htpasswd.rbs +36 -0
- data/sig/capsium/reactor/introspection.rbs +31 -0
- data/sig/capsium/reactor/oauth2.rbs +31 -0
- data/sig/capsium/reactor/serving.rbs +22 -0
- data/sig/capsium/reactor/session.rbs +36 -0
- data/sig/capsium/reactor.rbs +35 -0
- data/sig/capsium.rbs +3 -1
- metadata +108 -170
- data/lib/capsium/package/dataset_config.rb +0 -28
- data/lib/capsium/protector.rb +0 -103
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Capsium
|
|
2
|
+
class Package
|
|
3
|
+
# Integrity and digital-signature verification of a loaded package
|
|
4
|
+
# (ARCHITECTURE.md section 6), mixed into Package.
|
|
5
|
+
module Verification
|
|
6
|
+
# Verifies the package against security.json. Returns a list of
|
|
7
|
+
# typed errors; empty when no security.json is present or all
|
|
8
|
+
# checksums match.
|
|
9
|
+
def verify_integrity: () -> Array[Security::ChecksumMismatch | Security::MissingFile | Security::UncheckedFile]
|
|
10
|
+
|
|
11
|
+
def verify_integrity!: () -> void
|
|
12
|
+
|
|
13
|
+
# Whether security.json declares a digital signature for this package.
|
|
14
|
+
def signed?: () -> bool
|
|
15
|
+
|
|
16
|
+
# Verifies the declared digital signature (RSA-SHA256) against the
|
|
17
|
+
# checksum-covered payload. True when the package is unsigned or the
|
|
18
|
+
# signature verifies; false on mismatch.
|
|
19
|
+
def verify_signature: () -> bool
|
|
20
|
+
|
|
21
|
+
def verify_signature!: () -> void
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Capsium
|
|
2
|
+
class Package
|
|
3
|
+
# A semantic version (MAJOR.MINOR.PATCH[-prerelease][+build]) with
|
|
4
|
+
# semver precedence ordering.
|
|
5
|
+
class Version
|
|
6
|
+
include Comparable
|
|
7
|
+
|
|
8
|
+
PATTERN: Regexp
|
|
9
|
+
|
|
10
|
+
attr_reader major: Integer
|
|
11
|
+
attr_reader minor: Integer
|
|
12
|
+
attr_reader patch: Integer
|
|
13
|
+
attr_reader prerelease: String?
|
|
14
|
+
|
|
15
|
+
def self.parse: (String string) -> Version
|
|
16
|
+
|
|
17
|
+
def initialize: (Integer major, Integer minor, Integer patch,
|
|
18
|
+
?String? prerelease) -> void
|
|
19
|
+
|
|
20
|
+
def <=>: (Version other) -> Integer
|
|
21
|
+
|
|
22
|
+
def to_s: () -> String
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# A semver range for metadata.dependencies (ARCHITECTURE.md section
|
|
26
|
+
# 4a): "*", exact versions, wildcards/partials, caret, tilde,
|
|
27
|
+
# comparison operators and comma/space conjunctions.
|
|
28
|
+
class VersionRange
|
|
29
|
+
NUMERIC_PART: Regexp
|
|
30
|
+
WILDCARD_PART: Regexp
|
|
31
|
+
|
|
32
|
+
def self.parse: (String string) -> VersionRange
|
|
33
|
+
|
|
34
|
+
def initialize: (Array[[String, Version]] bounds) -> void
|
|
35
|
+
|
|
36
|
+
def satisfied_by?: (String | Version version) -> bool
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module Capsium
|
|
2
|
+
# A Capsium package loaded from a directory or a .cap file
|
|
3
|
+
# (ARCHITECTURE.md section 1).
|
|
4
|
+
class Package
|
|
5
|
+
include Verification
|
|
6
|
+
include Composition
|
|
7
|
+
include Preparation
|
|
8
|
+
|
|
9
|
+
MANIFEST_FILE: String
|
|
10
|
+
METADATA_FILE: String
|
|
11
|
+
STORAGE_FILE: String
|
|
12
|
+
ROUTES_FILE: String
|
|
13
|
+
SECURITY_FILE: String
|
|
14
|
+
SIGNATURE_FILE: String
|
|
15
|
+
AUTHENTICATION_FILE: String
|
|
16
|
+
CONTENT_DIR: String
|
|
17
|
+
DATA_DIR: String
|
|
18
|
+
|
|
19
|
+
attr_reader name: String
|
|
20
|
+
attr_reader path: String
|
|
21
|
+
attr_reader manifest: Manifest
|
|
22
|
+
attr_reader metadata: Metadata
|
|
23
|
+
attr_reader routes: Routes
|
|
24
|
+
attr_reader storage: Storage
|
|
25
|
+
attr_reader security: Security
|
|
26
|
+
attr_reader load_type: Symbol
|
|
27
|
+
attr_reader resolved_dependencies: Array[ResolvedDependency]
|
|
28
|
+
attr_reader authentication: Authentication
|
|
29
|
+
|
|
30
|
+
# Loads a package directory or .cap file. Composite packages
|
|
31
|
+
# (metadata.dependencies, ARCHITECTURE.md section 4a) resolve against
|
|
32
|
+
# the package store given as `store` (directory path or Store) or via
|
|
33
|
+
# CAPSIUM_STORE. `dependency_chain` is internal: the ancestor GUIDs
|
|
34
|
+
# used for circular-dependency detection during recursive resolution.
|
|
35
|
+
def initialize: (String | Pathname path, ?load_type: Symbol? load_type,
|
|
36
|
+
?decryption_key: String? decryption_key,
|
|
37
|
+
?store: (Store | String)? store,
|
|
38
|
+
?dependency_chain: Array[String] dependency_chain) -> void
|
|
39
|
+
|
|
40
|
+
def solidify: () -> void
|
|
41
|
+
|
|
42
|
+
def load_package: () -> void
|
|
43
|
+
|
|
44
|
+
# Removes the temporary extraction directories of the package and its
|
|
45
|
+
# resolved dependencies; a no-op for directory loads.
|
|
46
|
+
def cleanup: () -> void
|
|
47
|
+
|
|
48
|
+
def datasets: () -> Array[Dataset]
|
|
49
|
+
|
|
50
|
+
# The merged content view across the storage layers (ARCHITECTURE.md
|
|
51
|
+
# section 5a); exported_only gives the dependent-package view (section 4a).
|
|
52
|
+
# Resolved dependencies act as read-only layers below all own layers.
|
|
53
|
+
def merged_view: (?exported_only: bool exported_only) -> MergedView
|
|
54
|
+
|
|
55
|
+
# The .cap file this package was loaded from, or nil when loaded
|
|
56
|
+
# from a directory.
|
|
57
|
+
def cap_file_path: () -> String?
|
|
58
|
+
|
|
59
|
+
def content_files: () -> Array[String]
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Capsium
|
|
2
|
+
# Packs a package directory into a .cap file (generating
|
|
3
|
+
# security.json) and unpacks .cap files with zip-slip protection.
|
|
4
|
+
class Packager
|
|
5
|
+
class FileAlreadyExistsError < StandardError
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
# Raised when a .cap archive contains an entry whose name would be
|
|
9
|
+
# written outside the destination directory (zip-slip).
|
|
10
|
+
class UnsafeEntryError < Capsium::Error
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
DRIVE_LETTER_PATTERN: Regexp
|
|
14
|
+
|
|
15
|
+
def pack: (Package package, ?Hash[Symbol, untyped] options) -> String
|
|
16
|
+
|
|
17
|
+
def unpack: (String cap_file_path, String destination) -> void
|
|
18
|
+
|
|
19
|
+
def compress_package: (Package package, String cap_file) -> void
|
|
20
|
+
|
|
21
|
+
# Unpacks a .cap into a temporary directory, yields it for read-only
|
|
22
|
+
# inspection and returns the block's value.
|
|
23
|
+
def with_unpacked_cap: (String cap_path) { (String dir) -> untyped } -> untyped
|
|
24
|
+
|
|
25
|
+
# Unpacks a .cap into a temporary directory, yields it for
|
|
26
|
+
# modification, then recompresses the result back over cap_path.
|
|
27
|
+
# Returns cap_path.
|
|
28
|
+
def transform_cap: (String cap_path) { (String dir) -> untyped } -> String
|
|
29
|
+
|
|
30
|
+
def relative_path_current: (String absolute_path) -> String
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Capsium
|
|
2
|
+
class Reactor
|
|
3
|
+
# Request authentication and route authorization for the reactor
|
|
4
|
+
# (05x-authentication, ARCHITECTURE.md section 4b).
|
|
5
|
+
class Authenticator
|
|
6
|
+
LOGIN_PATH: String
|
|
7
|
+
|
|
8
|
+
attr_reader authentication: Package::Authentication
|
|
9
|
+
attr_reader deploy: Deploy
|
|
10
|
+
|
|
11
|
+
def initialize: (Package::Authentication authentication,
|
|
12
|
+
deploy: Deploy deploy, package_path: String package_path,
|
|
13
|
+
?base_url: String? base_url,
|
|
14
|
+
?state_file: String? state_file) -> void
|
|
15
|
+
|
|
16
|
+
def enabled?: () -> bool
|
|
17
|
+
|
|
18
|
+
# The paths this authenticator answers itself (OAuth2 login and
|
|
19
|
+
# callback), mounted by the reactor.
|
|
20
|
+
def endpoints: () -> Array[String]
|
|
21
|
+
|
|
22
|
+
def endpoint?: (String path) -> bool
|
|
23
|
+
|
|
24
|
+
def serve_endpoint: (untyped request, untyped response) -> untyped
|
|
25
|
+
|
|
26
|
+
# The identity for a request — from the session cookie or Basic
|
|
27
|
+
# credentials — or nil. An identity always carries "roles"
|
|
28
|
+
# (possibly empty).
|
|
29
|
+
def authenticate: (untyped request) -> Hash[String, untyped]?
|
|
30
|
+
|
|
31
|
+
# 401, with a Basic challenge when basicAuth is enabled.
|
|
32
|
+
def challenge: (untyped response) -> untyped
|
|
33
|
+
|
|
34
|
+
# :ok, :unauthenticated or :forbidden for a route's accessControl
|
|
35
|
+
# ({"roles": [...], "authenticationRequired": bool}).
|
|
36
|
+
def authorize: (Hash[String, untyped]? identity,
|
|
37
|
+
Hash[String, untyped]? access_control) -> (:ok | :unauthenticated | :forbidden)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Capsium
|
|
2
|
+
class Reactor
|
|
3
|
+
# Reactor-side deployment configuration (deploy.json): everything
|
|
4
|
+
# that must NOT ship in the package — OAuth2 client secrets, the
|
|
5
|
+
# session signing secret, role assignments, an alternate htpasswd
|
|
6
|
+
# file, the public base URL.
|
|
7
|
+
class Deploy
|
|
8
|
+
FILE: String
|
|
9
|
+
ENV_VAR: String
|
|
10
|
+
|
|
11
|
+
attr_reader config: Hash[String, untyped]
|
|
12
|
+
|
|
13
|
+
# Loads from an explicit path, an already-parsed Hash, or the
|
|
14
|
+
# CAPSIUM_DEPLOY environment variable; empty when unconfigured.
|
|
15
|
+
def self.load: (Hash[String, untyped] | String? source) -> Deploy
|
|
16
|
+
|
|
17
|
+
def initialize: (Hash[String, untyped] config) -> void
|
|
18
|
+
|
|
19
|
+
def authentication: () -> Hash[String, untyped]
|
|
20
|
+
|
|
21
|
+
def base_url: () -> String?
|
|
22
|
+
|
|
23
|
+
def client_secret: () -> String?
|
|
24
|
+
|
|
25
|
+
def session_secret: () -> String?
|
|
26
|
+
|
|
27
|
+
def passwd_file: () -> String?
|
|
28
|
+
|
|
29
|
+
# Role assignments keyed by identity name (basic-auth username,
|
|
30
|
+
# OAuth2 email or subject): {"alice": ["admin", "user"]}.
|
|
31
|
+
def roles: () -> Hash[String, Array[String]]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Capsium
|
|
2
|
+
class Reactor
|
|
3
|
+
# Apache htpasswd verification (05x-authentication). Supported hash
|
|
4
|
+
# formats: bcrypt ($2a$/$2b$/$2y$), Apache apr1 MD5 and md5-crypt
|
|
5
|
+
# ($apr1$/$1$), unsalted SHA-1 ({SHA}), and a crypt(3) fallback for
|
|
6
|
+
# the rest (platform-dependent).
|
|
7
|
+
class Htpasswd
|
|
8
|
+
# md5-crypt as deployed by Apache htpasswd, OpenSSL and glibc.
|
|
9
|
+
module Md5Crypt
|
|
10
|
+
ITOA64: String
|
|
11
|
+
DIGEST_GROUPS: Array[Array[Integer]]
|
|
12
|
+
|
|
13
|
+
def self.verify: (String hash, String password) -> bool
|
|
14
|
+
|
|
15
|
+
def self.digest: (String password, String salt, String magic) -> String
|
|
16
|
+
|
|
17
|
+
def self.initial_digest: (String password, String salt, String magic) -> String
|
|
18
|
+
|
|
19
|
+
def self.stretch_digest: (Integer iteration, String password, String salt, String final) -> String
|
|
20
|
+
|
|
21
|
+
def self.to64: (String final) -> String
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
attr_reader path: String
|
|
25
|
+
|
|
26
|
+
def initialize: (String path) -> void
|
|
27
|
+
|
|
28
|
+
def usernames: () -> Array[String]
|
|
29
|
+
|
|
30
|
+
def verify?: (String username, String password) -> bool
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Constant-time string comparison (length-check first).
|
|
34
|
+
def self.secure_compare: (String own, String theirs) -> bool
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Capsium
|
|
2
|
+
class Reactor
|
|
3
|
+
# Monitoring HTTP API reports for the package this reactor serves
|
|
4
|
+
# (ARCHITECTURE.md section 7).
|
|
5
|
+
class Introspection
|
|
6
|
+
METADATA_PATH: String
|
|
7
|
+
ROUTES_PATH: String
|
|
8
|
+
CONTENT_HASHES_PATH: String
|
|
9
|
+
CONTENT_VALIDITY_PATH: String
|
|
10
|
+
PATHS: Array[String]
|
|
11
|
+
|
|
12
|
+
attr_reader package: Package
|
|
13
|
+
|
|
14
|
+
def initialize: (Package package) -> void
|
|
15
|
+
|
|
16
|
+
def endpoint?: (String path) -> bool
|
|
17
|
+
|
|
18
|
+
# The report body for an introspection endpoint, or nil when the
|
|
19
|
+
# path is not an introspection endpoint.
|
|
20
|
+
def report_for: (String path) -> Hash[Symbol, untyped]?
|
|
21
|
+
|
|
22
|
+
def metadata_report: () -> Hash[Symbol, untyped]
|
|
23
|
+
|
|
24
|
+
def routes_report: () -> Hash[Symbol, untyped]
|
|
25
|
+
|
|
26
|
+
def content_hashes_report: () -> Hash[Symbol, untyped]
|
|
27
|
+
|
|
28
|
+
def content_validity_report: () -> Hash[Symbol, untyped]
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Capsium
|
|
2
|
+
class Reactor
|
|
3
|
+
# OAuth2 authorization-code flow client (05x-authentication), used by
|
|
4
|
+
# the Authenticator. Talks to the provider over net/http; the client
|
|
5
|
+
# secret never comes from the package.
|
|
6
|
+
class OAuth2
|
|
7
|
+
# The token exchange or userinfo fetch failed at the provider.
|
|
8
|
+
class FlowError < Capsium::Error
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
GRANT_TYPE: String
|
|
12
|
+
|
|
13
|
+
attr_reader config: Package::OAuth2Config
|
|
14
|
+
|
|
15
|
+
def initialize: (Package::OAuth2Config config, client_secret: String client_secret,
|
|
16
|
+
session: Session session, ?base_url: String? base_url) -> void
|
|
17
|
+
|
|
18
|
+
# The provider URL the login endpoint redirects the browser to.
|
|
19
|
+
def authorization_url: (untyped request) -> String
|
|
20
|
+
|
|
21
|
+
def valid_state?: (String? state) -> bool
|
|
22
|
+
|
|
23
|
+
# Exchanges the authorization code and fetches the userinfo
|
|
24
|
+
# claims. Returns the raw userinfo hash; raises FlowError on
|
|
25
|
+
# provider errors.
|
|
26
|
+
def complete: (String? code, untyped request) -> Hash[String, untyped]
|
|
27
|
+
|
|
28
|
+
def callback_uri: (untyped request) -> String
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Capsium
|
|
2
|
+
class Reactor
|
|
3
|
+
# Serving of resolved routes (static files through the merged view,
|
|
4
|
+
# datasets, handler-route 501s), mixed into Reactor. Includes route
|
|
5
|
+
# inheritance processing per 05x-routing.
|
|
6
|
+
module Serving
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def serve_route: (Package::Route route, untyped response) -> untyped
|
|
10
|
+
|
|
11
|
+
def serve_file: (Package::Route route, untyped response) -> untyped
|
|
12
|
+
|
|
13
|
+
def inherited_processing: (Package::Route route, String body, Hash[String, String] headers) -> [String, Hash[String, String]]
|
|
14
|
+
|
|
15
|
+
def content_type_for: (Package::Route route, String content_path) -> String
|
|
16
|
+
|
|
17
|
+
def headers_for: (Package::Route route) -> Hash[String, String]
|
|
18
|
+
|
|
19
|
+
def serve_dataset: (String dataset_name, untyped response) -> untyped
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Capsium
|
|
2
|
+
class Reactor
|
|
3
|
+
# HMAC-SHA256 signed session cookies (05x-authentication). The
|
|
4
|
+
# signing secret comes from deploy.json (sessionSecret) or is
|
|
5
|
+
# generated and persisted reactor-side (never in the package).
|
|
6
|
+
class Session
|
|
7
|
+
COOKIE_NAME: String
|
|
8
|
+
SECRET_BYTES: Integer
|
|
9
|
+
|
|
10
|
+
def self.hmac: (String secret, String data) -> String
|
|
11
|
+
|
|
12
|
+
# The persisted reactor-side secret: loaded from state_file when
|
|
13
|
+
# present, generated and written (mode 0600) otherwise.
|
|
14
|
+
def self.load_or_generate_secret: (String? state_file) -> String
|
|
15
|
+
|
|
16
|
+
attr_reader secret: String
|
|
17
|
+
|
|
18
|
+
def initialize: (?secret: String? secret, ?state_file: String? state_file) -> void
|
|
19
|
+
|
|
20
|
+
# HMAC-SHA256 of data with the session secret (hex).
|
|
21
|
+
def sign: (String data) -> String
|
|
22
|
+
|
|
23
|
+
def encode: (Hash[String, untyped] payload) -> String
|
|
24
|
+
|
|
25
|
+
# The verified payload, or nil when the cookie is missing or the
|
|
26
|
+
# signature does not match.
|
|
27
|
+
def decode: (String? cookie_value) -> Hash[String, untyped]?
|
|
28
|
+
|
|
29
|
+
# The identity for a request's Cookie header, or nil.
|
|
30
|
+
def identity_from: (untyped request) -> Hash[String, untyped]?
|
|
31
|
+
|
|
32
|
+
# A Set-Cookie value establishing the identity session.
|
|
33
|
+
def cookie_for: (Hash[String, untyped] identity) -> String
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Capsium
|
|
2
|
+
# Rack-free WEBrick reactor: serves the package routes plus the
|
|
3
|
+
# Monitoring HTTP API (ARCHITECTURE.md section 7) and reloads the
|
|
4
|
+
# package on filesystem changes.
|
|
5
|
+
class Reactor
|
|
6
|
+
include Serving
|
|
7
|
+
|
|
8
|
+
DEFAULT_PORT: Integer
|
|
9
|
+
DEFAULT_CACHE_CONTROL: String
|
|
10
|
+
|
|
11
|
+
attr_reader package: Package
|
|
12
|
+
attr_reader package_path: String
|
|
13
|
+
attr_reader routes: Package::Routes
|
|
14
|
+
attr_reader port: Integer
|
|
15
|
+
attr_reader cache_control: String?
|
|
16
|
+
attr_reader server: untyped
|
|
17
|
+
attr_reader server_thread: Thread?
|
|
18
|
+
attr_reader introspection: Introspection
|
|
19
|
+
attr_reader authenticator: Authenticator
|
|
20
|
+
|
|
21
|
+
def initialize: (package: Package | String package, ?port: Integer port,
|
|
22
|
+
?cache_control: String? cache_control,
|
|
23
|
+
?do_not_listen: bool do_not_listen,
|
|
24
|
+
?store: (Package::Store | String)? store,
|
|
25
|
+
?deploy: (Hash[String, untyped] | String)? deploy) -> void
|
|
26
|
+
|
|
27
|
+
def serve: () -> untyped
|
|
28
|
+
|
|
29
|
+
def handle_request: (untyped request, untyped response) -> untyped
|
|
30
|
+
|
|
31
|
+
def mount_routes: () -> void
|
|
32
|
+
|
|
33
|
+
def restart_server: () -> Thread
|
|
34
|
+
end
|
|
35
|
+
end
|