unisec 0.0.3 → 0.0.5

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: d93010e590d0ae588dfb31364036652eb19d5ab17b504fbb851495a2ca71d18d
4
- data.tar.gz: b76c392938f2c804626b81efa227aaf44a65abec7ac63558144644e851b8d475
3
+ metadata.gz: 0b6f74de3dc3d0f9aebac59ff68bc5731b7185e9e73e86e87477c23408900452
4
+ data.tar.gz: 910be7b95b71022f352cc6d612c7752fe2ea13a0e6e3dc89aca4566cb1879569
5
5
  SHA512:
6
- metadata.gz: bde0eb13806b6e6ac2a12d8889c7ef236bdc923e334d59409257a95101d48702aefe10cf83b6a3a2c5bd5d12ebe0170f52cfcaff2cc9c2177db8c455f9a5c6b1
7
- data.tar.gz: 3f3d376b4549b846fee8af810ed134aca724eb377853b64bbe3f75562a33f4b799f7808554ad73211a4158a93feb989e4fc7ecc511babf233f7a6ebf358a17fb
6
+ metadata.gz: 47b730a884a30979be5968d90a30bc214ec93725383f20c48a02ec1090ce64e6043f95427c7ed79ebc31b3b4e1d3b66e01c7b0d63f936793f6c8eb008ce5f9fe
7
+ data.tar.gz: be9ca5cc40baaf9cd56141a3a8e41f5709c6071d5e7797ebd64a1daf231671e6835c168bce53f540e72ead4f68fc93bfd2d211764ba474e1cd8a4ca1bf5e7a65
@@ -0,0 +1,171 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'unisec/utils'
4
+ require 'ctf_party'
5
+
6
+ module Unisec
7
+ # Manipulation of bidirectional related content
8
+ class Bidi
9
+ # Attack using BiDi code points like RtLO, for example, for spoofing a domain name or a file name
10
+ class Spoof
11
+ # The target string to spoof (eg. URL, domain or file name)
12
+ # @return [String] the target string
13
+ attr_reader :target_display
14
+
15
+ # Set a new target string to spoof
16
+ #
17
+ # It will automatically set `@spoof_string` and `@spoof_payload` as well.
18
+ # @param input [String] the target string
19
+ # @param opts [Hash] optional parameters, see {Spoof.bidi_affix}
20
+ # @return [String] the target string
21
+ def set_target_display(input, **opts)
22
+ @target_display = input
23
+ @spoof_string = reverse(**opts)
24
+ @spoof_payload = bidi_affix(**opts)
25
+ @target_display
26
+ end
27
+
28
+ # The string for the spoofing attack without the BiDi characters
29
+ # @return [String] the spoof string (without BiDi)
30
+ attr_reader :spoof_string
31
+
32
+ # The string for the spoofing attack with the BiDi characters. (Spoof payload = spoof string + BiDi)
33
+ # @return [String] the spoof string (with BiDi)
34
+ attr_reader :spoof_payload
35
+
36
+ # @param input [String] the target string
37
+ # @param opts [Hash] optional parameters, see {Spoof.bidi_affix}
38
+ # @example
39
+ # bd = Unisec::Bidi::Spoof.new('https://moc.example.org//:sptth')
40
+ # bd.target_display # => "https://moc.example.org//:sptth"
41
+ # bd.spoof_string # => "https://gro.elpmaxe.com//:sptth"
42
+ # bd.spoof_payload => "‮https://gro.elpmaxe.com//:sptth‬"
43
+ def initialize(input, **opts)
44
+ opts[:index] ||= opts[:infix_pos]
45
+
46
+ @target_display = input
47
+ @spoof_string = reverse(**opts)
48
+ @spoof_payload = bidi_affix(**opts)
49
+ end
50
+
51
+ # Reverse the (sub)-string (grapheme cluster aware)
52
+ # @param target [String] string to reverse
53
+ # @param opts [Hash] optional parameters
54
+ # @option opts [String] :index Index at which the revese starts (before this position will be left untouched)
55
+ # @return [String] the reversed string
56
+ # @example
57
+ # Unisec::Bidi::Spoof.reverse('document_anntxt.exe', index: 12)
58
+ # # => "document_annexe.txt"
59
+ #
60
+ # Unisec::Bidi::Spoof.reverse("🇫🇷🐓")
61
+ # # => "🐓🇫🇷"
62
+ def self.reverse(target, **opts)
63
+ opts[:index] ||= 0
64
+
65
+ target[0...opts[:index]] + Unisec::Utils::String.grapheme_reverse(target[opts[:index]..])
66
+ end
67
+
68
+ # Call {Spoof.reverse} with `@target_display` as default input (target).
69
+ def reverse(**opts)
70
+ Spoof.reverse(@target_display, **opts)
71
+ end
72
+
73
+ # Inject BiDi characters into the input string
74
+ # @param input [String] input string
75
+ # @param opts [Hash] optional parameters
76
+ # @option opts [String] :prefix Prefix Bidi. Default: RLO (U+202E).
77
+ # @option opts [String] :suffix Suffix Bidi. Default: PDF (U+202C).
78
+ # @option opts [String] :infix_bidi Bidi injected at a chosen position. Default: none (empty string).
79
+ # @option opts [String] :infix_pos Position (index) where to inject an extra BiDi. Default: 0.
80
+ # @return [String] spoof payload (input string with injected BiDi)
81
+ # @example
82
+ # # By default inject a RLO prefix, a PDF suffix and no infix.
83
+ # Unisec::Bidi::Spoof.bidi_affix('acceis')
84
+ # # => "‮acceis‬"
85
+ #
86
+ # # RLI ... PDI
87
+ # Unisec::Bidi::Spoof.bidi_affix('acceis', prefix: "\u{2067}", suffix: "\u{2069}")
88
+ # # => "⁧acceis⁩"
89
+ #
90
+ # # RLE ... PDF
91
+ # Unisec::Bidi::Spoof.bidi_affix('acceis', prefix: "\u{202B}", suffix: "\u{202C}")
92
+ # # => "‫acceis‬"
93
+ #
94
+ # # RLO ... PDF
95
+ # Unisec::Bidi::Spoof.bidi_affix('https://moc.example.org//:sptth', prefix: "\u{202E}", suffix: "\u{202C}")
96
+ # # => "‮https://moc.example.org//:sptth‬"
97
+ #
98
+ # # FSI RLO ... PDF PDI
99
+ # Unisec::Bidi::Spoof.bidi_affix('https://moc.example.org//:sptth', prefix: "\u{2068 202E}", suffix: "\u{202C 2069}")
100
+ # # => "⁨‮https://moc.example.org//:sptth‬⁩"
101
+ #
102
+ # # RLM ...
103
+ # Unisec::Bidi::Spoof.bidi_affix('unicode', prefix: "\u{200F}", suffix: '')
104
+ # # => "‏unicode"
105
+ #
106
+ # # For file name spoofing, it is useful to be able to inject just a RLO before the fake extension
107
+ # # so we can void the prefix and suffix and just set the position of an infix
108
+ # ex = Unisec::Bidi::Spoof.bidi_affix('document_anntxt.exe', prefix: '', suffix: '', infix_bidi: "\u{202E}", infix_pos: 12)
109
+ # # => "document_ann‮txt.exe"
110
+ # puts ex
111
+ # # document_ann‮txt.exe
112
+ def self.bidi_affix(input, **opts)
113
+ opts[:prefix] ||= "\u{202E}" # RLO
114
+ opts[:suffix] ||= "\u{202C}" # PDF
115
+ opts[:infix_bidi] ||= ''
116
+ opts[:infix_pos] ||= 0
117
+
118
+ out = "#{opts[:prefix]}#{input}#{opts[:suffix]}"
119
+ out.insert(opts[:infix_pos], opts[:infix_bidi])
120
+ out
121
+ end
122
+
123
+ # Call {Spoof.bidi_affix} with `@spoof_string` as input.
124
+ def bidi_affix(**opts)
125
+ Spoof.bidi_affix(@spoof_string, **opts)
126
+ end
127
+
128
+ # Display a CLI-friendly output summurizing the spoof payload
129
+ #
130
+ # The light version displays only the spoof payload for easy piping with other commands.
131
+ # @param light [Boolean] `true` = light display (displays only the spoof payload for easy piping with other commands), `false` (default) = full display.
132
+ # @return [String] CLI-ready output
133
+ # @example
134
+ # puts Unisec::Bidi::Spoof.new('noraj').display
135
+ # # Target string: noraj
136
+ # # Spoof payload (display) ⚠: ‮jaron‬
137
+ # # Spoof string 🛈: jaron
138
+ # # Spoof payload (hex): e280ae6a61726f6ee280ac
139
+ # # Spoof payload (hex, escaped): \xe2\x80\xae\x6a\x61\x72\x6f\x6e\xe2\x80\xac
140
+ # # Spoof payload (base64): 4oCuamFyb27igKw=
141
+ # # Spoof payload (urlencode): %E2%80%AEjaron%E2%80%AC
142
+ # # Spoof payload (code points): U+202E U+006A U+0061 U+0072 U+006F U+006E U+202C
143
+ # #
144
+ # #
145
+ # #
146
+ # # ⚠: for the spoof payload to display correctly, be sure your VTE has RTL support, e.g. see https://wiki.archlinux.org/title/Bidirectional_text#Terminal.
147
+ # # 🛈: Does not contain the BiDi character (e.g. RtLO).
148
+ #
149
+ # puts Unisec::Bidi::Spoof.new('noraj').display(light: true)
150
+ # # ‮jaron‬
151
+ def display(light: false)
152
+ if light == false # full display
153
+ "Target string: #{@target_display}\n" \
154
+ "Spoof payload (display) ⚠: #{@spoof_payload}\n" \
155
+ "Spoof string 🛈: #{@spoof_string}\n" \
156
+ "Spoof payload (hex): #{@spoof_payload.to_hex}\n" \
157
+ "Spoof payload (hex, escaped): #{@spoof_payload.to_hex(prefixall: '\\x')}\n" \
158
+ "Spoof payload (base64): #{@spoof_payload.to_b64}\n" \
159
+ "Spoof payload (urlencode): #{@spoof_payload.urlencode}\n" \
160
+ "Spoof payload (code points): #{Unisec::Properties.chars2codepoints(@spoof_payload)}\n" \
161
+ "\n\n\n" \
162
+ '⚠: for the spoof payload to display correctly, be sure your VTE has RTL support, ' \
163
+ "e.g. see https://wiki.archlinux.org/title/Bidirectional_text#Terminal.\n" \
164
+ '🛈: Does not contain the BiDi character (e.g. RtLO).'
165
+ else # light display
166
+ @spoof_payload
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/cli'
4
+ require 'unisec'
5
+ require 'unisec/utils'
6
+
7
+ module Unisec
8
+ module CLI
9
+ module Commands
10
+ # CLI sub-commands `unisec bidi xxx` for the class {Unisec::Bidi} from the lib.
11
+ module Bidi
12
+ # Command `unisec bidi spoof`
13
+ #
14
+ # Example:
15
+ #
16
+ # ```plaintext
17
+ # $ unisec bidi spoof noraj
18
+ # Target string: noraj
19
+ # Spoof payload (display) ⚠: ‮jaron‬
20
+ # Spoof string 🛈: jaron
21
+ # Spoof payload (hex): e280ae6a61726f6ee280ac
22
+ # Spoof payload (hex, escaped): \xe2\x80\xae\x6a\x61\x72\x6f\x6e\xe2\x80\xac
23
+ # Spoof payload (base64): 4oCuamFyb27igKw=
24
+ # Spoof payload (urlencode): %E2%80%AEjaron%E2%80%AC
25
+ # Spoof payload (code points): U+202E U+006A U+0061 U+0072 U+006F U+006E U+202C
26
+ #
27
+ #
28
+ #
29
+ # ⚠: for the spoof payload to display correctly, be sure your VTE has RTL support, e.g. see https://wiki.archlinux.org/title/Bidirectional_text#Terminal.
30
+ # 🛈: Does not contain the BiDi character (e.g. RtLO).
31
+ #
32
+ # $ unisec bidi spoof 'document_annexe.txt' --prefix '' --suffix '' --infix-bidi $'\U202E' --infix-pos 12 --light=true
33
+ # document_ann‮txt.exe
34
+ # ```
35
+ class Spoof < Dry::CLI::Command
36
+ desc 'Craft a payload for BiDi attacks (for example, for spoofing a domain name or a file name)'
37
+
38
+ argument :input, required: true,
39
+ desc: 'String input'
40
+ option :light, default: false, values: %w[true false],
41
+ desc: 'true = light display (displays only the spoof payload for easy piping with other ' \
42
+ 'commands), false = full display'
43
+ option :prefix, default: nil, desc: 'Prefix Bidi. Default: RLO (U+202E).'
44
+ option :suffix, default: nil, desc: 'Suffix Bidi. Default: PDF (U+202C).'
45
+ option :infix_bidi, default: nil, desc: 'Bidi injected at a chosen position. Default: none (empty string).'
46
+ option :infix_pos, default: nil, desc: 'Spoof payload (input string with injected BiDi)'
47
+
48
+ # Craft a payload for BiDi attacks
49
+ # @param input [String] Input string to spoof
50
+ # @param options [Hash] optional parameters, see {Unisec::Bidi::Spoof.bidi_affix}
51
+ def call(input: nil, **options)
52
+ to_bool = ->(str) { ['true', true].include?(str) }
53
+ light = to_bool.call(options.fetch(:light))
54
+ infix_pos = options[:infix_pos].to_i unless options[:infix_pos].nil?
55
+ puts Unisec::Bidi::Spoof.new(input, prefix: options[:prefix], suffix: options[:suffix],
56
+ infix_bidi: options[:infix_bidi],
57
+ infix_pos: infix_pos).display(light: light)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'unisec/cli/bidi'
3
4
  require 'unisec/cli/confusables'
