miteru 2.1.1 → 2.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 509957b241020f76fcd9c85a6acbb9e80c0f8b3224fe5c1b4af41dcd2faa6ca5
4
- data.tar.gz: 4e507a9974264a9b98d1ded16c09496a06ed4ca83409f75fc49719c37f934f77
3
+ metadata.gz: 3767b21d7f569a43215e2fdc0f83f9fc4f29fe2a4bb11fc3548a5d1657812774
4
+ data.tar.gz: 7877fb357548c619210ec63f3bd26c61c3fda68dc6d21910aa22fc0d7144ebf1
5
5
  SHA512:
6
- metadata.gz: 3dc8e2b4569555f5551a1b7fd2407162949cc7a459a5a7f83c5a787206b5cf39b34f16235466b6bcd74f34bac1878e1e4df6797daebe407eda2c03a9e7379e3a
7
- data.tar.gz: 69d83a4c964ebbcd87b416675ed03bc18e270c0d604a19ef98b8988a0f344388eb49d0fb290edaa2f8637fa5f100608a3e9a76a1571503bda529611aea332bc0
6
+ metadata.gz: '02480c9a5604e5c7959ae4adb9e3a657d4b59f5c668be51b7d1fe120bd46e5548ecc9a26404d88d001729bf19f4f3d1b1545be80820c0717c0e027b7995030cd'
7
+ data.tar.gz: f2c1adc686393f3979ccf77e87c1bc5dba9cad9023903620ab61bbf6e6a2a4406dbbdd3ffb9ca73f5297c2135436dfd995f9572085fd9fde02fb5b72eac6032b
@@ -0,0 +1,45 @@
1
+ require "redis"
2
+
3
+ module Miteru
4
+ class Cache < Service
5
+ # @return [String]
6
+ attr_reader :url
7
+
8
+ #
9
+ # @param [String] url
10
+ #
11
+ def initialize(url)
12
+ super()
13
+ @url = url
14
+ end
15
+
16
+ #
17
+ # @param [String] key
18
+ # @param [String] value
19
+ # @param [Integer. nil] ex
20
+ #
21
+ def set(key, value, ex:)
22
+ value = redis.set("#{cache_prefix}:#{key}", value, ex:)
23
+ logger.info("Cache:#{key} is set.") if verbose?
24
+ value
25
+ end
26
+
27
+ #
28
+ # @param [String] key
29
+ #
30
+ def cached?(key)
31
+ value = redis.exists?("#{cache_prefix}:#{key}")
32
+ logger.info("Cache:#{key} found.") if verbose?
33
+ value
34
+ end
35
+
36
+ private
37
+
38
+ #
39
+ # @return [Redis]
40
+ #
41
+ def redis
42
+ @redis ||= Redis.new(url:)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Miteru
4
+ module Concerns
5
+ module UrlTruncatable
6
+ extend ActiveSupport::Concern
7
+
8
+ def decoded_url
9
+ @decoded_url ||= URI.decode_www_form_component(url)
10
+ end
11
+
12
+ #
13
+ # @return [String]
14
+ #
15
+ def truncated_url
16
+ @truncated_url ||= decoded_url.truncate(64)
17
+ end
18
+
19
+ def defanged_truncated_url
20
+ @defanged_truncated_url ||= truncated_url.to_s.gsub(".", "[.]")
21
+ end
22
+ end
23
+ end
24
+ end
data/lib/miteru/config.rb CHANGED
@@ -22,6 +22,9 @@ module Miteru
22
22
  sentry_dsn: nil,
23
23
  sentry_trace_sample_rate: 0.25,
24
24
  sidekiq_redis_url: nil,
25
+ cache_redis_url: nil,
26
+ cache_ex: nil,
27
+ cache_prefix: "miteru:cache",
25
28
  slack_channel: "#general",
26
29
  slack_webhook_url: nil,
27
30
  threads: Parallel.processor_count,
@@ -39,6 +42,15 @@ module Miteru
39
42
  # @return [Float]
40
43
 
41
44
  # @!attribute [r] sidekiq_redis_url
45
+ # @return [String, nil]
46
+
47
+ # @!attribute [r] cache_redis_url
48
+ # @return [String, nil]
49
+
50
+ # @!attribute [r] cache_ex
51
+ # @return [Integer, nil]
52
+
53
+ # @!attribute [r] cache_prefix
42
54
  # @return [String]
