miteru 1.2.2 → 2.0.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 +4 -4
- data/.github/workflows/gem.yml +36 -0
- data/.github/workflows/{test.yml → ruby.yml} +4 -13
- data/.gitignore +7 -2
- data/.rspec +1 -1
- data/README.md +7 -17
- data/docker-compose.yml +12 -0
- data/exe/miteru +3 -3
- data/lefthook.yml +9 -0
- data/lib/miteru/cli/application.rb +27 -0
- data/lib/miteru/cli/base.rb +16 -0
- data/lib/miteru/cli/database.rb +11 -0
- data/lib/miteru/commands/database.rb +23 -0
- data/lib/miteru/commands/main.rb +37 -0
- data/lib/miteru/commands/sidekiq.rb +35 -0
- data/lib/miteru/commands/web.rb +37 -0
- data/lib/miteru/concerns/database_connectable.rb +16 -0
- data/lib/miteru/concerns/error_unwrappable.rb +30 -0
- data/lib/miteru/config.rb +98 -0
- data/lib/miteru/crawler.rb +28 -44
- data/lib/miteru/database.rb +50 -38
- data/lib/miteru/downloader.rb +52 -41
- data/lib/miteru/errors.rb +37 -0
- data/lib/miteru/feeds/ayashige.rb +9 -20
- data/lib/miteru/feeds/base.rb +141 -0
- data/lib/miteru/feeds/phishing_database.rb +11 -10
- data/lib/miteru/feeds/urlscan.rb +47 -19
- data/lib/miteru/feeds/urlscan_pro.rb +20 -18
- data/lib/miteru/http.rb +51 -0
- data/lib/miteru/kit.rb +28 -20
- data/lib/miteru/mixin.rb +2 -29
- data/lib/miteru/notifiers/base.rb +10 -3
- data/lib/miteru/notifiers/slack.rb +85 -10
- data/lib/miteru/notifiers/urlscan.rb +29 -14
- data/lib/miteru/orchestrator.rb +58 -0
- data/lib/miteru/record.rb +8 -15
- data/lib/miteru/service.rb +28 -0
- data/lib/miteru/sidekiq/application.rb +13 -0
- data/lib/miteru/sidekiq/jobs.rb +21 -0
- data/lib/miteru/version.rb +1 -1
- data/lib/miteru/web/application.rb +42 -0
- data/lib/miteru/website.rb +48 -48
- data/lib/miteru.rb +130 -22
- data/miteru.gemspec +49 -38
- metadata +262 -97
- data/.overcommit.yml +0 -12
- data/.standard.yml +0 -4
- data/lib/miteru/attachement.rb +0 -74
- data/lib/miteru/cli.rb +0 -41
- data/lib/miteru/configuration.rb +0 -122
- data/lib/miteru/error.rb +0 -7
- data/lib/miteru/feeds/feed.rb +0 -53
- data/lib/miteru/feeds/phishstats.rb +0 -28
- data/lib/miteru/feeds.rb +0 -45
- data/lib/miteru/http_client.rb +0 -85
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa673c60148a21b0838fec44df350670fad6af4873cf54922ff14f8042f8a781
|
4
|
+
data.tar.gz: 3b09b49f88c1a56224e5f472647646619061fc57a258d54bb5a51ce4420ed22e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 396239204cda13c34766428ac7b223828413b56179b72eba137be1ded7af40ff7753ded1a504cef615b3654c43f597fd223c39324b063a4a281ea729e27882fa
|
7
|
+
data.tar.gz: f22eb47d90dc5ca7cd77896de1fcb9420450f9055f49da4d316c8cdd9f255acb5282ed91529109122811c300a0ecfc92de71a4b26031854f9671c58e6671990f
|
@@ -0,0 +1,36 @@
|
|
1
|
+
name: Release gem
|
2
|
+
|
3
|
+
on:
|
4
|
+
workflow_dispatch:
|
5
|
+
inputs:
|
6
|
+
rubygems-otp-code:
|
7
|
+
description: RubyGems OTP code
|
8
|
+
required: true
|
9
|
+
type: string
|
10
|
+
|
11
|
+
jobs:
|
12
|
+
release:
|
13
|
+
runs-on: ubuntu-latest
|
14
|
+
strategy:
|
15
|
+
matrix:
|
16
|
+
ruby-version:
|
17
|
+
- 3.3
|
18
|
+
steps:
|
19
|
+
- name: Checkout
|
20
|
+
uses: actions/checkout@v4
|
21
|
+
- name: Set up Ruby
|
22
|
+
uses: ruby/setup-ruby@v1
|
23
|
+
with:
|
24
|
+
ruby-version: ${{ matrix.ruby-version }}
|
25
|
+
bundler: latest
|
26
|
+
bundler-cache: true
|
27
|
+
- name: Configure Git
|
28
|
+
# Configure Git to push a tag
|
29
|
+
run: |
|
30
|
+
git config --global user.name "${GITHUB_ACTOR}"
|
31
|
+
git config --global user.email "${GITHUB_ACTOR}@users.noreply.github.com"
|
32
|
+
- name: Release gem
|
33
|
+
run: bundle exec rake release
|
34
|
+
env:
|
35
|
+
GEM_HOST_API_KEY: ${{ secrets.GEM_HOST_API_KEY }}
|
36
|
+
GEM_HOST_OTP_CODE: ${{ inputs.rubygems-otp-code }}
|
@@ -5,10 +5,9 @@ on: [push, pull_request]
|
|
5
5
|
jobs:
|
6
6
|
build:
|
7
7
|
runs-on: ubuntu-latest
|
8
|
-
|
9
8
|
services:
|
10
9
|
postgres:
|
11
|
-
image: postgres:
|
10
|
+
image: postgres:16
|
12
11
|
env:
|
13
12
|
POSTGRES_USER: postgres
|
14
13
|
POSTGRES_PASSWORD: postgres
|
@@ -20,7 +19,6 @@ jobs:
|
|
20
19
|
--health-retries 5
|
21
20
|
ports:
|
22
21
|
- 5432:5432
|
23
|
-
|
24
22
|
mysql:
|
25
23
|
image: mysql:8.0
|
26
24
|
env:
|
@@ -35,31 +33,24 @@ jobs:
|
|
35
33
|
--health-interval=10s
|
36
34
|
--health-timeout=5s
|
37
35
|
--health-retries=3
|
38
|
-
|
39
36
|
strategy:
|
40
|
-
fail-fast: false
|
41
37
|
matrix:
|
42
|
-
ruby: [
|
43
|
-
|
38
|
+
ruby: [3.1, 3.2, 3.3]
|
44
39
|
steps:
|
45
|
-
- uses: actions/checkout@
|
40
|
+
- uses: actions/checkout@v4
|
46
41
|
- name: Set up Ruby
|
47
42
|
uses: ruby/setup-ruby@v1
|
48
43
|
with:
|
49
44
|
ruby-version: ${{ matrix.ruby }}
|
50
45
|
bundler: latest
|
51
46
|
bundler-cache: true
|
52
|
-
|
53
47
|
- name: Install dependencies
|
54
|
-
run:
|
55
|
-
sudo apt-get -yqq install libpq-dev libmysqlclient-dev
|
56
|
-
|
48
|
+
run: sudo apt-get -yqq install libpq-dev libmysqlclient-dev
|
57
49
|
- name: Test with PostgreSQL
|
58
50
|
env:
|
59
51
|
MITERU_DATABASE: postgresql://postgres:postgres@localhost:5432/test
|
60
52
|
run: |
|
61
53
|
bundle exec rake
|
62
|
-
|
63
54
|
- name: Test with MySQL
|
64
55
|
env:
|
65
56
|
MITERU_DATABASE: mysql2://mysql:mysql@127.0.0.1:3306/test
|
data/.gitignore
CHANGED
data/.rspec
CHANGED
data/README.md
CHANGED
@@ -5,33 +5,23 @@
|
|
5
5
|
[](https://www.codefactor.io/repository/github/ninoseki/miteru)
|
6
6
|
[](https://coveralls.io/github/ninoseki/miteru?branch=master)
|
7
7
|
|
8
|
-
|
8
|
+
A phishing kit collector for scavengers.
|
9
9
|
|
10
10
|
## Disclaimer
|
11
11
|
|
12
12
|
This tool is for research purposes only. The use of this tool is your responsibility.
|
13
13
|
I take no responsibility and/or liability for how you choose to use this tool.
|
14
14
|
|
15
|
-
## How
|
15
|
+
## How It Works
|
16
16
|
|
17
17
|
- It collects phishy URLs from the following feeds:
|
18
|
-
-
|
19
|
-
-
|
20
|
-
- [
|
21
|
-
- [
|
22
|
-
|
23
|
-
- [Ayashige feed](https://github.com/ninoseki/ayashige)
|
24
|
-
- [Phishing Database feed](https://github.com/mitchellkrogza/Phishing.Database)
|
25
|
-
- [PhishStats feed](https://phishstats.info/)
|
26
|
-
- It checks each phishy URL whether it enables directory listing and contains a phishing kit (compressed file) or not.
|
18
|
+
- urlscan.io's automatic submissions. (`task.method:automatic`)
|
19
|
+
- urlscan.io phish feed. (available for Pro users)
|
20
|
+
- [mitchellkrogza/Phishing.Database](https://github.com/mitchellkrogza/Phishing.Database)'s `phishing-links-ACTIVE-NOW.txt`.
|
21
|
+
- [ninoseki/ayashige](https://github.com/ninoseki/ayashige) feed.
|
22
|
+
- It checks each phishy URL whether it enables directory listing and contains phishing kits (compressed files) or not.
|
27
23
|
- Note: Supported compressed files are: `*.zip`, `*.rar`, `*.7z`, `*.tar` and `*.gz`.
|
28
24
|
|
29
|
-
## Features
|
30
|
-
|
31
|
-
- [x] Phishing kit detection & collection
|
32
|
-
- [x] Slack notification
|
33
|
-
- [x] Threading
|
34
|
-
|
35
25
|
## Docs
|
36
26
|
|
37
27
|
- [Requirements & Installation](https://github.com/ninoseki/miteru/wiki/Requirements-&-Installation)
|
data/docker-compose.yml
ADDED
data/exe/miteru
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
$LOAD_PATH.unshift("#{__dir__}/../lib")
|
5
5
|
|
6
|
-
require
|
6
|
+
require 'miteru'
|
7
7
|
|
8
|
-
ARGV.unshift(Miteru::CLI.default_task) unless Miteru::CLI.all_tasks.key?(ARGV[0])
|
9
|
-
Miteru::CLI.start(ARGV)
|
8
|
+
ARGV.unshift(Miteru::CLI::App.default_task) unless Miteru::CLI::App.all_tasks.key?(ARGV[0])
|
9
|
+
Miteru::CLI::App.start(ARGV)
|
data/lefthook.yml
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "thor"
|
4
|
+
require "thor/hollaback"
|
5
|
+
|
6
|
+
require "miteru/cli/base"
|
7
|
+
require "miteru/cli/database"
|
8
|
+
|
9
|
+
require "miteru/commands/main"
|
10
|
+
require "miteru/commands/sidekiq"
|
11
|
+
require "miteru/commands/web"
|
12
|
+
|
13
|
+
module Miteru
|
14
|
+
module CLI
|
15
|
+
#
|
16
|
+
# Main CLI class
|
17
|
+
#
|
18
|
+
class App < Base
|
19
|
+
include Commands::Main
|
20
|
+
include Commands::Sidekiq
|
21
|
+
include Commands::Web
|
22
|
+
|
23
|
+
desc "db", "Sub commands for DB"
|
24
|
+
subcommand "db", CLI::Database
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Miteru
|
4
|
+
module Commands
|
5
|
+
module Database
|
6
|
+
class << self
|
7
|
+
def included(thor)
|
8
|
+
thor.class_eval do
|
9
|
+
include Concerns::DatabaseConnectable
|
10
|
+
|
11
|
+
desc "migrate", "Migrate DB schemas"
|
12
|
+
around :with_db_connection
|
13
|
+
method_option :verbose, type: :boolean, default: true
|
14
|
+
def migrate(direction = "up")
|
15
|
+
ActiveRecord::Migration.verbose = options["verbose"]
|
16
|
+
Miteru::Database.migrate direction.to_sym
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Miteru
|
4
|
+
module Commands
|
5
|
+
module Main
|
6
|
+
class << self
|
7
|
+
def included(thor)
|
8
|
+
thor.class_eval do
|
9
|
+
include Concerns::DatabaseConnectable
|
10
|
+
|
11
|
+
method_option :auto_download, type: :boolean, default: false,
|
12
|
+
desc: "Enable or disable auto-downloading of phishing kits"
|
13
|
+
method_option :directory_traveling, type: :boolean, default: false,
|
14
|
+
desc: "Enable or disable directory traveling"
|
15
|
+
method_option :download_to, type: :string, default: "/tmp", desc: "Directory to download phishing kits"
|
16
|
+
method_option :threads, type: :numeric, desc: "Number of threads to use", default: Parallel.processor_count
|
17
|
+
method_option :verbose, type: :boolean, default: true
|
18
|
+
desc "execute", "Execute the crawler"
|
19
|
+
around :with_db_connection
|
20
|
+
def execute
|
21
|
+
Miteru.config.tap do |config|
|
22
|
+
config.auto_download = options["auto_download"]
|
23
|
+
config.directory_traveling = options["directory_traveling"]
|
24
|
+
config.download_to = options["download_to"]
|
25
|
+
config.threads = options["threads"]
|
26
|
+
config.verbose = options["verbose"]
|
27
|
+
end
|
28
|
+
|
29
|
+
Orchestrator.call
|
30
|
+
end
|
31
|
+
default_command :execute
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Miteru
|
4
|
+
module Commands
|
5
|
+
#
|
6
|
+
# Sidekiq sub-commands
|
7
|
+
#
|
8
|
+
module Sidekiq
|
9
|
+
class << self
|
10
|
+
def included(thor)
|
11
|
+
thor.class_eval do
|
12
|
+
desc "sidekiq", "Start Sidekiq"
|
13
|
+
method_option :env, type: :string, default: "production", desc: "Environment"
|
14
|
+
method_option :concurrency, type: :numeric, default: 5, desc: "Sidekiq concurrency", aliases: "-c"
|
15
|
+
def sidekiq
|
16
|
+
require "sidekiq/cli"
|
17
|
+
|
18
|
+
ENV["APP_ENV"] ||= options["env"]
|
19
|
+
concurrency = options["concurrency"].to_s
|
20
|
+
|
21
|
+
cli = ::Sidekiq::CLI.instance
|
22
|
+
cli.parse [
|
23
|
+
"-r",
|
24
|
+
File.expand_path(File.join(__dir__, "..", "sidekiq", "application.rb")),
|
25
|
+
"-c",
|
26
|
+
concurrency
|
27
|
+
]
|
28
|
+
cli.run
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Miteru
|
4
|
+
module Commands
|
5
|
+
#
|
6
|
+
# Web sub-commands
|
7
|
+
#
|
8
|
+
module Web
|
9
|
+
class << self
|
10
|
+
def included(thor)
|
11
|
+
thor.class_eval do
|
12
|
+
desc "web", "Start the web app"
|
13
|
+
method_option :port, type: :numeric, default: 9292, desc: "Port to listen on"
|
14
|
+
method_option :host, type: :string, default: "localhost", desc: "Hostname to listen on"
|
15
|
+
method_option :threads, type: :string, default: "0:3", desc: "min:max threads to use"
|
16
|
+
method_option :verbose, type: :boolean, default: false, desc: "Don't report each request"
|
17
|
+
method_option :worker_timeout, type: :numeric, default: 60, desc: "Worker timeout value (in seconds)"
|
18
|
+
method_option :env, type: :string, default: "production", desc: "Environment"
|
19
|
+
def web
|
20
|
+
require "miteru/web/application"
|
21
|
+
|
22
|
+
ENV["APP_ENV"] ||= options["env"]
|
23
|
+
|
24
|
+
Miteru::Web::App.run!(
|
25
|
+
port: options["port"],
|
26
|
+
host: options["host"],
|
27
|
+
threads: options["threads"],
|
28
|
+
verbose: options["verbose"],
|
29
|
+
worker_timeout: options["worker_timeout"]
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Miteru
|
4
|
+
module Concerns
|
5
|
+
#
|
6
|
+
# Database connectable concern
|
7
|
+
#
|
8
|
+
module DatabaseConnectable
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
def with_db_connection(&block)
|
12
|
+
Database.with_db_connection(&block)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Miteru
|
4
|
+
module Concerns
|
5
|
+
#
|
6
|
+
# Error unwrappable concern
|
7
|
+
#
|
8
|
+
module ErrorUnwrappable
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
def unwrap_error(err)
|
12
|
+
return err unless err.is_a?(Dry::Monads::UnwrapError)
|
13
|
+
|
14
|
+
# NOTE: UnwrapError's receiver can be either of:
|
15
|
+
# - Dry::Monads::Try::Error
|
16
|
+
# - Dry::Monads::Result::Failure
|
17
|
+
receiver = err.receiver
|
18
|
+
case receiver
|
19
|
+
when Dry::Monads::Try::Error
|
20
|
+
# Error may be wrapped like Matryoshka
|
21
|
+
unwrap_error receiver.exception
|
22
|
+
when Dry::Monads::Failure
|
23
|
+
unwrap_error receiver.failure
|
24
|
+
else
|
25
|
+
err
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "anyway_config"
|
4
|
+
|
5
|
+
module Miteru
|
6
|
+
class Config < Anyway::Config
|
7
|
+
config_name :miteru
|
8
|
+
env_prefix ""
|
9
|
+
|
10
|
+
attr_config(
|
11
|
+
auto_download: false,
|
12
|
+
database_url: URI("sqlite3:miteru.db"),
|
13
|
+
directory_traveling: false,
|
14
|
+
download_to: "/tmp",
|
15
|
+
file_max_size: 1024 * 1024 * 100,
|
16
|
+
file_extensions: [".zip", ".rar", ".7z", ".tar", ".gz"],
|
17
|
+
file_mime_types: ["application/zip", "application/vnd.rar", "application/x-7z-compressed", "application/x-tar",
|
18
|
+
"application/gzip"],
|
19
|
+
api_timeout: 60,
|
20
|
+
http_timeout: 60,
|
21
|
+
download_timeout: 60,
|
22
|
+
sentry_dsn: nil,
|
23
|
+
sentry_trace_sample_rate: 0.25,
|
24
|
+
sidekiq_redis_url: nil,
|
25
|
+
slack_channel: "#general",
|
26
|
+
slack_webhook_url: nil,
|
27
|
+
threads: Parallel.processor_count,
|
28
|
+
urlscan_api_key: nil,
|
29
|
+
urlscan_submit_visibility: "public",
|
30
|
+
urlscan_date_condition: ">now-1h",
|
31
|
+
verbose: false
|
32
|
+
)
|
33
|
+
|
34
|
+
# @!attribute [r] sentry_dsn
|
35
|
+
# @return [String, nil]
|
36
|
+
|
37
|
+
# @!attribute [r] sentry_trace_sample_rate
|
38
|
+
# @return [Float]
|
39
|
+
|
40
|
+
# @!attribute [r] sidekiq_redis_url
|
41
|
+
# @return [String]
|
42
|
+
|
43
|
+
# @!attribute [r] http_timeout
|
44
|
+
# @return [Integer]
|
45
|
+
|
46
|
+
# @!attribute [r] api_timeout
|
47
|
+
# @return [Integer]
|
48
|
+
|
49
|
+
# @!attribute [r] download_timeout
|
50
|
+
# @return [Integer]
|
51
|
+
|
52
|
+
# @!attribute [rw] auto_download
|
53
|
+
# @return [Boolean]
|
54
|
+
|
55
|
+
# @!attribute [rw] directory_traveling
|
56
|
+
# @return [Boolean]
|
57
|
+
|
58
|
+
# @!attribute [rw] download_to
|
59
|
+
# @return [String]
|
60
|
+
|
61
|
+
# @!attribute [rw] threads
|
62
|
+
# @return [Integer]
|
63
|
+
|
64
|
+
# @!attribute [rw] verbose
|
65
|
+
# @return [Boolean]
|
66
|
+
|
67
|
+
# @!attribute [r] database_url
|
68
|
+
# @return [URI]
|
69
|
+
|
70
|
+
# @!attribute [r] file_max_size
|
71
|
+
# @return [Integer]
|
72
|
+
|
73
|
+
# @!attribute [r] file_extensions
|
74
|
+
# @return [Array<String>]
|
75
|
+
|
76
|
+
# @!attribute [r] file_mime_types
|
77
|
+
# @return [Array<String>]
|
78
|
+
|
79
|
+
# @!attribute [r] slack_webhook_url
|
80
|
+
# @return [String, nil]
|
81
|
+
|
82
|
+
# @!attribute [r] slack_channel
|
83
|
+
# @return [String]
|
84
|
+
|
85
|
+
# @!attribute [r] urlscan_api_key
|
86
|
+
# @return [String, nil]
|
87
|
+
|
88
|
+
# @!attribute [r] urlscan_submit_visibility
|
89
|
+
# @return [String]
|
90
|
+
|
91
|
+
# @!attribute [r] urlscan_date_condition
|
92
|
+
# @return [String]
|
93
|
+
|
94
|
+
def database_url=(val)
|
95
|
+
super(URI(val.to_s))
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/lib/miteru/crawler.rb
CHANGED
@@ -1,63 +1,47 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "colorize"
|
4
|
-
require "parallel"
|
5
|
-
require "uri"
|
6
|
-
|
7
3
|
module Miteru
|
8
|
-
class Crawler
|
9
|
-
|
4
|
+
class Crawler < Service
|
5
|
+
#
|
6
|
+
# @param [Miteru::Website] website
|
7
|
+
#
|
8
|
+
def call(website)
|
9
|
+
Try[OpenSSL::SSL::SSLError, ::HTTP::Error, Addressable::URI::InvalidURIError] do
|
10
|
+
Miteru.logger.info("Website:#{website.truncated_url} has #{website.kits.length} kit(s).")
|
11
|
+
return unless website.has_kits?
|
10
12
|
|
11
|
-
|
12
|
-
@downloader = Downloader.new(Miteru.configuration.download_to)
|
13
|
-
@feeds = Feeds.new
|
14
|
-
end
|
13
|
+
notify website
|
15
14
|
|
16
|
-
|
17
|
-
website = Website.new(entry.url, entry.source)
|
18
|
-
downloader.download_kits(website.kits) if website.has_kits? && auto_download?
|
19
|
-
notify(website) if website.has_kits? || verbose?
|
20
|
-
rescue OpenSSL::SSL::SSLError, HTTP::Error, Addressable::URI::InvalidURIError => _e
|
21
|
-
nil
|
22
|
-
end
|
15
|
+
return unless auto_download?
|
23
16
|
|
24
|
-
|
25
|
-
|
26
|
-
|
17
|
+
website.kits.each do |kit|
|
18
|
+
downloader = Downloader.new(kit)
|
19
|
+
result = downloader.result
|
27
20
|
|
28
|
-
|
29
|
-
|
30
|
-
|
21
|
+
if result.success?
|
22
|
+
Miteru.logger.info("Kit:#{kit.truncated_url} downloaded as #{result.value!}")
|
23
|
+
else
|
24
|
+
Miteru.logger.warn("Kit:#{kit.truncated_url} failed to download - #{result.failure}")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end.recover { nil }.value!
|
31
28
|
end
|
32
29
|
|
33
|
-
|
34
|
-
@threads ||= Miteru.configuration.threads
|
35
|
-
end
|
36
|
-
|
37
|
-
def notify(website)
|
38
|
-
Parallel.each(notifiers) do |notifier|
|
39
|
-
notifier.notify website
|
40
|
-
end
|
41
|
-
end
|
30
|
+
private
|
42
31
|
|
43
32
|
def auto_download?
|
44
|
-
Miteru.
|
33
|
+
Miteru.config.auto_download
|
45
34
|
end
|
46
35
|
|
47
|
-
def
|
48
|
-
|
36
|
+
def notify(website)
|
37
|
+
Parallel.each(notifiers) { |notifier| notifier.call(website) }
|
49
38
|
end
|
50
39
|
|
51
|
-
|
52
|
-
|
40
|
+
#
|
41
|
+
# @return [Array<Miteru::Notifiers::Base>]
|
42
|
+
#
|
53
43
|
def notifiers
|
54
|
-
@notifiers ||=
|
55
|
-
end
|
56
|
-
|
57
|
-
class << self
|
58
|
-
def execute
|
59
|
-
new.execute
|
60
|
-
end
|
44
|
+
@notifiers ||= Miteru.notifiers.map(&:new)
|
61
45
|
end
|
62
46
|
end
|
63
47
|
end
|