disarm 0.14.0-aarch64-linux → 0.15.0-aarch64-linux

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8626868ff11d6125f1768356c699416cbf5013b97bcdb75f02e53cefce7168d7
4
- data.tar.gz: 236bf3cebcfdb91dd2d55a6fb4f2a510488550b37007dd4668df0b767781c523
3
+ metadata.gz: affa6ae8c002469f386f0cc010093af423746f17b2b23f33cb8e5baeef7d460a
4
+ data.tar.gz: 8c04e95811cc9608f473a44c85815c2e37332c5c71d489963a236b83e1a405e4
5
5
  SHA512:
6
- metadata.gz: 3b1068de3adb50799dbb3c9bf408664d69c095c99f558ac6e8153a61d8a36db1088e2cd1613a3123aacef1ee222321f642ba5939991acd6f944dcd6b2979a548
7
- data.tar.gz: ce875b46faa853663866f8357e8d3ad9ca36bd6608f9e839f3b7667a7ac549165e95d818a2eb99611b8605cdc677755a8901ed2205c762be714cb5a8d379a09d
6
+ metadata.gz: 2102a383ea426986f32d6bbc2c1aa52970226e9e7ed135b5d6f0bd34102c060b5076dd12071985e695ccf3638499930ee4d2ad8b414f0fbc5d4871de38d82bbd
7
+ data.tar.gz: 70976043387c5e0d0cf23c5ced76e0bb58af9cae186f03937963ff08f98e225f90443e4077f93d4cb56e7a27d29812ca37bea3bc4a21fb9ac2f97ca2ec849cab
data/README.md CHANGED
@@ -19,9 +19,10 @@ gem "disarm"
19
19
  gem install disarm