43
55
 
44
56
  # @!attribute [r] http_timeout
@@ -11,49 +11,46 @@ module Miteru
11
11
  Try[OpenSSL::SSL::SSLError, ::HTTP::Error, Addressable::URI::InvalidURIError] do
12
12
  info = "Website:#{website.info}."
13
13
  info = info.colorize(:red) if website.kits?
14
-
15
- Miteru.logger.info(info)
16
- return unless website.kits?
17
-
18
- notify website
19
-
20
- return unless auto_download?
14
+ logger.info(info)
21
15
 
22
16
  website.kits.each do |kit|
23
17
  downloader = Downloader.new(kit)
24
18
  result = downloader.result
25
- if result.success?
26
- Miteru.logger.info("Kit:#{kit.truncated_url} downloaded as #{result.value!}.")
27
- else
28
- Miteru.logger.warn("Kit:#{kit.truncated_url} failed to download - #{result.failure}.")
19
+ unless result.success?
20
+ logger.warn("Kit:#{kit.truncated_url} failed to download - #{result.failure}.")
21
+ next
29
22
  end
23
+ destination = result.value!
24
+ logger.info("Kit:#{kit.truncated_url} downloaded as #{destination}.")
25
+ # Remove downloaded file if auto_download is not allowed
26
+ FileUtils.rm(destination, force: true) unless auto_download?
27
+ # Notify the kit
28
+ notify(kit)
30
29
  end
30
+
31
+ # Cache the website
32
+ cache.set(website.url, website.source, ex: cache_ex) if cache?
31
33
  end.recover { nil }.value!
32
34
  end
33
35
 
34
36
  private
35
37
 
36
- def auto_download?
37
- Miteru.config.auto_download
38
- end
39
-
40
38
  #
41
- # @param [Miteru::Website] website
39
+ # @param [Miteru::Kit] kit
42
40
  #
43
- def notify(website)
41
+ def notify(kit)
44
42
  notifiers.each do |notifier|
45
- result = notifier.result(website)
43
+ result = notifier.result(kit)
46
44
  if result.success?
47
- Miteru.logger.info("Notifier:#{notifier.name} succeeded.")
45
+ logger.info("Notifier:#{notifier.name} succeeded.")
48
46
  else
49
- Miteru.logger.warn("Notifier:#{notifier.name} failed - #{result.failure}.")
47
+ logger.warn("Notifier:#{notifier.name} failed - #{result.failure}.")
50
48
  end
51
49
  end
52
50
  end
53
51
 
54
- #
55
- # @return [Array<Miteru::Notifiers::Base>]
56
- #
52
+ private
53
+
57
54
  def notifiers
58
55
  @notifiers ||= Miteru.notifiers.map(&:new)
59
56
  end
@@ -43,7 +43,7 @@ module Miteru
43
43
 
44
44
  # Record a kit in DB
45
45
  Record.create_by_kit_and_hash(kit, sha256: sha256(destination))
46
- Miteru.logger.info "Download #{kit.url} as #{destination}"
46
+ logger.info "Download #{kit.url} as #{destination}"
47
47
 
48
48
  destination
49
49
  end
data/lib/miteru/kit.rb CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  module Miteru
4
4
  class Kit < Service
5
+ include Concerns::UrlTruncatable
6
+
5
7
  # @return [String]
6
8
  attr_reader :url
7
9
 
@@ -85,17 +87,6 @@ module Miteru
85
87
  @hostname ||= URI(url).hostname
86
88
  end
87
89
 
88
- def decoded_url
89
- @decoded_url ||= URI.decode_www_form_component(url)
90
- end
91
-
92
- #
93
- # @return [String]
94
- #
95
- def truncated_url
96
- url.truncate(64)
97
- end
98
-
99
90
  private
100
91
 
101
92
  def filename_to_download
@@ -3,7 +3,7 @@
3
3
  module Miteru
4
4
  module Notifiers
5
5
  class Base < Service
6
- def call(website)
6
+ def call(kit)
7
7
  raise NotImplementedError
8
8
  end
9
9
 
@@ -77,13 +77,13 @@ module Miteru
77
77
  #
78
78
  # Notifiy to Slack
79
79
  #
80
- # @param [Miteru::Website] website
80
+ # @param [Miteru::Kit] kit
81
81
  #