4
5
  require 'unisec/cli/hexdump'
6
+ require 'unisec/cli/normalization'
5
7
  require 'unisec/cli/properties'
6
8
  require 'unisec/cli/rugrep'
7
9
  require 'unisec/cli/size'
@@ -17,10 +19,12 @@ module Unisec
17
19
 
18
20
  # Mapping between the (sub-)commands as seen by the user
19
21
  # on the command-line interface and the CLI modules in the lib
22
+ register 'bidi spoof', Bidi::Spoof
20
23
  register 'confusables list', Confusables::List
21
24
  register 'confusables randomize', Confusables::Randomize
22
25
  register 'grep', Grep
23
26
  register 'hexdump', Hexdump
27
+ register 'normalize', Normalize
24
28
  register 'properties char', Properties::Char
25
29
  register 'properties codepoints', Properties::Codepoints
26
30
  register 'properties list', Properties::List
@@ -17,17 +17,29 @@ module Unisec
17
17
  # UTF-16LE: 4100 4300 4300 4500 4900 5300
18
18
  # UTF-32BE: 00000041 00000043 00000043 00000045 00000049 00000053
19
19
  # UTF-32LE: 41000000 43000000 43000000 45000000 49000000 53000000
20
+ #
21
+ # $unisec hexdump "ACCEIS" --enc utf16le
22
+ # 4100 4300 4300 4500 4900 5300
20
23
  # ```
