adsedare_mattermost 0.0.2 → 0.0.3
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/LICENSE.txt +21 -0
- data/README.md +33 -0
- data/Rakefile +4 -0
- data/adsedare_mattermost.gemspec +30 -0
- data/lib/adsedare_mattermost/version.rb +5 -0
- data/lib/adsedare_mattermost.rb +134 -0
- metadata +17 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 910c2116de9894ffb0f2d69ee48c003248d52365d0116c14a20728ad13998098
|
4
|
+
data.tar.gz: 25d14bdd3d61ef71cfedfe2d5a9224b344e523c7f9151712fadbd1e1e618441a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73aae8a481990d322b960edc67cc1df6788107d2bc46850ea2e39d8ca1eae671db9c186e5c971de49336da0fe0ceece5d7415724273d8c1f1a765ce00c47e981
|
7
|
+
data.tar.gz: d7ad2c2e732bb15c1db8b50532b3a149261ab1be3b9cb272598a24f4d5e923bbbaeec04e004cb8c8f5704a141f7ffb226bc45a716a1e21f4a6413dbc16ee72cb
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2025 alexstrnik
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# AdSedareMattermost
|
2
|
+
|
3
|
+
AdSedareMattermost is a two-factor authentication provider for Adsedare that uses Mattermost to receive the 2FA code. It expects a lambda function that will extract the 2FA code from the array fo latest messages. This way it can be used with any SMS relay bots. It will wait for the 2FA code for a specified amount of time and retry if lambda function does not return a value.
|
4
|
+
|
5
|
+
## Configuration
|
6
|
+
|
7
|
+
```bash
|
8
|
+
export ADSEDARE_MM_TOKEN="mrm_your_bot_token"
|
9
|
+
export ADSEDARE_MM_HOST="https://your_mattermost_instance.com"
|
10
|
+
|
11
|
+
export ADSEDARE_MM_TEAM_ID="your_team_id"
|
12
|
+
# or
|
13
|
+
export ADSEDARE_MM_TEAM_NAME="Your Team Name"
|
14
|
+
|
15
|
+
export ADSEDARE_MM_CHANNEL_ID="your_channel_id"
|
16
|
+
# or
|
17
|
+
export ADSEDARE_MM_CHANNEL_NAME="Your Channel Name"
|
18
|
+
|
19
|
+
export ADSEDARE_MM_TIMEOUT_SECONDS="5" # How many seconds to wait for the 2FA code
|
20
|
+
export ADSEDARE_MM_RETRY_LIMIT="5" # How many times to retry
|
21
|
+
```
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
# TODO: Update after Adsedare release
|
27
|
+
provider = AdsedareMattermost::Provider.new(
|
28
|
+
lambda do |messages|
|
29
|
+
messages.last.match(/\d{6}/).to_s
|
30
|
+
end
|
31
|
+
)
|
32
|
+
Starship::set_provider(provider)
|
33
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/adsedare_mattermost/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "adsedare_mattermost"
|
7
|
+
spec.version = AdsedareMattermost::VERSION
|
8
|
+
spec.authors = ["alexstrnik"]
|
9
|
+
spec.email = ["alex.str.nik@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = "AdSedare 2FA Provider via Mattermost bot"
|
12
|
+
spec.description = "AdSedare 2FA Provider via Mattermost bot"
|
13
|
+
spec.homepage = "https://github.com/AlexStrNik/AdsedareMattermost"
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.required_ruby_version = ">= 2.6.0"
|
16
|
+
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
18
|
+
spec.metadata["source_code_uri"] = "https://github.com/AlexStrNik/AdsedareMattermost"
|
19
|
+
|
20
|
+
spec.files = Dir.chdir(__dir__) do
|
21
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
22
|
+
(File.expand_path(f) == __FILE__) ||
|
23
|
+
f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor Gemfile])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
spec.require_paths = ["lib"]
|
27
|
+
|
28
|
+
spec.add_dependency "adsedare", "~> 0.0.6"
|
29
|
+
spec.add_dependency "faraday", "~> 2.7"
|
30
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "adsedare"
|
4
|
+
require "faraday"
|
5
|
+
|
6
|
+
require_relative "adsedare_mattermost/version"
|
7
|
+
|
8
|
+
module AdsedareMattermost
|
9
|
+
class Error < StandardError; end
|
10
|
+
|
11
|
+
class Provider < Starship::TwoFactorProvider
|
12
|
+
include Logging
|
13
|
+
|
14
|
+
def initialize(
|
15
|
+
extract_2fa_code = nil
|
16
|
+
)
|
17
|
+
@extract_2fa_code = extract_2fa_code
|
18
|
+
unless @extract_2fa_code
|
19
|
+
raise Error, "Pass extract_2fa_code block"
|
20
|
+
end
|
21
|
+
|
22
|
+
@token = ENV["ADSEDARE_MM_TOKEN"]
|
23
|
+
@mm_host = ENV["ADSEDARE_MM_HOST"]
|
24
|
+
|
25
|
+
@team_id = ENV["ADSEDARE_MM_TEAM_ID"]
|
26
|
+
team_name = ENV["ADSEDARE_MM_TEAM_NAME"]
|
27
|
+
|
28
|
+
@channel_id = ENV["ADSEDARE_MM_CHANNEL_ID"]
|
29
|
+
channel_name = ENV["ADSEDARE_MM_CHANNEL_NAME"]
|
30
|
+
|
31
|
+
unless @token
|
32
|
+
raise Error, "ADSEDARE_MM_TOKEN is not set"
|
33
|
+
end
|
34
|
+
|
35
|
+
unless @mm_host
|
36
|
+
raise Error, "ADSEDARE_MM_HOST is not set"
|
37
|
+
end
|
38
|
+
|
39
|
+
unless team_name || @team_id
|
40
|
+
raise Error, "ADSEDARE_MM_TEAM_NAME and ADSEDARE_MM_TEAM_ID is not set"
|
41
|
+
end
|
42
|
+
|
43
|
+
unless @team_id
|
44
|
+
logger.warn "ADSEDARE_MM_TEAM_ID is not set, will find by name: #{team_name}"
|
45
|
+
@team_id = my_teams.find { |team| team["display_name"] == team_name }["id"]
|
46
|
+
raise Error, "Team #{team_name} not found" unless @team_id
|
47
|
+
logger.info "Using team: #{@team_id}"
|
48
|
+
end
|
49
|
+
|
50
|
+
unless channel_name || @channel_id
|
51
|
+
raise Error, "ADSEDARE_MM_CHANNEL_NAME and ADSEDARE_MM_CHANNEL_ID is not set"
|
52
|
+
end
|
53
|
+
|
54
|
+
unless @channel_id
|
55
|
+
logger.warn "ADSEDARE_MM_CHANNEL_ID is not set, will find by name: #{channel_name}"
|
56
|
+
@channel_id = my_channels.find { |channel| channel["display_name"] == channel_name }["id"]
|
57
|
+
raise Error, "Channel #{channel_name} not found" unless @channel_id
|
58
|
+
logger.info "Using channel: #{@channel_id}"
|
59
|
+
end
|
60
|
+
|
61
|
+
@timeout_seconds = ENV["ADSEDARE_MM_TIMEOUT_SECONDS"] || 5
|
62
|
+
@retry_limit = ENV["ADSEDARE_MM_RETRY_LIMIT"] || 5
|
63
|
+
@since = Time.now
|
64
|
+
|
65
|
+
@retry_counter = 0
|
66
|
+
end
|
67
|
+
|
68
|
+
def my_teams
|
69
|
+
response = Faraday.get("#{@mm_host}/api/v4/users/me/teams") do |req|
|
70
|
+
req.headers["Authorization"] = "Bearer #{@token}"
|
71
|
+
end
|
72
|
+
raise Error, "Failed to get teams" unless response.success?
|
73
|
+
|
74
|
+
JSON.parse(response.body)
|
75
|
+
end
|
76
|
+
|
77
|
+
def my_channels
|
78
|
+
response = Faraday.get("#{@mm_host}/api/v4/users/me/teams/#{@team_id}/channels") do |req|
|
79
|
+
req.headers["Authorization"] = "Bearer #{@token}"
|
80
|
+
end
|
81
|
+
raise Error, "Failed to get channels" unless response.success?
|
82
|
+
|
83
|
+
JSON.parse(response.body)
|
84
|
+
end
|
85
|
+
|
86
|
+
def latest_posts
|
87
|
+
response = Faraday.get("#{@mm_host}/api/v4/channels/#{@channel_id}/posts?since=#{@since.to_i}") do |req|
|
88
|
+
req.headers["Authorization"] = "Bearer #{@token}"
|
89
|
+
end
|
90
|
+
raise Error, "Failed to get messages" unless response.success?
|
91
|
+
|
92
|
+
JSON.parse(response.body)["posts"]
|
93
|
+
end
|
94
|
+
|
95
|
+
def retry_get_code
|
96
|
+
if @retry_counter > @retry_limit
|
97
|
+
return nil
|
98
|
+
end
|
99
|
+
|
100
|
+
logger.info "Retry #{@retry_counter} of #{@retry_limit}"
|
101
|
+
logger.info "Waiting for #{@timeout_seconds} seconds for 2FA code..."
|
102
|
+
|
103
|
+
sleep(@timeout_seconds)
|
104
|
+
|
105
|
+
# Update before request, since we dont want to miss messages due to any network delays
|
106
|
+
new_since = (Time.now.to_f * 1000).to_i
|
107
|
+
|
108
|
+
latest_messages = latest_posts.values.map { |post| post["message"] }
|
109
|
+
code = @extract_2fa_code.call(latest_messages)
|
110
|
+
|
111
|
+
@since = new_since
|
112
|
+
@retry_counter += 1
|
113
|
+
|
114
|
+
return code if code
|
115
|
+
|
116
|
+
retry_get_code
|
117
|
+
end
|
118
|
+
|
119
|
+
def get_code(session_id, scnt)
|
120
|
+
@retry_counter = 1
|
121
|
+
# Just to be sure we dont miss messages because Apple sends it before we got there
|
122
|
+
@since = (Time.now.to_f * 1000).to_i - 3000
|
123
|
+
|
124
|
+
code = retry_get_code
|
125
|
+
|
126
|
+
return code if code
|
127
|
+
raise Error, "2FA code not found"
|
128
|
+
end
|
129
|
+
|
130
|
+
def can_handle?(type)
|
131
|
+
true
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
metadata
CHANGED
@@ -1,28 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: adsedare_mattermost
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- alexstrnik
|
8
|
+
autorequire:
|
8
9
|
bindir: bin
|
9
10
|
cert_chain: []
|
10
|
-
date: 2025-05-
|
11
|
+
date: 2025-05-27 00:00:00.000000000 Z
|
11
12
|
dependencies:
|
12
13
|
- !ruby/object:Gem::Dependency
|
13
14
|
name: adsedare
|
14
15
|
requirement: !ruby/object:Gem::Requirement
|
15
16
|
requirements:
|
16
|
-
- - "
|
17
|
+
- - "~>"
|
17
18
|
- !ruby/object:Gem::Version
|
18
|
-
version:
|
19
|
+
version: 0.0.6
|
19
20
|
type: :runtime
|
20
21
|
prerelease: false
|
21
22
|
version_requirements: !ruby/object:Gem::Requirement
|
22
23
|
requirements:
|
23
|
-
- - "
|
24
|
+
- - "~>"
|
24
25
|
- !ruby/object:Gem::Version
|
25
|
-
version:
|
26
|
+
version: 0.0.6
|
26
27
|
- !ruby/object:Gem::Dependency
|
27
28
|
name: faraday
|
28
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -43,13 +44,20 @@ email:
|
|
43
44
|
executables: []
|
44
45
|
extensions: []
|
45
46
|
extra_rdoc_files: []
|
46
|
-
files:
|
47
|
+
files:
|
48
|
+
- LICENSE.txt
|
49
|
+
- README.md
|
50
|
+
- Rakefile
|
51
|
+
- adsedare_mattermost.gemspec
|
52
|
+
- lib/adsedare_mattermost.rb
|
53
|
+
- lib/adsedare_mattermost/version.rb
|
47
54
|
homepage: https://github.com/AlexStrNik/AdsedareMattermost
|
48
55
|
licenses:
|
49
56
|
- MIT
|
50
57
|
metadata:
|
51
58
|
homepage_uri: https://github.com/AlexStrNik/AdsedareMattermost
|
52
59
|
source_code_uri: https://github.com/AlexStrNik/AdsedareMattermost
|
60
|
+
post_install_message:
|
53
61
|
rdoc_options: []
|
54
62
|
require_paths:
|
55
63
|
- lib
|
@@ -64,7 +72,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
64
72
|
- !ruby/object:Gem::Version
|
65
73
|
version: '0'
|
66
74
|
requirements: []
|
67
|
-
rubygems_version: 3.
|
75
|
+
rubygems_version: 3.0.3.1
|
76
|
+
signing_key:
|
68
77
|
specification_version: 4
|
69
78
|
summary: AdSedare 2FA Provider via Mattermost bot
|
70
79
|
test_files: []
|