disarm 0.15.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d75406993aaa2ac76a20429c567601447bcffa79708398444b83dc8b445ebf01
4
+ data.tar.gz: cfea208f2da86fd373ed82f4e25a9166277ffd1806c22614551418ddb20acb05
5
+ SHA512:
6
+ metadata.gz: 68a46c759f40421b154e1879500edecf0ced53931224e317b1f3dacfb5a03750ebe132bfe7b1efd7f4be21d384f4478bfc104d826e27675c85b61c79723b40a1
7
+ data.tar.gz: 93d71a7e1d5aac2f0a33e26a72e6658ad842a2408b4e744f70ed73bdc1d141b567b2b575ec241c8e738e2c54dc39d4f49309118b353f7985084226d089de7ca3
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Richard Quinn
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # disarm (Ruby)
2
+
3
+ Ruby bindings for [**disarm**](https://github.com/raeq/disarm) — Unicode
4
+ confusable / text-security building blocks (homoglyph & bidi & zalgo handling,
5
+ plus standards-based transliteration), powered by Rust.
6
+
7
+ The native extension wraps the **pure-Rust `disarm` core** (no Python), via
8
+ [magnus](https://github.com/matsadler/magnus) + [rb-sys](https://github.com/oxidize-rb/rb-sys).
9
+ Precompiled platform gems install without a local Rust toolchain.
10
+
11
+ ## Install
12
+
13
+ ```ruby
14
+ # Gemfile
15
+ gem "disarm"
16
+ ```
17
+
18
+ ```sh
19
+ gem install disarm
20
+ ```
21
+
22
+ Requires Ruby >= 3.1. Precompiled platform gems ship for Ruby 3.1 through 4.0
23
+ (Linux x86_64/aarch64, macOS x86_64/arm64, Windows). On a supported Ruby with no
24
+ matching platform gem, the source gem installs and compiles locally, which needs a
25
+ Rust toolchain. Below 3.1 the gem does not install at all.
26
+
27
+ ## Usage
28
+
29
+ ```ruby
30
+ require "disarm"
31
+
32
+ # Standards-based transliteration to ASCII. `scheme:` is a symbol (or string):
33
+ # :default (general-purpose), :strict_iso9 (ISO 9:1995), :gost7034. `lang:`
34
+ # applies a language profile on top (e.g. "uk" → Київ → "Kyiv").
35
+ Disarm.transliterate("Москва") # => "Moskva"
36
+ Disarm.transliterate("Київ", lang: :uk) # => "Kyiv"
37
+ Disarm.transliterate("Москва", scheme: :strict_iso9)
38
+
39
+ # TR39 confusable folding (homoglyph defense). `target:` defaults to :latin.
40
+ Disarm.normalize_confusables("раypal") # => "paypal"
41
+ Disarm.confusable?("pаypal") # => true
42
+ Disarm.normalize_confusables("paypal", target: :cyrillic)
43
+
44
+ # Canonicalization primitives
45
+ Disarm.strip_accents("café") # => "cafe"
46
+ Disarm.fold_case("HELLO") # => "hello"
47
+ Disarm.slugify("Héllo Wörld") # => "hello-world"
48
+ Disarm.slugify("Hello World", separator: "_", max_length: 5, word_boundary: true)
49
+ Disarm.demojize("I ❤️ Ruby") # => "I red heart Ruby"
50
+ Disarm.demojize("👍🏽", strip_modifiers: true)
51
+
52
+ # Security presets
53
+ Disarm.strip_obfuscation("Ѕ𝗲𝗰𝗿𝗲𝘁 \u200bdata") # deobfuscated
54
+ Disarm.canonicalize("…") # homoglyph/bidi/zero-width clean
55
+
56
+ # IDN / hostname spoof check (a false result is not a safety guarantee)
57
+ Disarm.suspicious_hostname?("pаypal.com") # => true (Cyrillic 'а')
58
+ ```
59
+
60
+ Every option past the text is a keyword argument with the core's default, and
61
+ scheme/target tokens accept symbols or strings. `slugify` exposes the core's
62
+ `SlugConfig` surface (`separator:`, `lowercase:`, `max_length:`,
63
+ `word_boundary:`, `save_order:`, `stopwords:`, `allow_unicode:`, `lang:`,
64
+ `entities:`, `decimal:`, `hexadecimal:`, `safe_chars:`).
65
+
66
+ ### Errors
67
+
68
+ Every public method is wrapped so that everything disarm raises descends from
69
+ `Disarm::Error < StandardError` — a single `rescue Disarm::Error` catches all of
70
+ them. An invalid scheme/target, a non-String argument, or any other bad input
71
+ raises the more specific `Disarm::InvalidArgument`; the original backtrace is
72
+ preserved so the failing call site stays visible.
73
+
74
+ ```ruby
75
+ begin
76
+ Disarm.transliterate("x", scheme: :klingon)
77
+ rescue Disarm::InvalidArgument => e # also rescuable as Disarm::Error
78
+ warn e.message
79
+ end
80
+ ```
81
+
82
+ ## Security posture
83
+
84
+ This binding inherits the core's guarantees and limitations verbatim — it adds
85
+ no logic of its own. disarm is an **input-normalization** layer, not an output
86
+ sanitizer; read the [Threat Model](https://github.com/raeq/disarm/blob/main/THREAT_MODEL.md)
87
+ before relying on it in a security context.
88
+
89
+ ## Development
90
+
91
+ ```sh
92
+ cd bindings/ruby
93
+ bundle install
94
+ bundle exec rake compile # builds the native ext for the host platform
95
+ bundle exec rake spec # runs the RSpec suite against it
96
+ ```
97
+
98
+ `bundle exec rake compile` requires a Rust toolchain (the core is a path
99
+ dependency until disarm 0.10 is published to crates.io). Cross-platform release
100
+ gems are built in CI with `rb-sys-dock`.
101
+
102
+ ## License
103
+
104
+ MIT — same as the disarm core.
@@ -0,0 +1,36 @@
1
+ # Ruby (magnus) native extension for the disarm Unicode text-security core (#45).
2
+ #
3
+ # This is a *binding crate*, not published to crates.io — it is compiled into the
4
+ # `disarm` RubyGem by rake-compiler/rb-sys. It wraps the pure-Rust `disarm` core
5
+ # (no pyo3) and exposes an idiomatic `Disarm` Ruby module. It is a member of the
6
+ # gem-root workspace (../../Cargo.toml) so rb-sys's `cargo metadata` resolves here
7
+ # rather than walking up to the repo-root core crate.
8
+ #
9
+ # Named `disarm` (matching the gem / lib / loader) but pinned to version 0.0.0,
10
+ # distinct from the `disarm` core (0.10) it depends on — two same-named crates of
11
+ # different versions coexist in the lockfile; same name + same version would not.
12
+ [package]
13
+ name = "disarm"
14
+ version = "0.0.0"
15
+ edition = "2021"
16
+ rust-version = "1.81"
17
+ license = "MIT"
18
+ description = "Ruby bindings for disarm — Unicode confusable/text-security building blocks"
19
+ publish = false
20
+
21
+ [lib]
22
+ # Output the `disarm` shared object the gem's `require "disarm/disarm"` loads.
23
+ # The core is imported under the alias `disarm_core` (see [dependencies]) so the
24
+ # `disarm_core::` paths in src never clash with this crate's own `disarm` name.
25
+ name = "disarm"
26
+ crate-type = ["cdylib"]
27
+
28
+ [dependencies]
29
+ # The pure-Rust core from crates.io (default features = pyo3-free). A registry
30
+ # dep — not a path — so the gem is self-contained and the rb-sys-dock cross-gem
31
+ # build (which mounts only this gem dir) can fetch it. Imported as `disarm_core`
32
+ # because the package name `disarm` would otherwise clash with this crate.
33
+ disarm_core = { package = "disarm", version = "0.15", default-features = false }
34
+ # magnus: ergonomic, safe Ruby<->Rust bindings over rb-sys. 0.8 supports Ruby >= 3.0
35
+ # (the gem's required_ruby_version); rb-sys handles the platform glue.
36
+ magnus = "0.8"
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rb-sys builds the Cargo cdylib in `ext/disarm/` into the loadable extension.
4
+ require "mkmf"
5
+ require "rb_sys/mkmf"
6
+
7
+ create_rust_makefile("disarm/disarm")