magister 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: []