miteru 2.1.1 → 2.2.1

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: 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