Skip to content

Commit 06882ec

Browse files
add needed licence rake tasks
1 parent b98f261 commit 06882ec

File tree

7 files changed

+237
-21
lines changed

7 files changed

+237
-21
lines changed

react_on_rails_pro/Gemfile.lock

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ PATH
2525
connection_pool
2626
execjs (~> 2.9)
2727
httpx (~> 1.5)
28+
jwt (~> 2.7)
2829
rainbow
2930
react_on_rails (>= 16.0.0)
3031

@@ -184,6 +185,8 @@ GEM
184185
railties (>= 4.2.0)
185186
thor (>= 0.14, < 2.0)
186187
json (2.7.2)
188+
jwt (2.9.3)
189+
base64
187190
launchy (3.0.1)
188191
addressable (~> 2.8)
189192
childprocess (~> 5.0)

react_on_rails_pro/lib/react_on_rails_pro/license_public_key.rb

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,21 @@
22

33
module ReactOnRailsPro
44
module LicensePublicKey
5-
# This is a placeholder public key for development/testing
6-
# In production, this should be replaced with ShakaCode's actual public key
7-
# The private key corresponding to this public key should NEVER be committed to the repository
8-
KEY = OpenSSL::PKey::RSA.new(<<~PEM)
5+
# ShakaCode's public key for React on Rails Pro license verification
6+
# The private key corresponding to this public key is held by ShakaCode
7+
# and is never committed to the repository
8+
# Last updated: 2025-10-09 15:57:09 UTC
9+
# Source: http://localhost:8788/api/public-key
10+
KEY = OpenSSL::PKey::RSA.new(<<~PEM.strip.strip_heredoc)
911
-----BEGIN PUBLIC KEY-----
10-
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0Z3VS5JJcds3xfn/ygWyF/NP
11-
lRQkqfph3x6TEOirFCpDfRjowDXAk66dPmLzw5qVOmGVPKgpJBjZR7oMIMgxBPUoj00F
12-
DwlhUGmOVoqnVWGFHVUHDL5qYQaZzRdp4Bh9fxnN52Yk8+FuHsT+5lxLcaRV6mRtX7OT
13-
5pQbxV0o0/OxPFC1Hz9RdLPUevnWNbLe8f5ePHivmqsoAH9HE4g03WkFZEqBLmjqpJj8
14-
VqGR0q8CPPRCFGAr9S4WCQqBhLDH0j/JR+FpPX9Df8vfFJhHdBGdTGjN4g9g6qwPYmVH
15-
ukAErHNIJMNmzYjFIT4+Xwp6xKHyUqL3w3JZDQnFywIDAQAB
16-
-----END PUBLIC KEY-----
12+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlJFK3aWuycVp9X05qhGo
13+
FLztH8yjpuAKUoC4DKHX0fYjNIzwG3xwhLWKKDCmnNfuzW5R09/albl59/ZCHFyS
14+
I7H7Aita1l9rnHCHEyyyJUs/E7zMG27lsECkNoCJr5cD/qtabY45uggFJrl3YRgy
15+
ieonNQvxLtvPuatAPd6jfs/PlHOYA3z+t0C5uDW5YlXJkLKzKKiikvxsyOnk94Uq
16+
J7FWzSdlvY08aLkERZDlGuWcjvQexVz7NCAMR050aEgobwxg2AuaCWDd8cDH6Asq
17+
mhGxQr7ulvrXfDMI6dBqa3ihfjgk+dpA8ilfUsCFc8ovbIA0oE8BTIxogyYr2KaH
18+
vQIDAQAB
19+
-----END PUBLIC KEY-----
1720
PEM
1821
end
1922
end
Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
// This is a placeholder public key for development/testing
2-
// In production, this should be replaced with ShakaCode's actual public key
3-
// The private key corresponding to this public key should NEVER be committed to the repository
1+
// ShakaCode's public key for React on Rails Pro license verification
2+
// The private key corresponding to this public key is held by ShakaCode
3+
// and is never committed to the repository
4+
// Last updated: 2025-10-09 15:57:09 UTC
5+
// Source: http://localhost:8788/api/public-key
46
export const PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
5-
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0Z3VS5JJcds3xfn/ygWyF/NP
6-
lRQkqfph3x6TEOirFCpDfRjowDXAk66dPmLzw5qVOmGVPKgpJBjZR7oMIMgxBPUoj00F
7-
DwlhUGmOVoqnVWGFHVUHDL5qYQaZzRdp4Bh9fxnN52Yk8+FuHsT+5lxLcaRV6mRtX7OT
8-
5pQbxV0o0/OxPFC1Hz9RdLPUevnWNbLe8f5ePHivmqsoAH9HE4g03WkFZEqBLmjqpJj8
9-
VqGR0q8CPPRCFGAr9S4WCQqBhLDH0j/JR+FpPX9Df8vfFJhHdBGdTGjN4g9g6qwPYmVH
10-
ukAErHNIJMNmzYjFIT4+Xwp6xKHyUqL3w3JZDQnFywIDAQAB
7+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlJFK3aWuycVp9X05qhGo
8+
FLztH8yjpuAKUoC4DKHX0fYjNIzwG3xwhLWKKDCmnNfuzW5R09/albl59/ZCHFyS
9+
I7H7Aita1l9rnHCHEyyyJUs/E7zMG27lsECkNoCJr5cD/qtabY45uggFJrl3YRgy
10+
ieonNQvxLtvPuatAPd6jfs/PlHOYA3z+t0C5uDW5YlXJkLKzKKiikvxsyOnk94Uq
11+
J7FWzSdlvY08aLkERZDlGuWcjvQexVz7NCAMR050aEgobwxg2AuaCWDd8cDH6Asq
12+
mhGxQr7ulvrXfDMI6dBqa3ihfjgk+dpA8ilfUsCFc8ovbIA0oE8BTIxogyYr2KaH
13+
vQIDAQAB
1114
-----END PUBLIC KEY-----`;
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
# frozen_string_literal: true
2+
3+
require "net/http"
4+
require "json"
5+
require "uri"
6+
7+
# React on Rails Pro License Public Key Management Tasks
8+
#
9+
# Usage:
10+
# rake react_on_rails_pro:update_public_key # From production (shakacode.com)
11+
# rake react_on_rails_pro:update_public_key[local] # From localhost:8788
12+
# rake react_on_rails_pro:update_public_key[custom.com] # From custom hostname
13+
# rake react_on_rails_pro:verify_public_key # Verify current configuration
14+
# rake react_on_rails_pro:public_key_help # Show help
15+
16+
namespace :react_on_rails_pro do
17+
desc "Update the public key for React on Rails Pro license validation"
18+
task :update_public_key, [:source] do |_task, args|
19+
source = args[:source] || "production"
20+
21+
# Determine the API URL based on the source
22+
api_url = case source
23+
when "local", "localhost"
24+
"http://localhost:8788/api/public-key"
25+
when "production", "prod"
26+
"https://www.shakacode.com/api/public-key"
27+
else
28+
# Check if it's a custom URL or hostname
29+
if source.start_with?("http://", "https://")
30+
# Full URL provided
31+
source.end_with?("/api/public-key") ? source : "#{source}/api/public-key"
32+
else
33+
# Just a hostname provided
34+
"https://#{source}/api/public-key"
35+
end
36+
end
37+
38+
puts "Fetching public key from: #{api_url}"
39+
40+
begin
41+
uri = URI(api_url)
42+
response = Net::HTTP.get_response(uri)
43+
44+
if response.code != "200"
45+
puts "❌ Failed to fetch public key. HTTP Status: #{response.code}"
46+
puts "Response: #{response.body}"
47+
exit 1
48+
end
49+
50+
data = JSON.parse(response.body)
51+
public_key = data["publicKey"]
52+
53+
if public_key.nil? || public_key.empty?
54+
puts "❌ No public key found in response"
55+
exit 1
56+
end
57+
58+
# Update Ruby public key file
59+
ruby_file_path = File.join(File.dirname(__FILE__), "..", "lib", "react_on_rails_pro", "license_public_key.rb")
60+
ruby_content = <<~RUBY.strip_heredoc
61+
# frozen_string_literal: true
62+
63+
module ReactOnRailsPro
64+
module LicensePublicKey
65+
# ShakaCode's public key for React on Rails Pro license verification
66+
# The private key corresponding to this public key is held by ShakaCode
67+
# and is never committed to the repository
68+
# Last updated: #{Time.now.utc.strftime("%Y-%m-%d %H:%M:%S UTC")}
69+
# Source: #{api_url}
70+
KEY = OpenSSL::PKey::RSA.new(<<~PEM.strip.strip_heredoc)
71+
#{public_key.strip}
72+
PEM
73+
end
74+
end
75+
RUBY
76+
77+
File.write(ruby_file_path, ruby_content)
78+
puts "✅ Updated Ruby public key: #{ruby_file_path}"
79+
80+
# Update Node/TypeScript public key file
81+
node_file_path = File.join(File.dirname(__FILE__), "..", "packages", "node-renderer", "src", "shared", "licensePublicKey.ts")
82+
node_content = <<~TYPESCRIPT
83+
// ShakaCode's public key for React on Rails Pro license verification
84+
// The private key corresponding to this public key is held by ShakaCode
85+
// and is never committed to the repository
86+
// Last updated: #{Time.now.utc.strftime("%Y-%m-%d %H:%M:%S UTC")}
87+
// Source: #{api_url}
88+
export const PUBLIC_KEY = `#{public_key.strip}`;
89+
TYPESCRIPT
90+
91+
File.write(node_file_path, node_content)
92+
puts "✅ Updated Node public key: #{node_file_path}"
93+
94+
puts "\n✅ Successfully updated public keys from #{api_url}"
95+
puts "\nPublic key info:"
96+
puts " Algorithm: #{data['algorithm'] || 'RSA-2048'}"
97+
puts " Format: #{data['format'] || 'PEM'}"
98+
puts " Usage: #{data['usage'] || 'React on Rails Pro license verification'}"
99+
rescue SocketError, Net::OpenTimeout, Net::ReadTimeout => e
100+
puts "❌ Network error: #{e.message}"
101+
puts "Please check your internet connection and the API URL."
102+
exit 1
103+
rescue JSON::ParserError => e
104+
puts "❌ Failed to parse JSON response: #{e.message}"
105+
exit 1
106+
rescue StandardError => e
107+
puts "❌ Error: #{e.message}"
108+
puts e.backtrace.first(5)
109+
exit 1
110+
end
111+
end
112+
113+
desc "Verify the current public key configuration"
114+
task :verify_public_key do
115+
puts "Verifying public key configuration..."
116+
117+
begin
118+
# Load and check Ruby public key
119+
require "openssl"
120+
121+
# Need to define OpenSSL before loading the public key
122+
require_relative "../lib/react_on_rails_pro/license_public_key"
123+
ruby_key = ReactOnRailsPro::LicensePublicKey::KEY
124+
puts "✅ Ruby public key loaded successfully"
125+
puts " Key size: #{ruby_key.n.num_bits} bits"
126+
127+
# Check Node public key file exists
128+
node_file_path = File.join(File.dirname(__FILE__), "..", "packages", "node-renderer", "src", "shared", "licensePublicKey.ts")
129+
if File.exist?(node_file_path)
130+
node_content = File.read(node_file_path)
131+
if node_content.include?("BEGIN PUBLIC KEY")
132+
puts "✅ Node public key file exists and contains a public key"
133+
else
134+
puts "⚠️ Node public key file exists but may not contain a valid key"
135+
end
136+
else
137+
puts "❌ Node public key file not found: #{node_file_path}"
138+
end
139+
140+
# Try to validate with current license if one exists (simplified check without Rails)
141+
license_file = File.join(File.dirname(__FILE__), "..", "spec", "dummy", "config", "react_on_rails_pro_license.key")
142+
if ENV["REACT_ON_RAILS_PRO_LICENSE"] || File.exist?(license_file)
143+
puts "\n✅ License configuration detected"
144+
puts " ENV variable set" if ENV["REACT_ON_RAILS_PRO_LICENSE"]
145+
puts " Config file exists: #{license_file}" if File.exist?(license_file)
146+
147+
# Basic JWT validation test
148+
require "jwt"
149+
license = ENV["REACT_ON_RAILS_PRO_LICENSE"] || File.read(license_file).strip
150+
151+
begin
152+
payload, _header = JWT.decode(license, ruby_key, true, { algorithm: "RS256" })
153+
puts " ✅ License signature valid"
154+
puts " License email: #{payload['sub']}" if payload['sub']
155+
puts " Organization: #{payload['organization']}" if payload['organization']
156+
rescue JWT::ExpiredSignature
157+
puts " ⚠️ License expired"
158+
rescue JWT::DecodeError => e
159+
puts " ⚠️ License validation failed: #{e.message}"
160+
end
161+
else
162+
puts "\n⚠️ No license configured"
163+
puts " Set REACT_ON_RAILS_PRO_LICENSE env variable or create config/react_on_rails_pro_license.key"
164+
end
165+
rescue LoadError => e
166+
puts "❌ Failed to load required module: #{e.message}"
167+
puts " You may need to run 'bundle install' first"
168+
exit 1
169+
rescue StandardError => e
170+
puts "❌ Error during verification: #{e.message}"
171+
exit 1
172+
end
173+
end
174+
175+
desc "Show usage examples for updating the public key"
176+
task :public_key_help do
177+
puts <<~HELP
178+
React on Rails Pro - Public Key Management
179+
==========================================
180+
181+
Update public key from different sources:
182+
183+
1. From production (ShakaCode's official server):
184+
rake react_on_rails_pro:update_public_key
185+
rake react_on_rails_pro:update_public_key[production]
186+
187+
2. From local development server:
188+
rake react_on_rails_pro:update_public_key[local]
189+
190+
3. From a custom hostname:
191+
rake react_on_rails_pro:update_public_key[staging.example.com]
192+
193+
4. From a custom full URL:
194+
rake react_on_rails_pro:update_public_key[https://api.example.com/api/public-key]
195+
196+
Verify current public key:
197+
rake react_on_rails_pro:verify_public_key
198+
199+
Note: The public key is used to verify JWT licenses for React on Rails Pro.
200+
The corresponding private key is held securely by ShakaCode.
201+
HELP
202+
end
203+
end

react_on_rails_pro/react_on_rails_pro.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
1919
s.files = `git ls-files -z`.split("\x0")
2020
.reject { |f|
2121
f.match(
22-
%r{^(test|spec|features|tmp|node_modules|packages|coverage|Gemfile.lock)/}
22+
%r{^(test|spec|features|tmp|node_modules|packages|coverage|Gemfile.lock|lib/tasks)/}
2323
)
2424
}
2525
s.bindir = "exe"

react_on_rails_pro/spec/dummy/Gemfile.lock

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ PATH
2525
connection_pool
2626
execjs (~> 2.9)
2727
httpx (~> 1.5)
28+
jwt (~> 2.7)
2829
rainbow
2930
react_on_rails (>= 16.0.0)
3031

@@ -195,6 +196,8 @@ GEM
195196
railties (>= 4.2.0)
196197
thor (>= 0.14, < 2.0)
197198
json (2.7.2)
199+
jwt (2.9.3)
200+
base64
198201
launchy (3.0.1)
199202
addressable (~> 2.8)
200203
childprocess (~> 5.0)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0ZXN0QGV4YW1wbGUuY29tIiwiaWF0IjoxNzYwMDIyNzk0LCJleHAiOjE3NjAwMjYzOTQsIm9yZ2FuaXphdGlvbiI6IkFjbWUgQ29ycCIsInBsYW4iOiJkZW1vIiwiaXNzdWVkX2J5IjoiYXBpLWRlbW8ifQ.HH-o78IeIsy-b7Iht_41eZAG7-OqQpFPhqxfm_BLc_dJsFOJFHm6Z8Ki7qad4U65KE5Kok7xab9662LAQB-MwnO8zxY0m2_ZHUM51T9MNlBZ20Xk3cETKoaPLG1XovdOfPvXf2oUoeSPnpHlm715UEJaprvR8IG0V2YS_upzpmIA-XHMghXeOZyXYTViWaeST3XE2PRgo2kC8f8hdtPDd4wnRe0X2j0lBpnIjYV-NFCigNUx50-F6uV87-OeBLMz2-PeufubHvu1mpCaPhewTorfEyG6A8jtsshKrdDvJO5p-iU4AvA7PPaxUcvaiVd6QiPyQGY4OBqSpLjZuE9w2Q

0 commit comments

Comments
 (0)