82
- def call(website)
82
+ def call(kit)
83
83
  return unless callable?
84
84
 
85
- attachment = SlackAttachment.new(website.url)
86
- notifier.post(text: website.info, attachments: attachment.to_a) if website.kits?
85
+ attachment = SlackAttachment.new(kit.url)
86
+ notifier.post(text: kit.defanged_truncated_url, attachments: attachment.to_a)
87
87
  end
88
88
 
89
89
  def callable?
@@ -4,12 +4,12 @@ module Miteru
4
4
  module Notifiers
5
5
  class UrlScan < Base
6
6
  #
7
- # @param [Miteru::Website] website
7
+ # @param [Miteru::Kit] kit
8
8
  #
9
- def call(website)
9
+ def call(kit)
10
10
  return unless callable?
11
11
 
12
- website.kits.each { |kit| submit(kit.url, source: website.source) }
12
+ submit(kit.decoded_url, source: kit.source)
13
13
  end
14
14
 
15
15
  def callable?
@@ -3,30 +3,37 @@
3
3
  module Miteru
4
4
  class Orchestrator < Service
5
5
  def call
6
- Miteru.logger.info("#{websites.length} websites loaded in total.") if verbose?
6
+ logger.info("#{non_cached_websites.length} websites loaded in total.") if verbose?
7
7
 
8
- if Miteru.sidekiq?
9
- websites.each do |website|
10
- Jobs::CrawleJob.perform_async(website.url, website.source)
11
- Miteru.logger.info("Website:#{website.truncated_url} crawler job queued.") if verbose?
12
- end
8
+ if sidekiq?
9
+ sidekiq_call
13
10
  else
14
- Miteru.logger.info("Use #{threads} thread(s).") if verbose?
15
- Parallel.each(websites, in_threads: threads) do |website|
16
- Miteru.logger.info("Website:#{website.truncated_url} crawling started.") if verbose?
11
+ parallel_call
12
+ end
13
+ end
17
14
 
18
- result = Crawler.result(website)
19
- if result.success?
20
- Miteru.logger.info("Crawler:#{website.truncated_url} succeeded.")
21
- else
22
- Miteru.logger.info("Crawler:#{website.truncated_url} failed - #{result.failure}.")
23
- end
15
+ def sidekiq_call
16
+ non_cached_websites.each do |website|
17
+ Jobs::CrawleJob.perform_async(website.url, website.source)
18
+ logger.info("Website:#{website.truncated_url} crawler job queued.") if verbose?
19
+ end
20
+ end
21
+
22
+ def parallel_call
23
+ logger.info("Use #{threads} thread(s).") if verbose?
24
+ Parallel.each(non_cached_websites, in_threads: threads) do |website|
25
+ logger.info("Website:#{website.truncated_url} crawling started.") if verbose?
26
+ result = Crawler.result(website)
27
+ if result.success?
28
+ logger.info("Crawler:#{website.truncated_url} succeeded.")
29
+ else
30
+ logger.info("Crawler:#{website.truncated_url} failed - #{result.failure}.")
24
31
  end
25
32
  end
26
33
  end
27
34
 
28
35
  #
29
- # @return [Array<Miteru::Websites>]
36
+ # @return [Array<Miteru::Website>]
30
37
  #
31
38
  def websites
32
39
  @websites ||= [].tap do |out|
@@ -34,30 +41,33 @@ module Miteru
34
41
  result = feed.result
35
42
  if result.success?
36
43
  websites = result.value!
37
- Miteru.logger.info("Feed:#{feed.source} has #{websites.length} websites.") if verbose?
44
+ logger.info("Feed:#{feed.source} has #{websites.length} websites.") if verbose?
38
45
  out << websites
39
46
  else
40
- Miteru.logger.warn("Feed:#{feed.source} failed - #{result.failure}")
47
+ logger.warn("Feed:#{feed.source} failed - #{result.failure}")
41
48
  end
42
49
  end
43
50
  end.flatten.uniq(&:url)
44
51
  end
45
52
 
46
53
  #
47
- # @return [Array<Miteru::Feeds::Base>]
54
+ # @return [Array<Miteru::Website>]
48
55
  #
