magister 1.0.0
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 +7 -0
- data/lib/magister/authenticator.rb +73 -0
- data/lib/magister/data.rb +22 -0
- data/lib/magister/profile.rb +82 -0
- data/lib/magister.rb +31 -0
- metadata +109 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8615e0de52da0b061810bd3ead80cb1be7c5c74b4cd019fa8adc378c2ed5ab3d
|
4
|
+
data.tar.gz: a3c20cfb453481be6079f14878e00e8d70ffe3c4b56769c5df0c79535547dd7c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a00609ba584cf34ccd127aa7f3d431856bf1e223e2bba6b7dafc3d752bca0972ac30664d8befa0a2e4db831678b684fdfaa1fa34e368f86c8dae4fb44a3f44ed
|
7
|
+
data.tar.gz: 68e5d06e95b52ebaad3c33ce98266d2e1967eb63f0e5efdce94dda66eaeae538290360a8273ae0596a3e10f01d9cf5eb77dd4c711f3127756d193c2302f43d15
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
2
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
3
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
4
|
+
require './lib/magister/profile.rb'
|
5
|
+
require 'net/http'
|
6
|
+
require 'json'
|
7
|
+
require 'securerandom'
|
8
|
+
require 'base64'
|
9
|
+
require 'digest'
|
10
|
+
require 'selenium-webdriver'
|
11
|
+
|
12
|
+
module Authenticator
|
13
|
+
extend self
|
14
|
+
|
15
|
+
def login(username, password, school)
|
16
|
+
# uri = URI("https://#{school}.magister.net/oidc_config.js")
|
17
|
+
# http = Net::HTTP.new(uri.host, uri.port)
|
18
|
+
# http.use_ssl = true
|
19
|
+
# request = Net::HTTP::Get.new(uri.request_uri)
|
20
|
+
# response = http.request(request)
|
21
|
+
# oidc_conf = (response.body.split("config =").last.split("};").first.gsub("window.location.hostname", "'" + uri.hostname + "'") + "}").gsub(': ', '":').gsub(/,(\s*)/, ',"').gsub(/{(\s*)/, '{"').gsub("'", '"').gsub('" + "', "")
|
22
|
+
|
23
|
+
# oidc_conf = JSON.parse(oidc_conf)
|
24
|
+
|
25
|
+
codeVerifier = SecureRandom.alphanumeric(128)
|
26
|
+
verifier = Base64.urlsafe_encode64(codeVerifier)
|
27
|
+
|
28
|
+
rawChallenge = Digest::SHA256.hexdigest verifier
|
29
|
+
challenge = Base64.urlsafe_encode64(rawChallenge)
|
30
|
+
|
31
|
+
@@state = SecureRandom.hex(16)
|
32
|
+
@@nonce = SecureRandom.hex(16)
|
33
|
+
|
34
|
+
auth_uri = "https://#{school}.magister.net/connect/authorize?client_id=M6LOAPP&redirect_uri=m6loapp%3A%2F%2Foauth2redirect%2F&scope=openid%20profile%20opp.read%20opp.manage%20attendance.overview%20attendance.administration%20calendar.ical.user%20calendar.to-do.user%20grades.read%20grades.manage&state=#{@@state}&nonce=#{@@nonce}&code_challenge=#{challenge}&code_challenge_method=S256&prompt=select_account"
|
35
|
+
# puts "using authentication url #{auth_uri}"
|
36
|
+
|
37
|
+
if $authMode == "local"
|
38
|
+
raise NotImplementedError.new("\n\nLocal authentication mode has not been implemented yet, \nCheck our github for any updates, or if you want to help implementing it!\n")
|
39
|
+
else
|
40
|
+
puts "Using Selenium with Chrome for authentication."
|
41
|
+
options = Selenium::WebDriver::Options.chrome(args: ['--headless=new'])
|
42
|
+
driver = Selenium::WebDriver.for :chrome, options: options
|
43
|
+
|
44
|
+
driver.get auth_uri
|
45
|
+
while !driver.current_url.start_with? "https://accounts.magister.net/account/login"
|
46
|
+
sleep(0.5)
|
47
|
+
# puts "waiting for load..."
|
48
|
+
end
|
49
|
+
sleep(3)
|
50
|
+
|
51
|
+
username_field = driver.find_element(id: 'username')
|
52
|
+
username_field.send_keys(username)
|
53
|
+
go_to_password_button = driver.find_element(id: 'username_submit')
|
54
|
+
go_to_password_button.click
|
55
|
+
|
56
|
+
sleep(1)
|
57
|
+
|
58
|
+
password_field = driver.find_element(id: 'password')
|
59
|
+
password_field.send_keys(password)
|
60
|
+
signin_button = driver.find_element(id: 'password_submit')
|
61
|
+
signin_button.click
|
62
|
+
|
63
|
+
wait = Selenium::WebDriver::Wait.new(timeout: 30)
|
64
|
+
wait.until { driver.current_url.start_with? "https://#{school}.magister.net/oidc/redirect_callback.html" }
|
65
|
+
|
66
|
+
token = driver.current_url.split("access_token=").last.split("&").first
|
67
|
+
|
68
|
+
driver.quit
|
69
|
+
|
70
|
+
return Profile.new(token, school)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
2
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
3
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
4
|
+
require 'date'
|
5
|
+
|
6
|
+
def validate_date(date)
|
7
|
+
format = '%Y-%m-%d'
|
8
|
+
DateTime.strptime(date, format)
|
9
|
+
true
|
10
|
+
rescue ArgumentError
|
11
|
+
false
|
12
|
+
end
|
13
|
+
|
14
|
+
module MagisterData
|
15
|
+
def get_classes(dateFrom, dateTo)
|
16
|
+
if validate_date(dateFrom) && validate_date(dateTo)
|
17
|
+
@profile.authenticatedRequest("/personen/{*id*}/afspraken?status=1&van=#{dateFrom}&tot=#{dateTo}")
|
18
|
+
else
|
19
|
+
puts "Invalid date, Format is yyyy-mm-dd"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
2
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
3
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
4
|
+
require 'uri'
|
5
|
+
require 'net/http'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
class Profile
|
9
|
+
def initialize(token, school)
|
10
|
+
@token = token
|
11
|
+
@id = 0
|
12
|
+
@school = school
|
13
|
+
@person = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def token=(token)
|
17
|
+
@token=token
|
18
|
+
end
|
19
|
+
def id
|
20
|
+
@id
|
21
|
+
end
|
22
|
+
def school
|
23
|
+
@school
|
24
|
+
end
|
25
|
+
def inspect
|
26
|
+
"#<#{self.class}:0x#{object_id} @token=\"[PRIVATE]\", @id=#{@id}, @school=#{@school}>"
|
27
|
+
end
|
28
|
+
|
29
|
+
def person
|
30
|
+
@person
|
31
|
+
end
|
32
|
+
|
33
|
+
def verify()
|
34
|
+
if @school == nil || @token == nil
|
35
|
+
puts "Either school or token was not defined!"
|
36
|
+
end
|
37
|
+
puts "authenticating to #{@school}..."
|
38
|
+
uri = URI("https://#{@school}.magister.net/api/account")
|
39
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
40
|
+
http.use_ssl = true
|
41
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
42
|
+
request['authorization'] = "Bearer #{@token}"
|
43
|
+
|
44
|
+
begin
|
45
|
+
response = http.request(request)
|
46
|
+
if response.is_a?(Net::HTTPSuccess)
|
47
|
+
res = JSON.parse(response.body)
|
48
|
+
@person = res["Persoon"]
|
49
|
+
@id = person["Id"].to_i
|
50
|
+
puts "Succesfully authenticated as #{@person["Roepnaam"]} with id #{@person["Id"]}"
|
51
|
+
else
|
52
|
+
puts "Failed to authenticate, http code #{response.code}"
|
53
|
+
end
|
54
|
+
rescue StandardError => e
|
55
|
+
puts "An error occurred #{e}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def authenticatedRequest(endpoint)
|
60
|
+
if @id == 0
|
61
|
+
puts "Not yet authenticated!"
|
62
|
+
self.verify()
|
63
|
+
end
|
64
|
+
uri = URI("https://#{@school}.magister.net/api#{endpoint}".gsub("{*id*}", @id.to_s))
|
65
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
66
|
+
http.use_ssl = true
|
67
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
68
|
+
request['authorization'] = "Bearer #{@token}"
|
69
|
+
|
70
|
+
begin
|
71
|
+
response = http.request(request)
|
72
|
+
if response.is_a?(Net::HTTPSuccess)
|
73
|
+
return JSON.parse(response.body)
|
74
|
+
else
|
75
|
+
puts "failed to get #{endpoint}, status code #{response.code}"
|
76
|
+
return nil
|
77
|
+
end
|
78
|
+
rescue StandardError => e
|
79
|
+
puts "An error occurred #{e}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/magister.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
2
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
3
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
4
|
+
require './lib/magister/profile.rb'
|
5
|
+
require './lib/magister/data.rb'
|
6
|
+
require './lib/magister/authenticator.rb'
|
7
|
+
|
8
|
+
# can be either "selenium" or "local"
|
9
|
+
# "selenium" will run headlessly
|
10
|
+
# "local" will open a browser window for the user to login
|
11
|
+
$authMode = "selenium"
|
12
|
+
|
13
|
+
class Magister
|
14
|
+
include MagisterData
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@profile = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def authenticate(school, token)
|
21
|
+
@profile = Profile.new(token, school)
|
22
|
+
@profile.verify
|
23
|
+
end
|
24
|
+
def login(school, username, password)
|
25
|
+
@profile = Authenticator.login(username, password, school)
|
26
|
+
end
|
27
|
+
|
28
|
+
def profile
|
29
|
+
@profile
|
30
|
+
end
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: magister
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Riley0122
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-02-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.7'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 2.7.1
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.7'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 2.7.1
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: securerandom
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 0.3.1
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 0.3.1
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: base64
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.2.0
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 0.2.0
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: selenium-webdriver
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '4.17'
|
68
|
+
type: :runtime
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '4.17'
|
75
|
+
description: An unofficial Magister API wrapper for ruby
|
76
|
+
email: contact@riley0122.dev
|
77
|
+
executables: []
|
78
|
+
extensions: []
|
79
|
+
extra_rdoc_files: []
|
80
|
+
files:
|
81
|
+
- lib/magister.rb
|
82
|
+
- lib/magister/authenticator.rb
|
83
|
+
- lib/magister/data.rb
|
84
|
+
- lib/magister/profile.rb
|
85
|
+
homepage: https://github.com/riley0122/rubymag#readme
|
86
|
+
licenses:
|
87
|
+
- MPL-2.0
|
88
|
+
metadata:
|
89
|
+
source_code_uri: https://github.com/riley0122/rubymag
|
90
|
+
post_install_message:
|
91
|
+
rdoc_options: []
|
92
|
+
require_paths:
|
93
|
+
- lib
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
requirements: []
|
105
|
+
rubygems_version: 3.4.10
|
106
|
+
signing_key:
|
107
|
+
specification_version: 4
|
108
|
+
summary: Magister API wrapper
|
109
|
+
test_files: []
|