20
20
  ```
21
21
 
22
- Requires Ruby >= 3.1. `gem install disarm` pulls a precompiled platform gem
23
- (Linux x86_64/aarch64, macOS x86_64/arm64, Windows) when one is available, and
24
- falls back to compiling from source (needs a Rust toolchain) otherwise.
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.
25
26
 
26
27
  ## Usage
27
28
 
@@ -49,7 +50,7 @@ Disarm.demojize("I ❤️ Ruby") # => "I red heart Ruby
49
50
  Disarm.demojize("👍🏽", strip_modifiers: true)
50
51
 
51
52
  # Security presets
52
- Disarm.strip_obfuscation("Ѕ𝗲𝗰𝗿𝗲𝘁 ​data") # deobfuscated
53
+ Disarm.strip_obfuscation("Ѕ𝗲𝗰𝗿𝗲𝘁 \u200bdata") # deobfuscated
53
54
  Disarm.canonicalize("…") # homoglyph/bidi/zero-width clean
54
55
 
55
56
  # IDN / hostname spoof check (a false result is not a safety guarantee)
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Disarm
4
4
  # Kept in lockstep with the Rust crate / Python package version.
5
- VERSION = "0.14.0"
5
+ VERSION = "0.15.0"
6
6
  end
data/lib/disarm.rb CHANGED
@@ -55,15 +55,22 @@ module Disarm
55
55
 
56
56
  # Fold cross-script confusables toward `target:` (:latin or :cyrillic).
57
57
  #
58
- # `digit_policy:` selects how non-Latin DIGITS fold (#561). `:numeric` (default)
59
- # sends them to the ASCII digit — `०` becomes `0` — which is right for prose, where
60
- # a Devanagari zero really is a zero. `:tr39` uses upstream's targets, which send
61
- # most of them to a Latin letter (`०` `o`; three of the 45 rows fold to `.` or
62
- # to the two characters `rn` instead); that is what an identifier *skeleton*
63
- # wants, since its only job is to make two confusable identifiers collide. The two
64
- # differ on 45 rows and agree everywhere else. Scoped to `target: :latin` the
65
- # override rows are generated from the Latin table and carry TR39's Latin-script
66
- # targets, so with `target: :cyrillic` it is a no-op.
58
+ # `digit_policy:` selects how non-Latin DIGITS fold (#561).
59
+ #
60
+ # `:numeric` (default) sends them to the ASCII digit `०` becomes `0` — which is
61
+ # right for prose, where a Devanagari zero really is a zero.
62
+ #
63
+ # `:tr39` uses upstream's targets, which send most of them to a Latin letter
64
+ # (`०` `o`; three of the 45 rows fold to `.` or to the two characters `rn`
65
+ # instead). That is what an identifier *skeleton* wants, since its only job is to
66
+ # make two confusable identifiers collide. The two differ on 45 rows and agree
67
+ # everywhere else. Scoped to `target: :latin` — the override rows are generated from
68
+ # the Latin table and carry TR39's Latin-script targets, so with `target: :cyrillic`
69
+ # it is a no-op.
70
+ #
71
+ # `:preserve` leaves the digit alone (#648). The other two both yield a mixed-script
72
+ # numeral — `२०२४` becomes `२0२४` or `२o२४` — so neither keeps the script. Unlike
73
+ # `:tr39` it applies under every target script.
67
74
  def normalize_confusables(text, target: :latin, digit_policy: :numeric)
68
75
  translate_errors { _normalize_confusables(text, target.to_s, digit_policy.to_s) }
69
76
  end
@@ -109,6 +116,24 @@ module Disarm
109
116
  translate_errors { _demojize(text, strip_modifiers) }
110
117
  end
111
118
 
119
+ # Canonicalize, but raise rather than silently normalize a structural difference
120
+ # away — the half of the pair that lets a caller reject input instead of comparing
121
+ # a value the sender never wrote.
122
+ def canonicalize_strict(text)
123
+ translate_errors { _canonicalize_strict(text) }
124
+ end
125
+
126
+ # Strip the non-interchange and invisible classes while KEEPING the script.
127
+ #
128
+ # Unlike `canonicalize` it folds no confusables, so non-Latin text survives as
129
+ # itself. It cannot be rebuilt from the seven universal `strip_*` methods, and the
130
+ # difference runs both ways: this preserves the Private Use Area (icon fonts) and
131
+ # keeps the VS15/VS16 presentation selectors after a base, which the naive chain
132
+ # deletes, and it collapses TAB/LF to a space, which the primitives leave alone.
133
+ def strip_format(text)
134
+ _strip_format(text)
135
+ end
136
+
112
137
  # Remove obfuscation (zero-width, bidi, combining-mark abuse) while keeping
113
138
  # legible content.
114
139
  def strip_obfuscation(text)
@@ -119,6 +144,13 @@ module Disarm
119
144
  # control characters, and other spoofing vectors. The name describes the
120
145
  # mechanism (Unicode canonicalization for matching), not a safety guarantee —
121
146
  # this is not an output sanitizer; encode at the sink.
147
+ #
148
+ # Two steps introduce ASCII, not one (#719): the leading NFKC, and the confusable
149
+ # fold, which reaches characters NFKC leaves alone. U+2236 RATIO becomes ":", U+2044
150
+ # FRACTION SLASH becomes "/", U+2216 SET MINUS becomes "\\". A string that carried no
151
+ # delimiter can leave here carrying one. #inspect_anomalies reports it as :confusable
152
+ # WHEN the word also carries an ASCII letter, which is the gate that keeps ordinary
153
+ # non-Latin text from firing; a delimiter-only string is not reported.
122
154
  def canonicalize(text)
123
155
  translate_errors { _canonicalize(text) }
124
156
  end
@@ -208,14 +240,14 @@ module Disarm
208
240
  # confusable test flags essentially every non-Latin host), not a precise verdict;
209
241
  # branch on the granular signals plus your own policy. Keys: :suspicious,
210
242
  # :scripts, :mixed_script, :has_confusables, :bidi_conflict, :bidi_control,
211
- # :has_invisible, :cross_label_script,
243
+ # :has_invisible, :compat_fold, :cross_label_script,
212
244
  # :label_scripts, :whole_script_confusable, :label_whole_script_confusable,
213
245
  # :canonical. `:whole_script_confusable` is a graded signal, NOT folded into
214
246
  # `:suspicious` (see #545).
215
247
  def analyze_hostname(host, contractions: false)
216
248
  suspicious, scripts, mixed_script, has_confusables, bidi_conflict,
217
- bidi_control, has_invisible, cross_label_script, label_scripts,
218
- whole_script_confusable, label_whole_script_confusable, canonical =
249
+ bidi_control, has_invisible, compat_fold, cross_label_script, label_scripts,
250
+ whole_script_confusable, (label_whole_script_confusable, canonical) =
219
251
  translate_errors { _analyze_hostname(host, contractions) }
220
252
  {
221
253
  suspicious:,
@@ -225,6 +257,7 @@ module Disarm
225
257
  bidi_conflict:,
226
258
  bidi_control:,
227
259
  has_invisible:,
260
+ compat_fold:,
228
261
  cross_label_script:,
229
262
  label_scripts:,
230
263
  whole_script_confusable:,
@@ -337,6 +370,12 @@ module Disarm
337
370
  # (default), :windows, or :posix; `preserve_extension:` keeps the final
338
371
  # extension when truncating to `max_length:`. Raises Disarm::InvalidArgument
339
372
  # on an unknown platform.
373
+ #
374
+ # A safe *filename*, not a safe URL path segment. "%" is legal in a filename, so one
375
+ # the caller typed is kept — sanitize_filename("..%2Fetc") returns "%2Fetc" — and a
376
+ # consumer that percent-decodes the result must validate AFTER decoding. What this
377
+ # will not do is manufacture one: "%" never appears in the output unless it appeared
378
+ # in the input (#721).
340
379
  def sanitize_filename(text, separator: "_", max_length: 255, platform: :universal,
341
380
  lang: nil, preserve_extension: true)
342
381
  translate_errors do
@@ -415,6 +454,15 @@ module Disarm
415
454
  translate_errors { _has_bidi_conflict?(text) }
416
455
  end
417
456
 
457
+ # Whether `text` carries any of the twelve UAX #9 explicit formatting characters,
458
+ # with no context taken into account. The counterpart to `bidi_conflict?`, which
459
+ # reads strong-direction letters and is blind to these; the two are disjoint. The
460
+ # anomaly detector's `bidi` kind reports nine of the twelve, holding back LRM, RLM
461
+ # and ALM because a lone directional mark is ordinary in right-to-left text.
462
+ def bidi_control?(text)
463
+ _has_bidi_control?(text)
464
+ end
465
+
418
466
  # Explain how `lang: "auto"` detection resolves `text`: a hash with
419
467
  # `:script`, `:chosen_lang` (both nil if undetected), `:reason`, and
420
468
  # `:discriminators_hit`.
@@ -441,6 +489,20 @@ module Disarm
441
489
  # The Unicode `confusables.txt` release the bundled confusable tables were folded
442
490
  # from, e.g. "17.0.0". Not a Unicode version for the library as a whole — the
443
491
  # case-folding and width tables track different releases (see docs/provenance.md).
492
+ # The UCD release disarm's normalizer implements. Not a library-wide Unicode
493
+ # version — the bundled tables track different releases. This is the one integrators
494
+ # ask about: it decides whether disarm's normalization agrees with Ruby's.
495
+ def unicode_version
496
+ _unicode_version
497
+ end
498
+
499
+ # Whether a key stored under an earlier release still compares equal. A monotonic
500
+ # counter, not a version: two artifacts reporting the same value produce the same key
501
+ # for the same input. Meaningless in isolation, by design.
502
+ def key_schema_version
503
+ _key_schema_version
504
+ end
505
+
444
506
  def confusables_version
445
507
  translate_errors { _confusables_version }
446
508
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: disarm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.0
4
+ version: 0.15.0
5
5
  platform: aarch64-linux
6
6
  authors:
7
7
  - Richard Quinn
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-28 00:00:00.000000000 Z
11
+ date: 2026-09-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -98,6 +98,8 @@ files:
98
98
  - lib/disarm/3.1/disarm.so
99
99
  - lib/disarm/3.2/disarm.so
100
100
  - lib/disarm/3.3/disarm.so
101
+ - lib/disarm/3.4/disarm.so
102
+ - lib/disarm/4.0/disarm.so
101
103
  - lib/disarm/version.rb
102
104
  homepage: https://github.com/raeq/disarm
103
105
  licenses:
@@ -118,7 +120,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
118
120
  version: '3.1'
119
121
  - - "<"
120
122
  - !ruby/object:Gem::Version
121
- version: 3.4.dev
123
+ version: 4.1.dev
122
124
  required_rubygems_version: !ruby/object:Gem::Requirement
123
125
  requirements:
124
126
  - - ">="