21
24
  class Hexdump < Dry::CLI::Command
22
25
  desc 'Hexdump in all Unicode encodings'
23
26
 
24
27
  argument :input, required: true,
25
- desc: 'String input'
28
+ desc: 'String input. Read from STDIN if equal to -.'
29
+
30
+ option :enc, default: nil, values: %w[utf8 utf16be utf16le utf32be utf32le],
31
+ desc: 'Output only in the specified encoding.'
26
32
 
27
33
  # Hexdump of all Unicode encodings.
28
34
  # @param input [String] Input string to encode
29
- def call(input: nil, **)
30
- puts Unisec::Hexdump.new(input).display
35
+ def call(input: nil, **options)
36
+ input = $stdin.read.chomp if input == '-'
37
+ if options[:enc].nil?
38
+ puts Unisec::Hexdump.new(input).display
39
+ else
40
+ # using send() is safe here thanks to the value whitelist
41
+ puts Unisec::Hexdump.send(options[:enc], input)
42
+ end
31
43
  end
32
44
  end
33
45
  end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/cli'
4
+ require 'unisec'
5
+ require 'unisec/utils'
6
+
7
+ module Unisec
8
+ module CLI
9
+ module Commands
10
+ # CLI sub-commands `unisec normalize xxx` for the class {Unisec::Normalization} from the lib.
11
+ #
12
+ # Command `unisec normalize "example"`
13
+ #
14
+ # Example:
15
+ #
16
+ # ```plaintext
17
+ # ➜ unisec normalize ẛ̣
18
+ # Original: ẛ̣
19
+ # U+1E9B U+0323
20
+ # NFC: ẛ̣
21
+ # U+1E9B U+0323
22
+ # NFKC: ṩ
23
+ # U+1E69
24
+ # NFD: ẛ̣
25
+ # U+017F U+0323 U+0307
26
+ # NFKD: ṩ
27
+ # U+0073 U+0323 U+0307
28
+ #
29
+ # ➜ unisec normalize ẛ̣ --form nfkd
30
+ # ṩ
31
+ # ```
32
+ class Normalize < Dry::CLI::Command
33
+ desc 'Normalize in all forms'
34
+
35
+ argument :input, required: true,
36
+ desc: 'String input. Read from STDIN if equal to -.'
37
+
38
+ option :form, default: nil, values: %w[nfc nfkc nfd nfkd],
39
+ desc: 'Output only in the specified normalization form.'
40
+
41
+ # Normalize in all forms
42
+ # @param input [String] Input string to normalize
43
+ def call(input: nil, **options)
44
+ input = $stdin.read.chomp if input == '-'
45
+ if options[:form].nil?
46
+ puts Unisec::Normalization.new(input).display
47
+ else
48
+ # using send() is safe here thanks to the value whitelist
49
+ puts Unisec::Normalization.send(options[:form], input)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -86,6 +86,7 @@ module Unisec
86
86
  end
