miwifi 0.2.0.pre.beta

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: fb6ea39da161011ec13fa9ab16071be68d9533ad2a61f9bdca9e8723dbb1bd70
4
+ data.tar.gz: d57fccbfb3e61ab20dd9ee83256d43c9ebb5f90c6270ed2d4818aa3e8b31a46f
5
+ SHA512:
6
+ metadata.gz: eeb32818d0467e035b0d1439d2e92d03e2117f6f5787f1593405c9a1f19e1d107aede1faf6e8928feb006d40fc71d59fe8d6739649e7e4dd6eb9b48cfa09778d
7
+ data.tar.gz: 353743986d173732d4e6fecf8c1c19fae9bc3251a88c168caee7fc887a6abf6afd1194f1296f1cab4d60f3c65d62adf93d201408fe3df243fcdaef0057c70c2d
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ /.gem
10
+ *.bin
11
+ *.lock
12
+ *.gem
13
+ .idea
data/.rubocop.yml ADDED
@@ -0,0 +1,20 @@
1
+ Layout/IndentationStyle:
2
+ Enabled: false
3
+ Layout/IndentationWidth:
4
+ Enabled: false
5
+ Layout/FirstHashElementIndentation:
6
+ Enabled: false
7
+ Layout/LineLength:
8
+ Enabled: false
9
+ Layout/ArgumentAlignment:
10
+ Enabled: false
11
+ Layout/FirstArrayElementIndentation:
12
+ Enabled: false
13
+ Style/NumericLiterals:
14
+ Enabled: false
15
+ Style/AndOr:
16
+ Enabled: false
17
+ Metrics/BlockLength:
18
+ Enabled: false
19
+ Metrics/MethodLength:
20
+ Enabled: false
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ # Handcrafted by Aydar N.
2
+ # 2022 - 2023
3
+ #
4
+ # me@aydar.media
5
+ #
6
+
7
+ # frozen_string_literal: true
8
+
9
+ source 'https://rubygems.org'
10
+
11
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
12
+
13
+ # Specify your gem's dependencies in miwifi.gemspec
14
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Boost Software License - Version 1.0 - August 17th, 2003
2
+
3
+ Permission is hereby granted, free of charge, to any person or organization
4
+ obtaining a copy of the software and accompanying documentation covered by
5
+ this license (the "Software") to use, reproduce, display, distribute,
6
+ execute, and transmit the Software, and to prepare derivative works of the
7
+ Software, and to permit third-parties to whom the Software is furnished to
8
+ do so, all subject to the following:
9
+
10
+ The copyright notices in the Software and this entire statement, including
11
+ the above license grant, this restriction and the following disclaimer,
12
+ must be included in all copies of the Software, in whole or in part, and
13
+ all derivative works of the Software, unless such copies or derivative
14
+ works are solely in the form of machine-executable object code generated by
15
+ a source language processor.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
20
+ SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
21
+ FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
22
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,23 @@
1
+ # Miwifi
2
+ With miwifi authenticating to your Mi router and getting list of connected devices is as simple as that:
3
+ ```ruby
4
+ router = Miwifi::Router.new("192.168.31.1", "password")
5
+ router.auth
6
+ devices = router.device_list
7
+ ```
8
+
9
+ ## Installation
10
+ 1. [Authenticate](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-rubygems-registry#authenticating-to-github-packages) to GitHub Packages
11
+
12
+ 2. Add these lines to your application's Gemfile:
13
+ ```ruby
14
+ source "https://rubygems.pkg.github.com/lesterrry" do
15
+ gem "miwifi"
16
+ end
17
+ ```
18
+
19
+ ## Development
20
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
21
+
22
+ ## Support
23
+ - Xiaomi Router 3 (R3)
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ # Handcrafted by Aydar N.
2
+ # 2023
3
+ #
4
+ # me@aydar.media
5
+ #
6
+
7
+ # frozen_string_literal: true
8
+
9
+ require 'bundler/gem_tasks'
10
+ require 'rake/testtask'
11
+
12
+ Rake::TestTask.new(:test) do |t|
13
+ t.libs << 'test'
14
+ t.libs << 'lib'
15
+ t.test_files = FileList['test/**/*_test.rb'].exclude('test/**/*_bench_test.rb')
16
+ end
17
+
18
+ desc 'Run all tests'
19
+ task default: :test
data/bin/console ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # COPYRIGHT LESTER COVEY,
4
+ #
5
+ # 2022
6
+
7
+ require "bundler/setup"
8
+ require "miwifi"
9
+
10
+ # You can add fixtures and/or initialization code here to make experimenting
11
+ # with your gem easier. You can also use a different console, if you like.
12
+
13
+ # (If you use this, don't forget to add pry to your Gemfile!)
14
+ # require "pry"
15
+ # Pry.start
16
+
17
+ require "irb"
18
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # COPYRIGHT LESTER COVEY,
4
+ #
5
+ # 2022
6
+
7
+ set -euo pipefail
8
+ IFS=$'\n\t'
9
+ set -vx
10
+
11
+ bundle install
12
+
13
+ # Do any other automated setup that you need to do here
data/lib/miwifi/api.rb ADDED
@@ -0,0 +1,44 @@
1
+ # Handcrafted by Aydar N.
2
+ # 2022-2023
3
+ #
4
+ # me@aydar.media
5
+ #
6
+
7
+ # frozen_string_literal: true
8
+
9
+ module Miwifi
10
+
11
+ class Router
12
+ def device_list
13
+ generic_api_request "http://#{@ip}/cgi-bin/luci/;stok=#{@token}/api/misystem/devicelist"
14
+ end
15
+
16
+ def reboot
17
+ generic_api_request "http://#{@ip}/cgi-bin/luci/;stok=#{@token}/api/misystem/reboot"
18
+ end
19
+
20
+ private
21
+
22
+ def generic_api_request(uri_string)
23
+ raise Miwifi::NoTokenError if @token.nil?
24
+
25
+ uri = URI.parse(uri_string)
26
+ r = Request.default(uri, false)
27
+ Request.json_make(r, uri)
28
+ end
29
+ end
30
+
31
+ class Request
32
+ def self.json_make(r, uri)
33
+ response = Net::HTTP.start(uri.hostname, uri.port) do |http|
34
+ http.request(r)
35
+ end
36
+ parsed = JSON.parse(response.body)
37
+ raise Miwifi::AccessDeniedError if parsed['code'] == 401
38
+ raise Miwifi::UnexpectedResponseCodeError if parsed['code'] != 0
39
+
40
+ parsed
41
+ end
42
+ end
43
+
44
+ end
@@ -0,0 +1,13 @@
1
+ # Handcrafted by Aydar N.
2
+ # 2022-2023
3
+ #
4
+ # me@aydar.media
5
+ #
6
+
7
+ # frozen_string_literal: true
8
+
9
+ class String
10
+ def between(start, finish)
11
+ self[/#{Regexp.escape(start)}(.*?)#{Regexp.escape(finish)}/m, 1]
12
+ end
13
+ end
@@ -0,0 +1,89 @@
1
+ # Handcrafted by Aydar N.
2
+ # 2022-2023
3
+ #
4
+ # me@aydar.media
5
+ #
6
+
7
+ # frozen_string_literal: true
8
+
9
+ require 'net/http'
10
+ require 'digest/sha1'
11
+ require 'uri'
12
+ require 'json'
13
+
14
+ module Miwifi
15
+
16
+ class Router
17
+ attr_reader :token
18
+
19
+ def initialize(ip, password, username = 'admin', token: nil)
20
+ @ip = ip
21
+ @password = password
22
+ @username = username
23
+ @token = token
24
+ end
25
+
26
+ def auth
27
+ uri = URI.parse("http://#{@ip}/cgi-bin/luci/web/home")
28
+ r = Net::HTTP::Get.new(uri)
29
+ response = Net::HTTP.start(uri.hostname, uri.port) do |http|
30
+ http.request(r)
31
+ end
32
+ # TODO: This is unsafe as hell but bruh nobody even pays me
33
+ key = response.body.between("key: '", "',")
34
+ # iv = response.body.between("iv: '", "',")
35
+ device_id = response.body.between("deviceId = '", "';")
36
+ time = Time.now.to_i
37
+ random = rand(1000..9000)
38
+ nonce = "0_#{device_id}_#{time}_#{random}"
39
+ pass = Digest::SHA1.hexdigest(nonce + Digest::SHA1.hexdigest(@password + key))
40
+ uri = URI.parse("http://#{@ip}/cgi-bin/luci/api/xqsystem/login")
41
+ r = Request.default(uri, true)
42
+ r.set_form_data(
43
+ 'logtype' => '2',
44
+ 'nonce' => nonce,
45
+ 'password' => pass,
46
+ 'username' => @username,
47
+ )
48
+ response = Net::HTTP.start(uri.hostname, uri.port) do |http|
49
+ http.request(r)
50
+ end
51
+ parsed = JSON.parse(response.body)
52
+ raise Miwifi::AccessDeniedError if parsed['code'] == 401
53
+ raise Miwifi::UnexpectedResponseCodeError if parsed['code'] != 0
54
+
55
+ @token = parsed['token']
56
+ end
57
+
58
+ def bury_token(file)
59
+ raise Miwifi::NoTokenError if @token.nil?
60
+
61
+ File.open(file, 'wb') do |f|
62
+ f.write(Marshal.dump(@token))
63
+ end
64
+ end
65
+
66
+ def restore_token(file)
67
+ file_data = File.read(file)
68
+ @token = Marshal.load(file_data)
69
+ end
70
+ end
71
+
72
+ class Request
73
+ def self.default(uri, post)
74
+ request = post ? Net::HTTP::Post.new(uri) : Net::HTTP::Get.new(uri)
75
+ request.content_type = 'application/x-www-form-urlencoded; charset=UTF-8' if post
76
+ request['Accept'] = '*/*'
77
+ request['Accept-Language'] = 'ru'
78
+ request['Host'] = uri.host
79
+ request['Origin'] = "http://#{uri.host}"
80
+ request['User-Agent'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Safari/605.1.15'
81
+ request['Connection'] = 'keep-alive'
82
+ request['Referer'] = "http://#{uri.host}/cgi-bin/luci/web"
83
+ request['Cookie'] = 'monitor_count=1'
84
+ request['X-Requested-With'] = 'XMLHttpRequest'
85
+ request
86
+ end
87
+ end
88
+
89
+ end
@@ -0,0 +1,11 @@
1
+ # Handcrafted by Aydar N.
2
+ # 2022-2023
3
+ #
4
+ # me@aydar.media
5
+ #
6
+
7
+ # frozen_string_literal: true
8
+
9
+ module Miwifi
10
+ VERSION = '0.2.0-beta'
11
+ end
data/lib/miwifi.rb ADDED
@@ -0,0 +1,37 @@
1
+ # Handcrafted by Aydar N.
2
+ # 2022-2023
3
+ #
4
+ # me@aydar.media
5
+ #
6
+
7
+ # frozen_string_literal: true
8
+
9
+ require_relative 'miwifi/version'
10
+ require_relative 'miwifi/extensions'
11
+ require_relative 'miwifi/router'
12
+ require_relative 'miwifi/api'
13
+
14
+ module Miwifi
15
+
16
+ class AccessDeniedError < StandardError
17
+ def initialize(msg = 'Access denied; check your credentials', exception_type = 'custom')
18
+ @exception_type = exception_type
19
+ super(msg)
20
+ end
21
+ end
22
+
23
+ class UnexpectedResponseCodeError < StandardError
24
+ def initialize(msg = 'Got unexpected response code. Please report this behavior', exception_type = 'custom')
25
+ @exception_type = exception_type
26
+ super(msg)
27
+ end
28
+ end
29
+
30
+ class NoTokenError < StandardError
31
+ def initialize(msg = 'You are unauthorized', exception_type = 'custom')
32
+ @exception_type = exception_type
33
+ super(msg)
34
+ end
35
+ end
36
+
37
+ end
data/miwifi.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'miwifi/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'miwifi'
9
+ spec.version = Miwifi::VERSION
10
+ spec.authors = ['Aydar N.']
11
+ spec.email = ['me@aydar.media']
12
+
13
+ spec.required_ruby_version = '>= 2.6.3'
14
+
15
+ spec.summary = 'API wrapper for MiWIFI routers'
16
+ spec.description = 'Provides authentication methods as well as some simple API calls'
17
+ spec.homepage = 'https://github.com/lesterrry/miwifi'
18
+ spec.license = 'MIT'
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
23
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
+ end
25
+ spec.bindir = 'exe'
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ['lib']
28
+
29
+ spec.add_development_dependency 'bundler', '>= 2.2.33'
30
+ spec.add_development_dependency 'irb'
31
+ spec.add_development_dependency 'minitest', '~> 5.0'
32
+ spec.add_development_dependency 'rake', '~> 13.0'
33
+ spec.add_development_dependency 'rubocop'
34
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: miwifi
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0.pre.beta
5
+ platform: ruby
6
+ authors:
7
+ - Aydar N.
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-07-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 2.2.33
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 2.2.33
27
+ - !ruby/object:Gem::Dependency
28
+ name: irb
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '13.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '13.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Provides authentication methods as well as some simple API calls
84
+ email:
85
+ - me@aydar.media
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".rubocop.yml"
92
+ - Gemfile
93
+ - LICENSE
94
+ - README.md
95
+ - Rakefile
96
+ - bin/console
97
+ - bin/setup
98
+ - lib/miwifi.rb
99
+ - lib/miwifi/api.rb
100
+ - lib/miwifi/extensions.rb
101
+ - lib/miwifi/router.rb
102
+ - lib/miwifi/version.rb
103
+ - miwifi.gemspec
104
+ homepage: https://github.com/lesterrry/miwifi
105
+ licenses:
106
+ - MIT
107
+ metadata: {}
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: 2.6.3
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">"
120
+ - !ruby/object:Gem::Version
121
+ version: 1.3.1
122
+ requirements: []
123
+ rubygems_version: 3.3.7
124
+ signing_key:
125
+ specification_version: 4
126
+ summary: API wrapper for MiWIFI routers
127
+ test_files: []