49
- def feeds
50
- Miteru.feeds.map(&:new)
51
- end
52
-
53
- private
54
-
55
- def threads
56
- Miteru.config.threads
56
+ def non_cached_websites
57
+ @non_cached_websites ||= [].tap do |out|
58
+ out << if cache?
59
+ websites.reject { |website| cache.cached?(website.url) }
60
+ else
61
+ websites
62
+ end
63
+ end.flatten.uniq(&:url)
57
64
  end
58
65
 
59
- def verbose?
60
- Miteru.config.verbose
66
+ #
67
+ # @return [Array<Miteru::Feeds::Base>]
68
+ #
69
+ def feeds
70
+ @feeds ||= Miteru.feeds.map(&:new)
61
71
  end
62
72
  end
63
73
  end
@@ -24,5 +24,49 @@ module Miteru
24
24
  new.result(...)
25
25
  end
26
26
  end
27
+
28
+ private
29
+
30
+ def auto_download?
31
+ Miteru.config.auto_download
32
+ end
33
+
34
+ #
35
+ # @return [SemanticLogger]
36
+ #
37
+ def logger
38
+ Miteru.logger
39
+ end
40
+
41
+ def cache?
42
+ Miteru.cache?
43
+ end
44
+
45
+ def sidekiq?
46
+ Miteru.sidekiq?
47
+ end
48
+
49
+ #
50
+ # @return [Miteru::Cache]
51
+ #
52
+ def cache
53
+ Miteru.cache
54
+ end
55
+
56
+ def threads
57
+ Miteru.config.threads
58
+ end
59
+
60
+ def verbose?
61
+ Miteru.config.verbose
62
+ end
63
+
64
+ def cache_prefix
65
+ Miteru.config.cache_prefix
66
+ end
67
+
68
+ def cache_ex
69
+ Miteru.config.cache_ex
70
+ end
27
71
  end
28
72
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Miteru
4
- VERSION = "2.1.1"
4
+ VERSION = "2.2.1"
5
5
  end
@@ -4,6 +4,8 @@ require "oga"
4
4
 
5
5
  module Miteru
6
6
  class Website < Service
7
+ include Concerns::UrlTruncatable
8
+
7
9
  # @return [String]
8
10
  attr_reader :url
9
11
 
@@ -41,17 +43,6 @@ module Miteru
41
43
  (href_links + possible_file_links).compact.uniq
42
44
  end
43
45
 
44
- #
45
- # @return [String]
46
- #
47
- def truncated_url
48
- url.truncate(64)
49
- end
50
-
51
- def defanged_truncated_url
52
- truncated_url.to_s.gsub(".", "[.]")
53
- end
54
-
55
46
  def info
56
47
  "#{defanged_truncated_url} has #{kits.length} kit(s) (Source: #{source})"
57
48
  end
data/lib/miteru.rb CHANGED
@@ -31,8 +31,12 @@ require "miteru/errors"
31
31
  # Concerns
32
32
  require "miteru/concerns/database_connectable"
33
33
  require "miteru/concerns/error_unwrappable"
34
+ require "miteru/concerns/url_truncatable"
34
35
 
35
36
  # Core classes
37
+ require "miteru/service"
38
+
39
+ require "miteru/cache"
36
40
  require "miteru/config"
37
41
  require "miteru/http"
38
42
 
@@ -93,6 +97,14 @@ module Miteru
93
97
  env == "development"
94
98
  end
95
99
 
100
+ def cache?
101
+ !Miteru.config.cache_redis_url.nil?
102
+ end
103
+
104
+ def cache
105
+ @cache ||= Cache.new(Miteru.config.cache_redis_url)
106
+ end
107
+
96
108
  #
97
109
  # @return [Boolean]
98
110
  #
@@ -117,8 +129,6 @@ module Miteru
117
129
  end
118
130
 
119
131
  # Services
120
- require "miteru/service"
121
-
122
132
  require "miteru/crawler"
123
133
  require "miteru/downloader"
124
134
  require "miteru/kit"