87
87
 
88
88
  # Display a CLI-friendly output summurizing the hexdump in all Unicode encodings
89
+ # @return [String] CLI-ready output
89
90
  # @example
90
91
  # puts Unisec::Hexdump.new('K').display # =>
91
92
  # # UTF-8: e2 84 aa
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ctf_party'
4
+
5
+ module Unisec
6
+ # Normalization Forms
7
+ class Normalization
8
+ # Original input
9
+ # @return [String] untouched input
10
+ attr_reader :original
11
+
12
+ # Normalization Form C (NFC) - Canonical Decomposition, followed by Canonical Composition
13
+ # @return [String] input normalized with NFC
14
+ attr_reader :nfc
15
+
16
+ # Normalization Form KC (NFKC) - Compatibility Decomposition, followed by Canonical Composition
17
+ # @return [String] input normalized with NFKC
18
+ attr_reader :nfkc
19
+
20
+ # Normalization Form D (NFD) - Canonical Decomposition
21
+ # @return [String] input normalized with NFD
22
+ attr_reader :nfd
23
+
24
+ # Normalization Form KD (NFKD) - Compatibility Decomposition
25
+ # @return [String] input normalized with NFKD
26
+ attr_reader :nfkd
27
+
28
+ # Generate all normilzation forms for a given input
29
+ # @param str [String] the target string
30
+ # @return [nil]
31
+ def initialize(str)
32
+ @original = str
33
+ @nfc = Normalization.nfc(str)
34
+ @nfkc = Normalization.nfkc(str)
35
+ @nfd = Normalization.nfd(str)
36
+ @nfkd = Normalization.nfkd(str)
37
+ end
38
+
39
+ # Normalization Form C (NFC) - Canonical Decomposition, followed by Canonical Composition
40
+ # @param str [String] the target string
41
+ # @return [String] input normalized with NFC
42
+ def self.nfc(str)
43
+ str.unicode_normalize(:nfc)
44
+ end
45
+
46
+ # Normalization Form KC (NFKC) - Compatibility Decomposition, followed by Canonical Composition
47
+ # @param str [String] the target string
48
+ # @return [String] input normalized with NFKC
49
+ def self.nfkc(str)
50
+ str.unicode_normalize(:nfkc)
51
+ end
52
+
53
+ # Normalization Form D (NFD) - Canonical Decomposition
54
+ # @param str [String] the target string
55
+ # @return [String] input normalized with NFD
56
+ def self.nfd(str)
57
+ str.unicode_normalize(:nfd)
58
+ end
59
+
60
+ # Normalization Form KD (NFKD) - Compatibility Decomposition
61
+ # @param str [String] the target string
62
+ # @return [String] input normalized with NFKD
63
+ def self.nfkd(str)
64
+ str.unicode_normalize(:nfkd)
65
+ end
66
+
67
+ # Display a CLI-friendly output summurizing all normalization forms
68
+ # @return [String] CLI-ready output
69
+ # @example
70
+ # puts Unisec::Normalization.new("\u{1E9B 0323}").display
71
+ # # =>
72
+ # # Original: ẛ̣
73
+ # # U+1E9B U+0323
74
+ # # NFC: ẛ̣
75
+ # # U+1E9B U+0323
76
+ # # NFKC: ṩ
77
+ # # U+1E69
78
+ # # NFD: ẛ̣
79
+ # # U+017F U+0323 U+0307
80
+ # # NFKD: ṩ
81
+ # # U+0073 U+0323 U+0307
82
+ def display
83
+ colorize = lambda { |form_title, form_attr|
84
+ "#{Paint[form_title.to_s, :underline,
85
+ :bold]}: #{form_attr}\n #{Paint[Unisec::Properties.chars2codepoints(form_attr), :red]}\n"
86
+ }
87
+ colorize.call('Original', @original) +
88
+ colorize.call('NFC', @nfc) +
89
+ colorize.call('NFKC', @nfkc) +
90
+ colorize.call('NFD', @nfd) +
91
+ colorize.call('NFKD', @nfkd)
92
+ end
93
+ end
94
+ end
@@ -102,6 +102,7 @@ module Unisec
102
102
  # Display a CLI-friendly output summurizing everithing about the surrogates:
