terminalwire 0.1.11 → 0.1.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +9 -1
- data/lib/generators/terminalwire/install/install_generator.rb +2 -1
- data/lib/generators/terminalwire/install/templates/application_terminal.rb.tt +2 -35
- data/lib/generators/terminalwire/install/templates/main_terminal.rb +40 -0
- data/lib/terminalwire/client.rb +9 -21
- data/lib/terminalwire/licensing.rb +183 -0
- data/lib/terminalwire/logging.rb +1 -1
- data/lib/terminalwire/server.rb +3 -77
- data/lib/terminalwire/transport.rb +0 -65
- data/lib/terminalwire/version.rb +1 -1
- data/lib/terminalwire.rb +0 -5
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b3e02592c8154c835d32f4dc149d47212665f5dd2974d2634746207ced582b3
|
4
|
+
data.tar.gz: 0a4b15090653b5b54a10a215db6a39ee5465cac9a10c4e1cd29ba7fc0622822a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d74b1186e46a73eb62de35f0624f20a4f3f90aa8bf24137b772423a87a09bea920886824d7175c5b08bd18c963b3823c4cccbff0e7abd44120bfe186edda84e6
|
7
|
+
data.tar.gz: 9997f63145801d3ca47476ead70f49ac001f77765cb777063b44b62d96e1b3dfdf266f42897fae01eb0a9a224e8fddeb5e878533e773f11aaafe2e81512a48f4
|
data/LICENSE.txt
CHANGED
@@ -1 +1,9 @@
|
|
1
|
-
Copyright (c) 2024 Brad Gessler.
|
1
|
+
Copyright (c) 2024 Brad Gessler.
|
2
|
+
|
3
|
+
License is propietary. Here's the deal:
|
4
|
+
|
5
|
+
* You need to pay for Terminalwire if your organization has more than $1m in assets or makes more than $100k/year in revenue.
|
6
|
+
* Terminalwire is free for personal use, hobbyists, or businesses that are just starting out, but server licenses still need to be registered at https://terminalwire.com/developers/licenses.
|
7
|
+
* You can only use the Terminalwire client with licensed Terminalwire servers.
|
8
|
+
|
9
|
+
This list is not exhaustive, please read the full license text at https://terminalwire.com/license.
|
@@ -7,6 +7,7 @@ class Terminalwire::InstallGenerator < Rails::Generators::Base
|
|
7
7
|
|
8
8
|
def create_terminal_files
|
9
9
|
template "application_terminal.rb.tt", Rails.root.join("app/terminal/application_terminal.rb")
|
10
|
+
template "main_terminal.rb", Rails.root.join("app/terminal/main_terminal.rb")
|
10
11
|
end
|
11
12
|
|
12
13
|
def create_binary_files
|
@@ -17,7 +18,7 @@ class Terminalwire::InstallGenerator < Rails::Generators::Base
|
|
17
18
|
def add_route
|
18
19
|
route <<~ROUTE
|
19
20
|
match "/terminal",
|
20
|
-
to: Terminalwire::Server::Thor.new(
|
21
|
+
to: Terminalwire::Server::Thor.new(MainTerminal),
|
21
22
|
via: [:get, :connect]
|
22
23
|
ROUTE
|
23
24
|
end
|
@@ -1,44 +1,11 @@
|
|
1
1
|
# Learn how to use Thor at http://whatisthor.com.
|
2
2
|
class ApplicationTerminal < Thor
|
3
|
+
# Enables IO Streaming.
|
3
4
|
include Terminalwire::Thor
|
4
5
|
|
6
|
+
# The name of your binary. Thor uses this for its help output.
|
5
7
|
def self.basename = "<%= binary_name %>"
|
6
8
|
|
7
|
-
desc "hello NAME", "say hello to NAME"
|
8
|
-
def hello(name)
|
9
|
-
puts "Hello #{name}"
|
10
|
-
end
|
11
|
-
|
12
|
-
desc "login", "Login to your account"
|
13
|
-
def login
|
14
|
-
print "Email: "
|
15
|
-
email = gets.chomp
|
16
|
-
|
17
|
-
print "Password: "
|
18
|
-
password = getpass
|
19
|
-
|
20
|
-
if self.current_user = User.authenticate(email, password)
|
21
|
-
puts "Successfully logged in as #{current_user.email}."
|
22
|
-
else
|
23
|
-
puts "Could not find a user with that email and password."
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
desc "whoami", "Displays current user information."
|
28
|
-
def whoami
|
29
|
-
if self.current_user
|
30
|
-
puts "Logged in as #{current_user.email}."
|
31
|
-
else
|
32
|
-
puts "Not logged in. Run `#{self.class.basename} login` to login."
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
desc "logout", "Logout of your account"
|
37
|
-
def logout
|
38
|
-
session.reset
|
39
|
-
puts "Successfully logged out."
|
40
|
-
end
|
41
|
-
|
42
9
|
private
|
43
10
|
|
44
11
|
def current_user=(user)
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class MainTerminal < ApplicationTerminal
|
2
|
+
desc "hello NAME", "say hello to NAME"
|
3
|
+
def hello(name)
|
4
|
+
puts "Hello #{name}"
|
5
|
+
end
|
6
|
+
|
7
|
+
desc "login", "Login to your account"
|
8
|
+
def login
|
9
|
+
print "Email: "
|
10
|
+
email = gets.chomp
|
11
|
+
|
12
|
+
print "Password: "
|
13
|
+
password = getpass
|
14
|
+
|
15
|
+
# Replace this with your own authentication logic; this is an example
|
16
|
+
# of how you might do this with Devise.
|
17
|
+
user = User.find_for_authentication(email: email)
|
18
|
+
if user && user.valid_password?(password)
|
19
|
+
self.current_user = user
|
20
|
+
puts "Successfully logged in as #{current_user.email}."
|
21
|
+
else
|
22
|
+
puts "Could not find a user with that email and password."
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "whoami", "Displays current user information."
|
27
|
+
def whoami
|
28
|
+
if self.current_user
|
29
|
+
puts "Logged in as #{current_user.email}."
|
30
|
+
else
|
31
|
+
puts "Not logged in. Run `#{self.class.basename} login` to login."
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "logout", "Logout of your account"
|
36
|
+
def logout
|
37
|
+
session.reset
|
38
|
+
puts "Successfully logged out."
|
39
|
+
end
|
40
|
+
end
|
data/lib/terminalwire/client.rb
CHANGED
@@ -28,13 +28,15 @@ module Terminalwire
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def connect
|
31
|
-
@adapter.write(
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
31
|
+
@adapter.write(
|
32
|
+
event: "initialization",
|
33
|
+
protocol: { version: VERSION },
|
34
|
+
entitlement: @entitlement.serialize,
|
35
|
+
program: {
|
36
|
+
name: @program_name,
|
37
|
+
arguments: @program_arguments
|
38
|
+
}
|
39
|
+
)
|
38
40
|
|
39
41
|
loop do
|
40
42
|
handle @adapter.read
|
@@ -51,20 +53,6 @@ module Terminalwire
|
|
51
53
|
end
|
52
54
|
end
|
53
55
|
|
54
|
-
def self.tcp(...)
|
55
|
-
socket = TCPSocket.new(...)
|
56
|
-
transport = Terminalwire::Transport::Socket.new(socket)
|
57
|
-
adapter = Terminalwire::Adapter::Socket.new(transport)
|
58
|
-
Terminalwire::Client::Handler.new(adapter)
|
59
|
-
end
|
60
|
-
|
61
|
-
def self.socket(...)
|
62
|
-
socket = UNIXSocket.new(...)
|
63
|
-
transport = Terminalwire::Transport::Socket.new(socket)
|
64
|
-
adapter = Terminalwire::Adapter::Socket.new(transport)
|
65
|
-
Terminalwire::Client::Handler.new(adapter)
|
66
|
-
end
|
67
|
-
|
68
56
|
# Extracted from HTTP. This is so we can
|
69
57
|
def self.authority(url)
|
70
58
|
if url.port == url.default_port
|
@@ -0,0 +1,183 @@
|
|
1
|
+
require "msgpack"
|
2
|
+
require "openssl"
|
3
|
+
require "base64"
|
4
|
+
require "uri"
|
5
|
+
|
6
|
+
module Terminalwire::Licensing
|
7
|
+
PRIVATE_KEY_LENGTH = 2048
|
8
|
+
|
9
|
+
def self.generate_private_key
|
10
|
+
OpenSSL::PKey::RSA.new(PRIVATE_KEY_LENGTH)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.generate_private_pem
|
14
|
+
generate_private_key.to_pem
|
15
|
+
end
|
16
|
+
|
17
|
+
# Handles encoding data into a license key with prefixes that can be packed and unpacked.
|
18
|
+
module Key
|
19
|
+
# Mix into classes that need to generate or read keys
|
20
|
+
module Serialization
|
21
|
+
# This is called when the module is included in a class
|
22
|
+
def self.included(base)
|
23
|
+
# Extend the class with the class methods when the module is included
|
24
|
+
base.extend(ClassMethods)
|
25
|
+
end
|
26
|
+
|
27
|
+
def serialize(...)
|
28
|
+
self.class.serialize(...)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Define the class methods that will be available on the including class
|
32
|
+
module ClassMethods
|
33
|
+
def serializer
|
34
|
+
Key::Serializer.new(prefix: self::PREFIX)
|
35
|
+
end
|
36
|
+
|
37
|
+
def serialize(...)
|
38
|
+
serializer.serialize(...)
|
39
|
+
end
|
40
|
+
|
41
|
+
def deserialize(...)
|
42
|
+
serializer.deserialize(...)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class Serializer
|
48
|
+
attr_reader :prefix
|
49
|
+
|
50
|
+
def initialize(prefix:)
|
51
|
+
@prefix = prefix
|
52
|
+
end
|
53
|
+
|
54
|
+
def serialize(data)
|
55
|
+
prepend_prefix Base64.urlsafe_encode64 MessagePack.pack data
|
56
|
+
end
|
57
|
+
|
58
|
+
def deserialize(data)
|
59
|
+
MessagePack.unpack Base64.urlsafe_decode64 unshift_prefix data
|
60
|
+
end
|
61
|
+
|
62
|
+
protected
|
63
|
+
|
64
|
+
def prepend_prefix(key)
|
65
|
+
[prefix, key].join
|
66
|
+
end
|
67
|
+
|
68
|
+
def unshift_prefix(key)
|
69
|
+
head, prefix, tail = key.partition(@prefix)
|
70
|
+
# Check if partition successfully split the string with the correct prefix
|
71
|
+
raise RuntimeError, "Expected prefix #{@prefix.inspect} on #{key.inspect}" if prefix.empty?
|
72
|
+
tail
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# This code all runs on Terminalwire servers.
|
78
|
+
module Issuer
|
79
|
+
# Generates license keys that developers use to activate their software.
|
80
|
+
class ServerKeyGenerator
|
81
|
+
include Key::Serialization
|
82
|
+
|
83
|
+
PREFIX = "server_key_".freeze
|
84
|
+
|
85
|
+
VERSION = "1.0".freeze
|
86
|
+
|
87
|
+
def initialize(public_key:, license_url:)
|
88
|
+
@public_key = public_key
|
89
|
+
@license_url = URI(license_url)
|
90
|
+
@generated_at = Time.now.utc
|
91
|
+
end
|
92
|
+
|
93
|
+
def to_h
|
94
|
+
{
|
95
|
+
version: VERSION,
|
96
|
+
generated_at: @generated_at.iso8601,
|
97
|
+
public_key: @public_key.to_pem,
|
98
|
+
license_url: @license_url.to_s
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
def server_key
|
103
|
+
serialize to_h
|
104
|
+
end
|
105
|
+
alias :to_s :server_key
|
106
|
+
end
|
107
|
+
|
108
|
+
class ClientKeyVerifier
|
109
|
+
# Time variance the server will tolerate from the client.
|
110
|
+
DRIFT_SECONDS = 600 # 600 seconds, or 10 minutes.
|
111
|
+
|
112
|
+
# This means the server will tolerate a 10 minute drift in the generated_at time.
|
113
|
+
def self.drift
|
114
|
+
now = Time.now.utc
|
115
|
+
(now - DRIFT_SECONDS)...(now + DRIFT_SECONDS)
|
116
|
+
end
|
117
|
+
|
118
|
+
def initialize(client_key:, private_key:, drift: self.class.drift)
|
119
|
+
@data = Server::ClientKeyGenerator.deserialize client_key
|
120
|
+
@private_key = private_key
|
121
|
+
@drift = drift
|
122
|
+
end
|
123
|
+
|
124
|
+
def server_attestation
|
125
|
+
@server_attestation ||= decrypt @data.fetch("server_attestation")
|
126
|
+
end
|
127
|
+
|
128
|
+
def decrypt(data)
|
129
|
+
MessagePack.unpack @private_key.private_decrypt Base64.urlsafe_decode64 data
|
130
|
+
end
|
131
|
+
|
132
|
+
def generated_at
|
133
|
+
@generated_at ||= Time.parse(server_attestation.fetch("generated_at"))
|
134
|
+
end
|
135
|
+
|
136
|
+
def valid?
|
137
|
+
@drift.include? generated_at
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Those code runs on customer servers
|
143
|
+
module Server
|
144
|
+
class ClientKeyGenerator
|
145
|
+
VERSION = "1.0".freeze
|
146
|
+
|
147
|
+
include Key::Serialization
|
148
|
+
PREFIX = "client_key_".freeze
|
149
|
+
|
150
|
+
def initialize(server_key:)
|
151
|
+
@data = Issuer::ServerKeyGenerator.deserialize server_key
|
152
|
+
@generated_at = Time.now.utc
|
153
|
+
@license_url = URI(@data.fetch("license_url"))
|
154
|
+
end
|
155
|
+
|
156
|
+
def to_h
|
157
|
+
{
|
158
|
+
version: VERSION,
|
159
|
+
license_url: @license_url.to_s,
|
160
|
+
server_attestation: attest(
|
161
|
+
version: VERSION,
|
162
|
+
generated_at: @generated_at.iso8601,
|
163
|
+
)
|
164
|
+
}
|
165
|
+
end
|
166
|
+
|
167
|
+
def client_key
|
168
|
+
serialize to_h
|
169
|
+
end
|
170
|
+
alias :to_s :client_key
|
171
|
+
|
172
|
+
protected
|
173
|
+
|
174
|
+
def attest(data)
|
175
|
+
Base64.urlsafe_encode64 public_key.public_encrypt MessagePack.pack data
|
176
|
+
end
|
177
|
+
|
178
|
+
def public_key
|
179
|
+
@public_key ||= OpenSSL::PKey::RSA.new(@data.fetch("public_key"))
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
data/lib/terminalwire/logging.rb
CHANGED
data/lib/terminalwire/server.rb
CHANGED
@@ -2,57 +2,16 @@ require "thor"
|
|
2
2
|
|
3
3
|
module Terminalwire
|
4
4
|
module Server
|
5
|
-
class MyCLI < ::Thor
|
6
|
-
include Terminalwire::Thor
|
7
|
-
|
8
|
-
desc "greet NAME", "Greet a person"
|
9
|
-
def greet(name)
|
10
|
-
name = ask "What's your name?"
|
11
|
-
say "Hello, #{name}!"
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
class Socket
|
16
|
-
include Logging
|
17
|
-
|
18
|
-
def initialize(server_socket)
|
19
|
-
@server_socket = server_socket
|
20
|
-
end
|
21
|
-
|
22
|
-
def listen
|
23
|
-
logger.info "Socket: Listening..."
|
24
|
-
loop do
|
25
|
-
client_socket = @server_socket.accept
|
26
|
-
logger.debug "Socket: Client #{client_socket.inspect} connected"
|
27
|
-
handle_client(client_socket)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
def handle_client(socket)
|
34
|
-
transport = Transport::Socket.new(socket)
|
35
|
-
adapter = Adapter.new(transport)
|
36
|
-
|
37
|
-
Thread.new do
|
38
|
-
handler = Handler.new(adapter)
|
39
|
-
handler.run
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
5
|
class WebSocket
|
45
6
|
include Logging
|
46
7
|
|
47
8
|
def call(env)
|
48
9
|
Async::WebSocket::Adapters::Rack.open(env, protocols: ['ws']) do |connection|
|
49
|
-
|
10
|
+
handle(Adapter::Socket.new(Terminalwire::Transport::WebSocket.new(connection)))
|
50
11
|
end or [200, { "Content-Type" => "text/plain" }, ["Connect via WebSockets"]]
|
51
12
|
end
|
52
13
|
|
53
|
-
|
54
|
-
|
55
|
-
def run(adapter)
|
14
|
+
def handle(adapter)
|
56
15
|
while message = adapter.read
|
57
16
|
puts message
|
58
17
|
end
|
@@ -76,7 +35,7 @@ module Terminalwire
|
|
76
35
|
"An error occurred. Please try again."
|
77
36
|
end
|
78
37
|
|
79
|
-
def
|
38
|
+
def handle(adapter)
|
80
39
|
logger.info "ThorServer: Running #{@cli_class.inspect}"
|
81
40
|
while message = adapter.read
|
82
41
|
case message
|
@@ -100,38 +59,5 @@ module Terminalwire
|
|
100
59
|
end
|
101
60
|
end
|
102
61
|
end
|
103
|
-
|
104
|
-
class Handler
|
105
|
-
include Logging
|
106
|
-
|
107
|
-
def initialize(adapter)
|
108
|
-
@adapter = adapter
|
109
|
-
end
|
110
|
-
|
111
|
-
def run
|
112
|
-
logger.info "Server Handler: Running"
|
113
|
-
loop do
|
114
|
-
message = @adapter.read
|
115
|
-
case message
|
116
|
-
in { event: "initialization", protocol:, program: { arguments: }, entitlement: }
|
117
|
-
Context.new(adapter: @adapter) do |context|
|
118
|
-
MyCLI.start(arguments, context:)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
rescue EOFError, Errno::ECONNRESET
|
123
|
-
logger.info "Server Handler: Client disconnected"
|
124
|
-
ensure
|
125
|
-
@adapter.close
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
def self.tcp(...)
|
130
|
-
Server::Socket.new(TCPServer.new(...))
|
131
|
-
end
|
132
|
-
|
133
|
-
def self.socket(...)
|
134
|
-
Server::Socket.new(UNIXServer.new(...))
|
135
|
-
end
|
136
62
|
end
|
137
63
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'uri'
|
2
|
-
require 'socket'
|
3
2
|
require 'async/websocket/client'
|
4
3
|
|
5
4
|
module Terminalwire
|
@@ -26,70 +25,6 @@ module Terminalwire
|
|
26
25
|
end
|
27
26
|
end
|
28
27
|
|
29
|
-
class TCP < Base
|
30
|
-
def self.connect(url)
|
31
|
-
uri = URI(url)
|
32
|
-
new(TCPSocket.new(uri.host, uri.port))
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.listen(url)
|
36
|
-
uri = URI(url)
|
37
|
-
new(TCPServer.new(uri.host, uri.port))
|
38
|
-
end
|
39
|
-
|
40
|
-
def initialize(socket)
|
41
|
-
@socket = socket
|
42
|
-
end
|
43
|
-
|
44
|
-
def read
|
45
|
-
length = @socket.read(4)
|
46
|
-
return nil if length.nil?
|
47
|
-
length = length.unpack('L>')[0]
|
48
|
-
@socket.read(length)
|
49
|
-
end
|
50
|
-
|
51
|
-
def write(data)
|
52
|
-
length = [data.bytesize].pack('L>')
|
53
|
-
@socket.write(length + data)
|
54
|
-
end
|
55
|
-
|
56
|
-
def close
|
57
|
-
@socket.close
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
class Unix < Base
|
62
|
-
def self.connect(url)
|
63
|
-
uri = URI(url)
|
64
|
-
new(UNIXSocket.new(uri.path))
|
65
|
-
end
|
66
|
-
|
67
|
-
def self.listen(url)
|
68
|
-
uri = URI(url)
|
69
|
-
new(UNIXServer.new(uri.path))
|
70
|
-
end
|
71
|
-
|
72
|
-
def initialize(socket)
|
73
|
-
@socket = socket
|
74
|
-
end
|
75
|
-
|
76
|
-
def read
|
77
|
-
length = @socket.read(4)
|
78
|
-
return nil if length.nil?
|
79
|
-
length = length.unpack('L>')[0]
|
80
|
-
@socket.read(length)
|
81
|
-
end
|
82
|
-
|
83
|
-
def write(data)
|
84
|
-
length = [data.bytesize].pack('L>')
|
85
|
-
@socket.write(length + data)
|
86
|
-
end
|
87
|
-
|
88
|
-
def close
|
89
|
-
@socket.close
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
28
|
class WebSocket < Base
|
94
29
|
def self.connect(url)
|
95
30
|
uri = URI(url)
|
data/lib/terminalwire/version.rb
CHANGED
data/lib/terminalwire.rb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require_relative "terminalwire/version"
|
4
4
|
|
5
|
-
require 'socket'
|
6
5
|
require 'forwardable'
|
7
6
|
require 'uri'
|
8
7
|
require 'zeitwerk'
|
@@ -40,10 +39,6 @@ module Terminalwire
|
|
40
39
|
respond(status: "success", response:, **data)
|
41
40
|
end
|
42
41
|
|
43
|
-
def self.protocol_key
|
44
|
-
name.split("::").last.downcase
|
45
|
-
end
|
46
|
-
|
47
42
|
private
|
48
43
|
|
49
44
|
def respond(**response)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: terminalwire
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brad Gessler
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-10-
|
11
|
+
date: 2024-10-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: async-websocket
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
19
|
+
version: '0.30'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0.
|
26
|
+
version: '0.30'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: zeitwerk
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -158,12 +158,14 @@ files:
|
|
158
158
|
- lib/generators/terminalwire/install/install_generator.rb
|
159
159
|
- lib/generators/terminalwire/install/templates/application_terminal.rb.tt
|
160
160
|
- lib/generators/terminalwire/install/templates/bin/terminalwire
|
161
|
+
- lib/generators/terminalwire/install/templates/main_terminal.rb
|
161
162
|
- lib/terminalwire.rb
|
162
163
|
- lib/terminalwire/adapter.rb
|
163
164
|
- lib/terminalwire/client.rb
|
164
165
|
- lib/terminalwire/client/entitlement.rb
|
165
166
|
- lib/terminalwire/client/exec.rb
|
166
167
|
- lib/terminalwire/client/resource.rb
|
168
|
+
- lib/terminalwire/licensing.rb
|
167
169
|
- lib/terminalwire/logging.rb
|
168
170
|
- lib/terminalwire/rails.rb
|
169
171
|
- lib/terminalwire/server.rb
|
@@ -175,7 +177,7 @@ files:
|
|
175
177
|
- sig/terminalwire.rbs
|
176
178
|
homepage: https://terminalwire.com/ruby
|
177
179
|
licenses:
|
178
|
-
- Proprietary
|
180
|
+
- Proprietary (https://terminalwire.com/license)
|
179
181
|
metadata:
|
180
182
|
allowed_push_host: https://rubygems.org/
|
181
183
|
homepage_uri: https://terminalwire.com/ruby
|