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 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: []