103
103
  # the corresponding character, code point, high and low surrogates
104
104
  # (each displayed as hexadecimal, decimal and binary).
105
+ # @return [String] CLI-ready output
105
106
  # @example
106
107
  # surr = Unisec::Surrogates.new(128169)
107
108
  # puts surr.display # =>
data/lib/unisec/utils.rb CHANGED
@@ -98,6 +98,16 @@ module Unisec
98
98
  :string
99
99
  end
100
100
  end
101
+
102
+ # Reverse a string by graphemes (not by code points)
103
+ # @return [String] the reversed string
104
+ # @example
105
+ # b = "\u{1f1eb}\u{1f1f7}\u{1F413}" # => "🇫🇷🐓"
106
+ # b.reverse # => "🐓🇷🇫"
107
+ # Unisec::Utils::String.grapheme_reverse(b) # => "🐓🇫🇷"
108
+ def self.grapheme_reverse(str)
109
+ str.grapheme_clusters.reverse.join
110
+ end
101
111
  end
102
112
  end
103
113
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Unisec
4
4
  # Version of unisec library and app
5
- VERSION = '0.0.3'
5
+ VERSION = '0.0.5'
6
6
  end
@@ -72,19 +72,19 @@ module Unisec
72
72
  # # …
73
73
  def self.display # rubocop:disable Metrics/AbcSize