data/miteru.gemspec CHANGED
@@ -1,67 +1,68 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- lib = File.expand_path('lib', __dir__)
3
+ lib = File.expand_path("lib", __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
- require 'miteru/version'
5
+ require "miteru/version"
6
6
 
7
7
  Gem::Specification.new do |spec|
8
- spec.name = 'miteru'
8
+ spec.name = "miteru"
9
9
  spec.version = Miteru::VERSION
10
- spec.authors = ['Manabu Niseki']
11
- spec.email = ['manabu.niseki@gmail.com']
12
- spec.metadata['rubygems_mfa_required'] = 'true'
10
+ spec.authors = ["Manabu Niseki"]
11
+ spec.email = ["manabu.niseki@gmail.com"]
12
+ spec.metadata["rubygems_mfa_required"] = "true"
13
13
 
14
- spec.summary = 'A phishing kit collector for scavengers'
15
- spec.description = 'A phishing kit collector for scavengers'
16
- spec.homepage = 'https://github.com/ninoseki/miteru'
17
- spec.license = 'MIT'
14
+ spec.summary = "A phishing kit collector for scavengers"
15
+ spec.description = "A phishing kit collector for scavengers"
16
+ spec.homepage = "https://github.com/ninoseki/miteru"
17
+ spec.license = "MIT"
18
18
 
19
19
  # Specify which files should be added to the gem when it is released.
20
20
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
21
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
22
22
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
23
23
  end
24
- spec.bindir = 'exe'
24
+ spec.bindir = "exe"
25
25
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
- spec.require_paths = ['lib']
26
+ spec.require_paths = ["lib"]
27
27
 
28
- spec.add_development_dependency 'bundler', '~> 2.5'
29
- spec.add_development_dependency 'capybara', '~> 3.40'
30
- spec.add_development_dependency 'coveralls_reborn', '~> 0.28'
31
- spec.add_development_dependency 'fuubar', '~> 2.5'
32
- spec.add_development_dependency 'mysql2', '~> 0.5'
33
- spec.add_development_dependency 'pg', '~> 1.5'
34
- spec.add_development_dependency 'rake', '~> 13.1'
35
- spec.add_development_dependency 'rspec', '~> 3.13'
36
- spec.add_development_dependency 'simplecov-lcov', '~> 0.8'
37
- spec.add_development_dependency 'standard', '~> 1.33'
38
- spec.add_development_dependency 'test-prof', '~> 1.3'
39
- spec.add_development_dependency 'vcr', '~> 6.2'
40
- spec.add_development_dependency 'webmock', '~> 3.19'
28
+ spec.add_development_dependency "bundler", "~> 2.5"
29
+ spec.add_development_dependency "capybara", "~> 3.40"
30
+ spec.add_development_dependency "coveralls_reborn", "~> 0.28"
31
+ spec.add_development_dependency "fuubar", "~> 2.5"
32
+ spec.add_development_dependency "mysql2", "~> 0.5"
33
+ spec.add_development_dependency "pg", "~> 1.5"
34
+ spec.add_development_dependency "rake", "~> 13.1"
35
+ spec.add_development_dependency "rspec", "~> 3.13"
36
+ spec.add_development_dependency "simplecov-lcov", "~> 0.8"
37
+ spec.add_development_dependency "standard", "~> 1.33"
38
+ spec.add_development_dependency "test-prof", "~> 1.3"
39
+ spec.add_development_dependency "vcr", "~> 6.2"
40
+ spec.add_development_dependency "webmock", "~> 3.19"
41
41
 
42
- spec.add_dependency 'activerecord', '7.1.3'
43
- spec.add_dependency 'addressable', '2.8.6'
44
- spec.add_dependency 'anyway_config', '2.6.2'
45
- spec.add_dependency 'colorize', '1.1.0'
46
- spec.add_dependency 'dotenv', '2.8.1'
47
- spec.add_dependency 'down', '5.4.1'
48
- spec.add_dependency 'dry-files', '1.1.0'
49
- spec.add_dependency 'dry-monads', '1.6.0'
50
- spec.add_dependency 'http', '5.2.0'
51
- spec.add_dependency 'memo_wise', '1.8.0'
52
- spec.add_dependency 'oga', '3.4'
53
- spec.add_dependency 'parallel', '1.24.0'
54
- spec.add_dependency 'puma', '6.4.2'
55
- spec.add_dependency 'rack', '3.0.9'
56
- spec.add_dependency 'rack-session', '2.0.0'
57
- spec.add_dependency 'rackup', '2.1.0'
58
- spec.add_dependency 'semantic_logger', '4.15.0'
59
- spec.add_dependency 'sentry-ruby', '5.16.1'
60
- spec.add_dependency 'sentry-sidekiq', '5.16.1'
61
- spec.add_dependency 'sidekiq', '7.2.1'
62
- spec.add_dependency 'slack-notifier', '2.4.0'
63
- spec.add_dependency 'sqlite3', '1.7.2'
64
- spec.add_dependency 'thor', '1.3.0'
65
- spec.add_dependency 'thor-hollaback', '0.2.1'
66
- spec.add_dependency 'uuidtools', '2.2.0'
42
+ spec.add_dependency "activerecord", "7.1.3"
43
+ spec.add_dependency "addressable", "2.8.6"
44
+ spec.add_dependency "anyway_config", "2.6.3"
45
+ spec.add_dependency "colorize", "1.1.0"
46
+ spec.add_dependency "dotenv", "2.8.1"
47
+ spec.add_dependency "down", "5.4.1"
48
+ spec.add_dependency "dry-files", "1.1.0"
49
+ spec.add_dependency "dry-monads", "1.6.0"
50
+ spec.add_dependency "http", "5.2.0"
51
+ spec.add_dependency "memo_wise", "1.8.0"
52
+ spec.add_dependency "oga", "3.4"
53
+ spec.add_dependency "parallel", "1.24.0"
54
+ spec.add_dependency "puma", "6.4.2"
55
+ spec.add_dependency "rack", "3.0.9"
56
+ spec.add_dependency "rack-session", "2.0.0"
57
+ spec.add_dependency "rackup", "2.1.0"
58
+ spec.add_dependency "redis", "5.0.8"
59
+ spec.add_dependency "semantic_logger", "4.15.0"
60
+ spec.add_dependency "sentry-ruby", "5.16.1"
61
+ spec.add_dependency "sentry-sidekiq", "5.16.1"
62
+ spec.add_dependency "sidekiq", "7.2.1"
63
+ spec.add_dependency "slack-notifier", "2.4.0"
64
+ spec.add_dependency "sqlite3", "1.7.2"
65
+ spec.add_dependency "thor", "1.3.0"
66
+ spec.add_dependency "thor-hollaback", "0.2.1"
67
+ spec.add_dependency "uuidtools", "2.2.0"
67
68
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: miteru
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Manabu Niseki
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-02-07 00:00:00.000000000 Z
11
+ date: 2024-02-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -226,14 +226,14 @@ dependencies:
226
226
  requirements:
227
227
  - - '='
228
228
  - !ruby/object:Gem::Version
229
- version: 2.6.2
229
+ version: 2.6.3
230
230
  type: :runtime
231
231
  prerelease: false
232
232
  version_requirements: !ruby/object:Gem::Requirement
233
233
  requirements:
234
234
  - - '='
235
235
  - !ruby/object:Gem::Version
236
- version: 2.6.2
236
+ version: 2.6.3
237
237
  - !ruby/object:Gem::Dependency
238
238
  name: colorize
239
239
  requirement: !ruby/object:Gem::Requirement
@@ -416,6 +416,20 @@ dependencies:
416
416
  - - '='
417
417
  - !ruby/object:Gem::Version
418
418
  version: 2.1.0
419
+ - !ruby/object:Gem::Dependency
420
+ name: redis
421
+ requirement: !ruby/object:Gem::Requirement
422
+ requirements:
423
+ - - '='
424
+ - !ruby/object:Gem::Version
425
+ version: 5.0.8
426
+ type: :runtime
427
+ prerelease: false
428
+ version_requirements: !ruby/object:Gem::Requirement
429
+ requirements:
430
+ - - '='
431
+ - !ruby/object:Gem::Version
432
+ version: 5.0.8
419
433
  - !ruby/object:Gem::Dependency
420
434
  name: semantic_logger
421
435
  requirement: !ruby/object:Gem::Requirement
@@ -566,6 +580,7 @@ files:
566
580
  - exe/miteru
567
581
  - lefthook.yml
568
582
  - lib/miteru.rb
583
+ - lib/miteru/cache.rb
569
584
  - lib/miteru/cli/application.rb
570
585
  - lib/miteru/cli/base.rb
571
586
  - lib/miteru/cli/database.rb
@@ -575,6 +590,7 @@ files:
575
590
  - lib/miteru/commands/web.rb
576
591
  - lib/miteru/concerns/database_connectable.rb
577
592
  - lib/miteru/concerns/error_unwrappable.rb
593
+ - lib/miteru/concerns/url_truncatable.rb
578
594
  - lib/miteru/config.rb
579
595
  - lib/miteru/crawler.rb
580
596
  - lib/miteru/database.rb