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 +7 -0
- data/LICENSE +21 -0
- data/README.md +104 -0
- data/ext/disarm/Cargo.toml +36 -0
- data/ext/disarm/extconf.rb +7 -0
- data/ext/disarm/src/lib.rs +959 -0
- data/lib/disarm/version.rb +6 -0
- data/lib/disarm.rb +618 -0
- metadata +144 -0
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"
|