74
74
  data = versions
75
- display = ->(node) { puts Paint[data[node][:label], :red, :bold].ljust(44) + " #{data[node][:version]}" }
76
- puts Paint['Unicode:', :underline]
77
- display.call(:ruby_unicode)
78
- display.call(:twittercldr_unicode)
79
- display.call(:unicodeconfusable_unicode)
80
- display.call(:twittercldr_icu)
81
- display.call(:twittercldr_cldr)
82
- display.call(:ruby_unicode_emoji)
83
- display.call(:ucd_derivedname)
84
- puts Paint["\nGems:", :underline]
85
- display.call(:unisec)
86
- display.call(:twittercldr)
87
- display.call(:unicodeconfusable)
75
+ colorize = ->(node) { Paint[data[node][:label], :red, :bold].ljust(44) + " #{data[node][:version]}\n" }
76
+ Paint["Unicode:\n", :underline] +
77
+ colorize.call(:ruby_unicode) +
78
+ colorize.call(:twittercldr_unicode) +
79
+ colorize.call(:unicodeconfusable_unicode) +
80
+ colorize.call(:twittercldr_icu) +
81
+ colorize.call(:twittercldr_cldr) +
82
+ colorize.call(:ruby_unicode_emoji) +
83
+ colorize.call(:ucd_derivedname) +
84
+ Paint["\nGems:\n", :underline] +
85
+ colorize.call(:unisec) +
86
+ colorize.call(:twittercldr) +
87
+ colorize.call(:unicodeconfusable)
88
88
  end
