osa 0.1.0 → 0.1.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/.rubocop.yml +1 -0
- data/Gemfile +2 -1
- data/Gemfile.lock +1 -1
- data/Rakefile +7 -6
- data/bin/console +3 -4
- data/bin/osa +28 -0
- data/exe/osa +2 -1
- data/lib/osa.rb +2 -1
- data/lib/osa/clients/http_client.rb +6 -1
- data/lib/osa/clients/ms_graph_client.rb +60 -22
- data/lib/osa/scripts/scan_report_folder.rb +0 -1
- data/lib/osa/services/auth_service.rb +1 -1
- data/lib/osa/util/constants.rb +1 -1
- data/lib/osa/util/context.rb +1 -1
- data/lib/osa/util/db.rb +1 -2
- data/lib/osa/version.rb +2 -1
- data/osa.gemspec +3 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 22c6dd2dc64261089df031e75fee841e1416276244674dce617792aacbb12fca
|
4
|
+
data.tar.gz: f0442134bc13835edcbacea2aa594fdc95202e47beed2e71c29f5214bbae2335
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ca001d8b232f9bfa8bcfde6e75be2a6e1a7b2d025254e22af2feec25625d979e3bd10a88325cee888442b5686b22c7f93fd1866225d7bb6ca38e27e9c62e05af
|
7
|
+
data.tar.gz: 7d96e933b2c4b09d335f825c933ba01197399aea947e7ca2fca3f66a851c7f469f046fd37abbb59548c54fbb37835eef3684540172cf01bcf30489f2106e6208
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
data/Rakefile
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
-
|
2
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'rake/testtask'
|
3
4
|
|
4
5
|
Rake::TestTask.new(:test) do |t|
|
5
|
-
t.libs <<
|
6
|
-
t.libs <<
|
7
|
-
t.test_files = FileList[
|
6
|
+
t.libs << 'test'
|
7
|
+
t.libs << 'lib'
|
8
|
+
t.test_files = FileList['test/**/*_test.rb']
|
8
9
|
end
|
9
10
|
|
10
|
-
task :
|
11
|
+
task default: :test
|
data/bin/console
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require
|
4
|
-
require "osa"
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'osa'
|
5
4
|
|
6
5
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
6
|
# with your gem easier. You can also use a different console, if you like.
|
@@ -10,5 +9,5 @@ require "osa"
|
|
10
9
|
# require "pry"
|
11
10
|
# Pry.start
|
12
11
|
|
13
|
-
require
|
12
|
+
require 'irb'
|
14
13
|
IRB.start(__FILE__)
|
data/bin/osa
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#
|
4
|
+
# This file was generated by Bundler.
|
5
|
+
#
|
6
|
+
# The application 'osa' is installed as part of a gem, and
|
7
|
+
# this file is here to facilitate running it.
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'pathname'
|
11
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
|
12
|
+
Pathname.new(__FILE__).realpath)
|
13
|
+
|
14
|
+
bundle_binstub = File.expand_path('../bundle', __FILE__)
|
15
|
+
|
16
|
+
if File.file?(bundle_binstub)
|
17
|
+
if /This file was generated by Bundler/.match?(File.read(bundle_binstub, 300))
|
18
|
+
load(bundle_binstub)
|
19
|
+
else
|
20
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
21
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'rubygems'
|
26
|
+
require 'bundler/setup'
|
27
|
+
|
28
|
+
load Gem.bin_path('osa', 'osa')
|
data/exe/osa
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
require 'osa/services/setup_service'
|
3
4
|
require 'osa/services/auth_service'
|
4
5
|
|
@@ -8,7 +9,7 @@ case cmd
|
|
8
9
|
when 'setup'
|
9
10
|
OSA::SetupService.new.setup!
|
10
11
|
when 'login'
|
11
|
-
OSA::AuthService.login(Config.first || Config.new)
|
12
|
+
OSA::AuthService.login(OSA::Config.first || OSA::Config.new)
|
12
13
|
when 'scan-junk'
|
13
14
|
require 'osa/scripts/scan_junk_folder'
|
14
15
|
when 'scan-report'
|
data/lib/osa.rb
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'osa/version'
|
@@ -15,6 +15,11 @@ module OSA
|
|
15
15
|
handle_response(response)
|
16
16
|
end
|
17
17
|
|
18
|
+
def put(*args, **kwargs)
|
19
|
+
response = @connection.put(*args, **kwargs)
|
20
|
+
handle_response(response)
|
21
|
+
end
|
22
|
+
|
18
23
|
def delete(*args, **kwargs)
|
19
24
|
response = @connection.delete(*args, **kwargs)
|
20
25
|
handle_response(response)
|
@@ -31,7 +36,7 @@ module OSA
|
|
31
36
|
if response.status > 299
|
32
37
|
raise StandardError, "Request failed with status code: #{response.status}, body: #{response.body}"
|
33
38
|
end
|
34
|
-
if response.headers['content-type']
|
39
|
+
if response.headers['content-type']&.include?('application/json')
|
35
40
|
JSON.parse(response.body)
|
36
41
|
else
|
37
42
|
response.body
|
@@ -4,43 +4,49 @@ require 'json'
|
|
4
4
|
require 'base64'
|
5
5
|
require 'osa/util/paginated'
|
6
6
|
require 'osa/clients/http_client'
|
7
|
+
require 'active_support/core_ext/numeric/bytes'
|
8
|
+
require 'active_support'
|
7
9
|
|
8
10
|
module OSA
|
9
|
-
class MSGraphClient
|
11
|
+
class MSGraphClient
|
12
|
+
URL = 'https://graph.microsoft.com'
|
13
|
+
|
10
14
|
def initialize(token)
|
11
|
-
|
15
|
+
@authenticated = HttpClient.new(Faraday.new(
|
12
16
|
url: 'https://graph.microsoft.com',
|
13
17
|
headers: {
|
14
18
|
'authorization' => "Bearer #{token}"
|
15
19
|
}
|
16
|
-
)
|
17
|
-
|
20
|
+
))
|
21
|
+
|
22
|
+
@unauthenticated = HttpClient.new(Faraday.new(
|
23
|
+
url: 'https://graph.microsoft.com'
|
24
|
+
))
|
18
25
|
end
|
19
26
|
|
20
27
|
def rules
|
21
|
-
get('/v1.0/me/mailFolders/inbox/messageRules')
|
28
|
+
@authenticated.get('/v1.0/me/mailFolders/inbox/messageRules')
|
22
29
|
end
|
23
30
|
|
24
31
|
def rule(id)
|
25
|
-
get("/v1.0/me/mailFolders/inbox/messageRules/#{id}")
|
32
|
+
@authenticated.get("/v1.0/me/mailFolders/inbox/messageRules/#{id}")
|
26
33
|
end
|
27
34
|
|
28
35
|
def folders
|
29
|
-
Paginated.new(get('/v1.0/me/mailFolders'), self)
|
36
|
+
Paginated.new(@authenticated.get('/v1.0/me/mailFolders'), self)
|
30
37
|
end
|
31
38
|
|
32
39
|
def mails(folder_id)
|
33
|
-
Paginated.new(get("/v1.0/me/mailFolders/#{folder_id}/messages"), self)
|
40
|
+
Paginated.new(@authenticated.get("/v1.0/me/mailFolders/#{folder_id}/messages"), self)
|
34
41
|
end
|
35
42
|
|
36
43
|
def raw_mail(mail_id)
|
37
|
-
get("/v1.0/me/messages/#{mail_id}/$value")
|
44
|
+
@authenticated.get("/v1.0/me/messages/#{mail_id}/$value")
|
38
45
|
end
|
39
46
|
|
40
47
|
def forward_mail_as_attachment(mail_id, to)
|
41
48
|
raw_mail = self.raw_mail(mail_id)
|
42
49
|
forward_message = create_forward_message(mail_id)
|
43
|
-
add_email_attachment(forward_message['id'], raw_mail)
|
44
50
|
update = {
|
45
51
|
toRecipients: [
|
46
52
|
{
|
@@ -51,36 +57,68 @@ module OSA
|
|
51
57
|
]
|
52
58
|
}
|
53
59
|
update_message(forward_message['id'], update)
|
60
|
+
add_email_attachment(forward_message['id'], 'email.eml', raw_mail)
|
54
61
|
send_message(forward_message['id'])
|
55
62
|
end
|
56
63
|
|
57
64
|
def create_forward_message(mail_id)
|
58
|
-
post("/v1.0/me/messages/#{mail_id}/createForward")
|
65
|
+
@authenticated.post("/v1.0/me/messages/#{mail_id}/createForward")
|
59
66
|
end
|
60
67
|
|
61
|
-
def add_email_attachment(mail_id, content)
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
post("/v1.0/me/messages/#{mail_id}/attachments", body.to_json, 'content-type': 'application/json')
|
68
|
+
def add_email_attachment(mail_id, name, content)
|
69
|
+
if content.length < 3.megabytes
|
70
|
+
add_small_email_attachment(mail_id, name, content)
|
71
|
+
else
|
72
|
+
add_large_email_attachment(mail_id, name, content)
|
73
|
+
end
|
68
74
|
end
|
69
75
|
|
70
76
|
def delete_mail(mail_id)
|
71
|
-
delete("/v1.0/me/messages/#{mail_id}")
|
77
|
+
@authenticated.delete("/v1.0/me/messages/#{mail_id}")
|
72
78
|
end
|
73
79
|
|
74
80
|
def update_rule(id, update)
|
75
|
-
patch("/v1.0/me/mailFolders/inbox/messageRules/#{id}", update.to_json, 'content-type' => 'application/json')
|
81
|
+
@authenticated.patch("/v1.0/me/mailFolders/inbox/messageRules/#{id}", update.to_json, 'content-type' => 'application/json')
|
76
82
|
end
|
77
83
|
|
78
84
|
def update_message(id, update)
|
79
|
-
patch("/v1.0/me/messages/#{id}", update.to_json, 'content-type': 'application/json')
|
85
|
+
@authenticated.patch("/v1.0/me/messages/#{id}", update.to_json, 'content-type': 'application/json')
|
80
86
|
end
|
81
87
|
|
82
88
|
def send_message(id)
|
83
|
-
post("/v1.0/me/messages/#{id}/send")
|
89
|
+
@authenticated.post("/v1.0/me/messages/#{id}/send")
|
84
90
|
end
|
91
|
+
|
92
|
+
private
|
93
|
+
def add_small_email_attachment(mail_id, name, content)
|
94
|
+
body = {
|
95
|
+
"@odata.type": '#microsoft.graph.fileAttachment',
|
96
|
+
contentBytes: Base64.encode64(content),
|
97
|
+
name: name
|
98
|
+
}
|
99
|
+
@authenticated.post("/v1.0/me/messages/#{mail_id}/attachments", body.to_json, 'content-type': 'application/json')
|
100
|
+
end
|
101
|
+
|
102
|
+
def add_large_email_attachment(mail_id, name, content)
|
103
|
+
upload_session = create_upload_session(mail_id, name, content.length)
|
104
|
+
ranges = upload_session['nextExpectedRanges'].map do |range|
|
105
|
+
range.split('-').then { |start, finish| (start.to_i..finish&.to_i) }
|
106
|
+
end
|
107
|
+
ranges.each do |range|
|
108
|
+
current_content = content[range]
|
109
|
+
@unauthenticated.put(upload_session['uploadUrl'], current_content[range], 'Content-Range': "bytes #{range.begin}-#{(range.end || content.length) - 1}/#{content.length}")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def create_upload_session(mail_id, name, size)
|
114
|
+
body = {
|
115
|
+
AttachmentItem: {
|
116
|
+
attachmentType: :file,
|
117
|
+
name: name,
|
118
|
+
size: size
|
119
|
+
}
|
120
|
+
}
|
121
|
+
@authenticated.post("/v1.0/me/messages/#{mail_id}/attachments/createUploadSession", body.to_json, 'content-type': 'application/json')
|
122
|
+
end
|
85
123
|
end
|
86
124
|
end
|
@@ -39,7 +39,7 @@ module OSA
|
|
39
39
|
base_uri = 'https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize'
|
40
40
|
|
41
41
|
uri = "#{base_uri}#{query_str}"
|
42
|
-
puts
|
42
|
+
puts 'Open the following url in your browser and enter the authentication code displayed.'
|
43
43
|
puts uri
|
44
44
|
|
45
45
|
prompt = TTY::Prompt.new
|
data/lib/osa/util/constants.rb
CHANGED
@@ -3,5 +3,5 @@
|
|
3
3
|
module OSA
|
4
4
|
CLIENT_ID = 'befa4a9e-5d16-4a48-9792-4bd1d125abe8'
|
5
5
|
REDIRECT_URL = 'https://storage.googleapis.com/outlook-spam-automator/login.html'
|
6
|
-
SCOPE = 'https://graph.microsoft.com/
|
6
|
+
SCOPE = 'https://graph.microsoft.com/Mail.ReadWrite https://graph.microsoft.com/MailboxSettings.ReadWrite offline_access'
|
7
7
|
end
|
data/lib/osa/util/context.rb
CHANGED
data/lib/osa/util/db.rb
CHANGED
@@ -5,10 +5,9 @@ ActiveRecord::Base.establish_connection(
|
|
5
5
|
adapter: 'sqlite3',
|
6
6
|
database: ENV['DATABASE'] || "#{Dir.pwd}/osa.db"
|
7
7
|
)
|
8
|
-
root = "#{File.dirname(__FILE__
|
8
|
+
root = "#{File.dirname(__FILE__)}/../"
|
9
9
|
ActiveRecord::MigrationContext.new("#{root}/migrations", ActiveRecord::SchemaMigration).migrate
|
10
10
|
|
11
|
-
|
12
11
|
module OSA
|
13
12
|
class Blacklist < ActiveRecord::Base
|
14
13
|
end
|
data/lib/osa/version.rb
CHANGED
data/osa.gemspec
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require_relative 'lib/osa/version'
|
2
3
|
|
3
4
|
Gem::Specification.new do |spec|
|
@@ -9,11 +10,11 @@ Gem::Specification.new do |spec|
|
|
9
10
|
spec.summary = 'Outlook Spam Automator'
|
10
11
|
spec.description = 'Get rid of spam on your Outlook account'
|
11
12
|
spec.license = 'MIT'
|
12
|
-
spec.required_ruby_version = Gem::Requirement.new(
|
13
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')
|
13
14
|
|
14
15
|
# Specify which files should be added to the gem when it is released.
|
15
16
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
16
|
-
spec.files
|
17
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
17
18
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
19
|
end
|
19
20
|
spec.bindir = 'exe'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: osa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Moray Baruh
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-11-
|
11
|
+
date: 2020-11-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -98,6 +98,7 @@ files:
|
|
98
98
|
- README.md
|
99
99
|
- Rakefile
|
100
100
|
- bin/console
|
101
|
+
- bin/osa
|
101
102
|
- bin/setup
|
102
103
|
- exe/osa
|
103
104
|
- lib/osa.rb
|