source_license_sdk 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.
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+ require 'socket'
5
+
6
+ # Generates unique machine identifiers for license activation
7
+ class SourceLicenseSDK::MachineIdentifier
8
+ class << self
9
+ # Generate a unique machine identifier
10
+ def generate
11
+ components = []
12
+
13
+ # Get hostname
14
+ components << hostname
15
+
16
+ # Get MAC addresses
17
+ components.concat(mac_addresses)
18
+
19
+ # Get CPU info if available
20
+ components << cpu_info if cpu_info
21
+
22
+ # Get motherboard info if available
23
+ components << motherboard_info if motherboard_info
24
+
25
+ # Get disk serial if available
26
+ components << disk_serial if disk_serial
27
+
28
+ # Create hash from all components
29
+ raw_id = components.compact.join('|')
30
+ Digest::SHA256.hexdigest(raw_id)[0..31] # First 32 characters
31
+ end
32
+
33
+ # Generate machine fingerprint (more detailed than machine ID)
34
+ def generate_fingerprint
35
+ components = []
36
+
37
+ # Basic system info
38
+ components << hostname
39
+ components << ruby_version
40
+ components << platform
41
+
42
+ # Network info
43
+ components.concat(mac_addresses)
44
+ components << local_ip
45
+
46
+ # Hardware info
47
+ components << cpu_info if cpu_info
48
+ components << memory_info if memory_info
49
+ components << disk_info if disk_info
50
+
51
+ # Environment info
52
+ components << environment_hash
53
+
54
+ raw_fingerprint = components.compact.join('|')
55
+ Digest::SHA256.hexdigest(raw_fingerprint)
56
+ end
57
+
58
+ private
59
+
60
+ def hostname
61
+ Socket.gethostname
62
+ rescue StandardError
63
+ 'unknown-host'
64
+ end
65
+
66
+ def mac_addresses
67
+ addresses = []
68
+
69
+ case RUBY_PLATFORM
70
+ when /darwin/i
71
+ # macOS
72
+ output = `ifconfig 2>/dev/null`
73
+ addresses = output.scan(/ether ([a-f0-9:]{17})/i).flatten
74
+ when /linux/i
75
+ # Linux
76
+ output = `ip link show 2>/dev/null || ifconfig 2>/dev/null`
77
+ addresses = output.scan(/(?:ether|HWaddr)\s+([a-f0-9:]{17})/i).flatten
78
+ when /mswin|mingw|cygwin/i
79
+ # Windows
80
+ output = `getmac /fo csv /nh 2>nul`
81
+ addresses = output.scan(/"([A-F0-9-]{17})"/i).flatten.map { |addr| addr.tr('-', ':').downcase }
82
+ end
83
+
84
+ # Filter out virtual/invalid addresses
85
+ addresses.select { |addr| addr && !addr.start_with?('00:00:00') && addr != '02:00:00:00:00:00' }
86
+ rescue StandardError
87
+ []
88
+ end
89
+
90
+ def cpu_info
91
+ case RUBY_PLATFORM
92
+ when /darwin/i
93
+ `sysctl -n machdep.cpu.brand_string 2>/dev/null`.strip
94
+ when /linux/i
95
+ info = `cat /proc/cpuinfo 2>/dev/null | grep "model name" | head -1`.strip
96
+ info.split(':').last&.strip if info.include?(':')
97
+ when /mswin|mingw|cygwin/i
98
+ `wmic cpu get name /value 2>nul | findstr "Name="`.strip.split('=').last
99
+ end
100
+ rescue StandardError
101
+ nil
102
+ end
103
+
104
+ def motherboard_info
105
+ case RUBY_PLATFORM
106
+ when /darwin/i
107
+ `system_profiler SPHardwareDataType 2>/dev/null | grep "Serial Number"`.strip
108
+ when /linux/i
109
+ `sudo dmidecode -s baseboard-serial-number 2>/dev/null`.strip
110
+ when /mswin|mingw|cygwin/i
111
+ `wmic baseboard get serialnumber /value 2>nul | findstr "SerialNumber="`.strip.split('=').last
112
+ end
113
+ rescue StandardError
114
+ nil
115
+ end
116
+
117
+ def disk_serial
118
+ case RUBY_PLATFORM
119
+ when /darwin/i
120
+ `diskutil info / 2>/dev/null | grep "Volume UUID"`.strip.split(':').last&.strip
121
+ when /linux/i
122
+ `lsblk -dno SERIAL 2>/dev/null | head -1`.strip
123
+ when /mswin|mingw|cygwin/i
124
+ `wmic diskdrive get serialnumber /value 2>nul | findstr "SerialNumber="`.strip.split('=').last
125
+ end
126
+ rescue StandardError
127
+ nil
128
+ end
129
+
130
+ def ruby_version
131
+ RUBY_VERSION
132
+ end
133
+
134
+ def platform
135
+ RUBY_PLATFORM
136
+ end
137
+
138
+ def local_ip
139
+ # Get local IP by connecting to a remote address (doesn't actually send data)
140
+ Socket.ip_address_list.find(&:ipv4_private?)&.ip_address
141
+ rescue StandardError
142
+ '127.0.0.1'
143
+ end
144
+
145
+ def memory_info
146
+ case RUBY_PLATFORM
147
+ when /darwin/i
148
+ `sysctl -n hw.memsize 2>/dev/null`.strip
149
+ when /linux/i
150
+ `cat /proc/meminfo 2>/dev/null | grep MemTotal`.strip.split.last
151
+ when /mswin|mingw|cygwin/i
152
+ output = `wmic computersystem get TotalPhysicalMemory /value 2>nul | findstr "TotalPhysicalMemory="`
153
+ output.strip.split('=').last
154
+ end
155
+ rescue StandardError
156
+ nil
157
+ end
158
+
159
+ def disk_info
160
+ case RUBY_PLATFORM
161
+ when /darwin/i, /linux/i
162
+ `df -h / 2>/dev/null | tail -1`.strip.split.first
163
+ when /mswin|mingw|cygwin/i
164
+ `wmic logicaldisk get size,caption /value 2>nul | findstr "Size=" | head -1`.strip.split('=').last
165
+ end
166
+ rescue StandardError
167
+ nil
168
+ end
169
+
170
+ def environment_hash
171
+ # Hash of relevant environment variables (non-sensitive)
172
+ env_vars = %w[HOME USER USERNAME PATH SHELL]
173
+ env_data = env_vars.map { |var| "#{var}=#{ENV.fetch(var, nil)}" }.join('|')
174
+ Digest::SHA256.hexdigest(env_data)[0..15] # First 16 characters
175
+ rescue StandardError
176
+ 'unknown-env'
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SourceLicenseSDK
4
+ VERSION = '1.0.0'
5
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'source_license_sdk/version'
4
+ require_relative 'source_license_sdk/client'
5
+ require_relative 'source_license_sdk/machine_identifier'
6
+ require_relative 'source_license_sdk/license_validator'
7
+ require_relative 'source_license_sdk/exceptions'
8
+
9
+ module SourceLicenseSDK
10
+ # Configure the SDK with your Source-License server details
11
+ def self.configure
12
+ yield(configuration)
13
+ end
14
+
15
+ def self.configuration
16
+ @configuration ||= Configuration.new
17
+ end
18
+
19
+ # Quick setup method for common use cases
20
+ def self.setup(server_url:, license_key:, machine_id: nil, auto_generate_machine_id: true)
21
+ configure do |config|
22
+ config.server_url = server_url
23
+ config.license_key = license_key
24
+ config.machine_id = machine_id
25
+ config.auto_generate_machine_id = auto_generate_machine_id
26
+ end
27
+ end
28
+
29
+ # Validate license (method 1)
30
+ def self.validate_license(license_key = nil, machine_id: nil)
31
+ license_key ||= configuration.license_key
32
+ machine_id ||= configuration.machine_id
33
+
34
+ raise ConfigurationError, 'License key is required' if license_key.nil? || license_key.empty?
35
+
36
+ client = Client.new(configuration)
37
+ client.validate_license(license_key, machine_id: machine_id)
38
+ end
39
+
40
+ # Activate license (method 2)
41
+ def self.activate_license(license_key = nil, machine_id: nil)
42
+ license_key ||= configuration.license_key
43
+ machine_id ||= configuration.machine_id ||
44
+ (configuration.auto_generate_machine_id ? MachineIdentifier.generate : nil)
45
+
46
+ raise ConfigurationError, 'License key is required' if license_key.nil? || license_key.empty?
47
+ raise ConfigurationError, 'Machine ID is required for activation' if machine_id.nil? || machine_id.empty?
48
+
49
+ client = Client.new(configuration)
50
+ client.activate_license(license_key, machine_id: machine_id)
51
+ end
52
+
53
+ # Enforce license check - exits application if license is invalid (method 3)
54
+ def self.enforce_license!(license_key = nil, machine_id: nil, exit_code: 1, custom_message: nil)
55
+ license_key ||= configuration.license_key
56
+ machine_id ||= configuration.machine_id
57
+
58
+ begin
59
+ result = validate_license(license_key, machine_id: machine_id)
60
+
61
+ unless result.valid?
62
+ message = custom_message || "License validation failed: #{result.error_message}"
63
+ puts "[LICENSE ERROR] #{message}"
64
+ exit(exit_code)
65
+ end
66
+
67
+ result
68
+ rescue SourceLicenseSDK::Error => e
69
+ message = custom_message || "License check failed: #{e.message}"
70
+ puts "[LICENSE ERROR] #{message}"
71
+ exit(exit_code)
72
+ end
73
+ end
74
+
75
+ class Configuration
76
+ attr_accessor :server_url, :license_key, :machine_id, :auto_generate_machine_id,
77
+ :timeout, :user_agent, :verify_ssl
78
+
79
+ def initialize
80
+ @server_url = nil
81
+ @license_key = nil
82
+ @machine_id = nil
83
+ @auto_generate_machine_id = true
84
+ @timeout = 30
85
+ @user_agent = "SourceLicenseSDK/#{VERSION}"
86
+ @verify_ssl = true
87
+ end
88
+
89
+ def valid?
90
+ !server_url.nil? && !server_url.empty?
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/source_license_sdk/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'source_license_sdk'
7
+ spec.version = SourceLicenseSDK::VERSION
8
+ spec.authors = ['PixelRidge Softworks']
9
+ spec.email = ['support@pixelridgesoftworks.com']
10
+
11
+ spec.summary = 'Ruby SDK for Source-License platform'
12
+ spec.description = 'A Ruby gem for easy integration with Source-License platform for license ' \
13
+ 'validation and activation'
14
+ spec.homepage = 'https://github.com/PixelRidgeSoftworks/Source-License'
15
+ spec.license = 'GPL-3.0-or-later'
16
+ spec.required_ruby_version = '>= 3.4.4'
17
+
18
+ spec.metadata['homepage_uri'] = spec.homepage
19
+ spec.metadata['source_code_uri'] = 'https://github.com/PixelRidgeSoftworks/Source-License/tree/main/SL_Ruby_SDK'
20
+ spec.metadata['changelog_uri'] = 'https://github.com/PixelRidgeSoftworks/Source-License/blob/main/SL_Ruby_SDK/CHANGELOG.md'
21
+ spec.metadata['rubygems_mfa_required'] = 'true'
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # Use cross-platform compatible file detection
25
+ spec.files = Dir.glob(%w[
26
+ lib/**/*.rb
27
+ README.md
28
+ CHANGELOG.md
29
+ LICENSE
30
+ Gemfile
31
+ Rakefile
32
+ source_license_sdk.gemspec
33
+ ]).select { |f| File.file?(f) }
34
+ spec.bindir = 'exe'
35
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
36
+ spec.require_paths = ['lib']
37
+
38
+ # Dependencies
39
+ spec.add_dependency 'digest', '~> 3.0'
40
+ spec.add_dependency 'json', '~> 2.0'
41
+ spec.add_dependency 'net-http', '~> 0.1'
42
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: source_license_sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - PixelRidge Softworks
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: digest
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '3.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '3.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: json
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '2.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '2.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: net-http
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0.1'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '0.1'
54
+ description: A Ruby gem for easy integration with Source-License platform for license
55
+ validation and activation
56
+ email:
57
+ - support@pixelridgesoftworks.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - CHANGELOG.md
63
+ - Gemfile
64
+ - LICENSE
65
+ - README.md
66
+ - Rakefile
67
+ - lib/source_license_sdk.rb
68
+ - lib/source_license_sdk/client.rb
69
+ - lib/source_license_sdk/exceptions.rb
70
+ - lib/source_license_sdk/license_validator.rb
71
+ - lib/source_license_sdk/machine_identifier.rb
72
+ - lib/source_license_sdk/version.rb
73
+ - source_license_sdk.gemspec
74
+ homepage: https://github.com/PixelRidgeSoftworks/Source-License
75
+ licenses:
76
+ - GPL-3.0-or-later
77
+ metadata:
78
+ homepage_uri: https://github.com/PixelRidgeSoftworks/Source-License
79
+ source_code_uri: https://github.com/PixelRidgeSoftworks/Source-License/tree/main/SL_Ruby_SDK
80
+ changelog_uri: https://github.com/PixelRidgeSoftworks/Source-License/blob/main/SL_Ruby_SDK/CHANGELOG.md
81
+ rubygems_mfa_required: 'true'
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 3.4.4
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ requirements: []
96
+ rubygems_version: 3.7.2
97
+ specification_version: 4
98
+ summary: Ruby SDK for Source-License platform
99
+ test_files: []