89
89
  end
90
90
  end
data/lib/unisec.rb CHANGED
@@ -2,8 +2,10 @@
2
2
 
3
3
  require 'unisec/version'
4
4
 
5
+ require 'unisec/bidi'
5
6
  require 'unisec/confusables'
6
7
  require 'unisec/hexdump'
8
+ require 'unisec/normalization'
7
9
  require 'unisec/properties'
8
10
  require 'unisec/rugrep'
9
11
  require 'unisec/size'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unisec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexandre ZANNI
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-18 00:00:00.000000000 Z
11
+ date: 2024-02-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ctf-party
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2.3'
19
+ version: '3.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '2.3'
26
+ version: '3.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: dry-cli
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -88,7 +88,7 @@ dependencies:
88
88
  version: '1.9'
89
89
  description: 'Toolkit for security research manipulating Unicode: confusables, homoglyphs,
90
90
  hexdump, code point, UTF-8, UTF-16, UTF-32, properties, regexp search, size, grapheme,
91
- surrogates, version, ICU, CLDR, UCD'
91
+ surrogates, version, ICU, CLDR, UCD, BiDi, normalization'
92
92
  email: alexandre.zanni@europe.com
93
93
  executables:
94
94
  - unisec
@@ -99,9 +99,12 @@ files:
99
99
  - bin/unisec
100
100
  - data/DerivedName.txt
101
101
  - lib/unisec.rb
102
+ - lib/unisec/bidi.rb
103
+ - lib/unisec/cli/bidi.rb
102
104
  - lib/unisec/cli/cli.rb
103
105
  - lib/unisec/cli/confusables.rb
104
106
  - lib/unisec/cli/hexdump.rb
107
+ - lib/unisec/cli/normalization.rb
105
108
  - lib/unisec/cli/properties.rb
106
109
  - lib/unisec/cli/rugrep.rb
107
110
  - lib/unisec/cli/size.rb
@@ -109,6 +112,7 @@ files:
109
112
  - lib/unisec/cli/versions.rb
110
113
  - lib/unisec/confusables.rb
111
114
  - lib/unisec/hexdump.rb
115
+ - lib/unisec/normalization.rb
112
116
  - lib/unisec/properties.rb
113
117
  - lib/unisec/rugrep.rb
114
118
  - lib/unisec/size.rb
@@ -145,7 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
145
149
  - !ruby/object:Gem::Version
146
150
  version: '0'
147
151
  requirements: []
148
- rubygems_version: 3.4.10
152
+ rubygems_version: 3.5.3
149
153
  signing_key:
150
154
  specification_version: 4
151
155
  summary: Unicode Security Toolkit