terminalwire 0.1.7 → 0.1.9
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 +4 -4
- data/lib/terminalwire/adapter.rb +24 -3
- data/lib/terminalwire/client/entitlement.rb +93 -12
- data/lib/terminalwire/client/resource.rb +37 -16
- data/lib/terminalwire/client.rb +6 -3
- data/lib/terminalwire/rails.rb +2 -2
- data/lib/terminalwire/server/context.rb +42 -0
- data/lib/terminalwire/server/resource.rb +107 -0
- data/lib/terminalwire/server.rb +1 -116
- data/lib/terminalwire/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a0eeaa4d2a6f23524e964bbd0fa0e507eca1415f591e71a565a47553411cf916
|
4
|
+
data.tar.gz: 30d9f26ce42e8e5a4f301bd4d99ca5ead398554f737b0ffe693aa921fd8e8bb2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb69226b00de7e49c73bcc1383aa5d31645cddd49d40c945131cb2e5b7c8c962a206c97127812278642c08371641e01a9a5d223f01c75551689d50a76257f691
|
7
|
+
data.tar.gz: 62412bf6431e84e49895887ca879045038bc046470b32863056db319f4e69e0f8ecfdfac2e9141543d3ecf0dcbc5d3ba9821046828bd05a40653ab60512db0a5
|
data/lib/terminalwire/adapter.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'msgpack'
|
2
2
|
|
3
|
-
module Terminalwire
|
4
|
-
|
5
|
-
|
3
|
+
module Terminalwire::Adapter
|
4
|
+
# Works with TCP, Unix, WebSocket, and other socket-like abstractions.
|
5
|
+
class Socket
|
6
|
+
include Terminalwire::Logging
|
6
7
|
|
7
8
|
attr_reader :transport
|
8
9
|
|
@@ -29,4 +30,24 @@ module Terminalwire
|
|
29
30
|
@transport.close
|
30
31
|
end
|
31
32
|
end
|
33
|
+
|
34
|
+
# This is a test adapter that can be used for testing purposes.
|
35
|
+
class Test
|
36
|
+
attr_reader :responses
|
37
|
+
|
38
|
+
def initialize(responses = [])
|
39
|
+
@responses = responses
|
40
|
+
end
|
41
|
+
|
42
|
+
def write(**data)
|
43
|
+
@responses << data
|
44
|
+
end
|
45
|
+
|
46
|
+
def response
|
47
|
+
@responses.pop
|
48
|
+
end
|
49
|
+
|
50
|
+
def close
|
51
|
+
end
|
52
|
+
end
|
32
53
|
end
|
@@ -3,6 +3,73 @@ require "pathname"
|
|
3
3
|
module Terminalwire::Client
|
4
4
|
module Entitlement
|
5
5
|
class Paths
|
6
|
+
class Permit
|
7
|
+
attr_reader :path, :mode
|
8
|
+
# Ensure the default file mode is read/write for owner only. This ensures
|
9
|
+
# that if the server tries uploading an executable file, it won't be when it
|
10
|
+
# lands on the client.
|
11
|
+
#
|
12
|
+
# Eventually we'll move this into entitlements so the client can set maximum
|
13
|
+
# permissions for files and directories.
|
14
|
+
MODE = 0o600 # rw-------
|
15
|
+
|
16
|
+
# Constants for permission bit masks
|
17
|
+
OWNER_PERMISSIONS = 0o700 # rwx------
|
18
|
+
GROUP_PERMISSIONS = 0o070 # ---rwx---
|
19
|
+
OTHERS_PERMISSIONS = 0o007 # ------rwx
|
20
|
+
|
21
|
+
# We'll validate that modes are within this range.
|
22
|
+
MODE_RANGE = 0o000..0o777
|
23
|
+
|
24
|
+
def initialize(path:, mode: MODE)
|
25
|
+
@path = Pathname.new(path).expand_path
|
26
|
+
@mode = convert(mode)
|
27
|
+
end
|
28
|
+
|
29
|
+
def permitted_path?(path)
|
30
|
+
# This MUST be done via File.fnmatch because Pathname#fnmatch does not work. If you
|
31
|
+
# try changing this 🚨 YOU MAY CIRCUMVENT THE SECURITY MEASURES IN PLACE. 🚨
|
32
|
+
File.fnmatch @path.to_s, File.expand_path(path), File::FNM_PATHNAME
|
33
|
+
end
|
34
|
+
|
35
|
+
def permitted_mode?(value)
|
36
|
+
# Ensure the mode is at least as permissive as the permitted mode.
|
37
|
+
mode = convert(value)
|
38
|
+
|
39
|
+
# Extract permission bits for owner, group, and others
|
40
|
+
owner_bits = mode & OWNER_PERMISSIONS
|
41
|
+
group_bits = mode & GROUP_PERMISSIONS
|
42
|
+
others_bits = mode & OTHERS_PERMISSIONS
|
43
|
+
|
44
|
+
# Ensure that the mode doesn't grant more permissions than @mode in any class (owner, group, others)
|
45
|
+
(owner_bits <= @mode & OWNER_PERMISSIONS) &&
|
46
|
+
(group_bits <= @mode & GROUP_PERMISSIONS) &&
|
47
|
+
(others_bits <= @mode & OTHERS_PERMISSIONS)
|
48
|
+
end
|
49
|
+
|
50
|
+
def permitted?(path:, mode: @mode)
|
51
|
+
permitted_path?(path) && permitted_mode?(mode)
|
52
|
+
end
|
53
|
+
|
54
|
+
def serialize
|
55
|
+
{
|
56
|
+
location: @path.to_s,
|
57
|
+
mode: @mode
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
protected
|
62
|
+
def convert(value)
|
63
|
+
mode = Integer(value)
|
64
|
+
raise ArgumentError, "The mode #{format_octet value} must be an octet value between #{format_octet MODE_RANGE.first} and #{format_octet MODE_RANGE.last}" unless MODE_RANGE.cover?(mode)
|
65
|
+
mode
|
66
|
+
end
|
67
|
+
|
68
|
+
def format_octet(value)
|
69
|
+
format("0o%03o", value)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
6
73
|
include Enumerable
|
7
74
|
|
8
75
|
def initialize
|
@@ -13,23 +80,20 @@ module Terminalwire::Client
|
|
13
80
|
@permitted.each(&)
|
14
81
|
end
|
15
82
|
|
16
|
-
def permit(path)
|
17
|
-
@permitted.append
|
83
|
+
def permit(path, **)
|
84
|
+
@permitted.append Permit.new(path:, **)
|
18
85
|
end
|
19
86
|
|
20
|
-
def permitted?(path)
|
21
|
-
|
87
|
+
def permitted?(path, mode: nil)
|
88
|
+
if mode
|
89
|
+
find { |it| it.permitted_path?(path) and it.permitted_mode?(mode) }
|
90
|
+
else
|
91
|
+
find { |it| it.permitted_path?(path) }
|
92
|
+
end
|
22
93
|
end
|
23
94
|
|
24
95
|
def serialize
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
def matches?(permitted:, path:)
|
30
|
-
# This MUST be done via File.fnmatch because Pathname#fnmatch does not work. If you
|
31
|
-
# try changing this 🚨 YOU MAY CIRCUMVENT THE SECURITY MEASURES IN PLACE. 🚨
|
32
|
-
File.fnmatch permitted.to_s, File.expand_path(path), File::FNM_PATHNAME
|
96
|
+
map(&:serialize)
|
33
97
|
end
|
34
98
|
end
|
35
99
|
|
@@ -105,6 +169,10 @@ module Terminalwire::Client
|
|
105
169
|
class RootPolicy < Policy
|
106
170
|
HOST = "terminalwire.com".freeze
|
107
171
|
|
172
|
+
# Ensure the binary stubs are executable. This increases the
|
173
|
+
# file mode entitlement so that stubs created in ./bin are executable.
|
174
|
+
BINARY_PATH_FILE_MODE = 0o755
|
175
|
+
|
108
176
|
def initialize(*, **, &)
|
109
177
|
# Make damn sure the authority is set to Terminalwire.
|
110
178
|
super(*, authority: HOST, **, &)
|
@@ -112,6 +180,9 @@ module Terminalwire::Client
|
|
112
180
|
# Now setup special permitted paths.
|
113
181
|
@paths.permit root_path
|
114
182
|
@paths.permit root_pattern
|
183
|
+
|
184
|
+
# Permit terminalwire to grant execute permissions to the binary stubs.
|
185
|
+
@paths.permit binary_pattern, mode: BINARY_PATH_FILE_MODE
|
115
186
|
end
|
116
187
|
|
117
188
|
# Grant access to the `~/.terminalwire/**/*` path so users can install
|
@@ -119,6 +190,16 @@ module Terminalwire::Client
|
|
119
190
|
def root_pattern
|
120
191
|
root_path.join("**/*")
|
121
192
|
end
|
193
|
+
|
194
|
+
# Path where the terminalwire binary stubs are stored.
|
195
|
+
def binary_path
|
196
|
+
root_path.join("bin")
|
197
|
+
end
|
198
|
+
|
199
|
+
# Pattern for the binary path.
|
200
|
+
def binary_pattern
|
201
|
+
binary_path.join("*")
|
202
|
+
end
|
122
203
|
end
|
123
204
|
|
124
205
|
def self.from_url(url)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
|
1
3
|
module Terminalwire::Client::Resource
|
2
4
|
# Dispatches messages from the Client::Handler to the appropriate resource.
|
3
5
|
class Handler
|
@@ -102,28 +104,16 @@ module Terminalwire::Client::Resource
|
|
102
104
|
class File < Base
|
103
105
|
File = ::File
|
104
106
|
|
105
|
-
# Ensure the default file mode is read/write for owner only. This ensures
|
106
|
-
# that if the server tries uploading an executable file, it won't be when it
|
107
|
-
# lands on the client.
|
108
|
-
#
|
109
|
-
# Eventually we'll move this into entitlements so the client can set maximum
|
110
|
-
# permissions for files and directories.
|
111
|
-
FILE_PERMISSIONS = 0o600 # rw-------
|
112
|
-
|
113
107
|
def read(path:)
|
114
108
|
File.read File.expand_path(path)
|
115
109
|
end
|
116
110
|
|
117
|
-
def write(path:, content:)
|
118
|
-
File.open(File.expand_path(path), "w",
|
119
|
-
end
|
120
|
-
|
121
|
-
def append(path:, content:)
|
122
|
-
File.open(File.expand_path(path), "a", FILE_PERMISSIONS) { |f| f.write(content) }
|
111
|
+
def write(path:, content:, mode: nil)
|
112
|
+
File.open(File.expand_path(path), "w", mode) { |f| f.write(content) }
|
123
113
|
end
|
124
114
|
|
125
|
-
def
|
126
|
-
|
115
|
+
def append(path:, content:, mode: nil)
|
116
|
+
File.open(File.expand_path(path), "a", mode) { |f| f.write(content) }
|
127
117
|
end
|
128
118
|
|
129
119
|
def delete(path:)
|
@@ -134,6 +124,37 @@ module Terminalwire::Client::Resource
|
|
134
124
|
File.exist? File.expand_path(path)
|
135
125
|
end
|
136
126
|
|
127
|
+
def change_mode(path:, mode:)
|
128
|
+
File.chmod(mode, File.expand_path(path))
|
129
|
+
end
|
130
|
+
|
131
|
+
protected
|
132
|
+
def permit(command, path:, mode: nil, **)
|
133
|
+
@entitlement.paths.permitted? path, mode:
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
class Directory < Base
|
138
|
+
File = ::File
|
139
|
+
|
140
|
+
def list(path:)
|
141
|
+
Dir.glob File.expand_path(path)
|
142
|
+
end
|
143
|
+
|
144
|
+
def create(path:)
|
145
|
+
FileUtils.mkdir_p File.expand_path(path)
|
146
|
+
rescue Errno::EEXIST
|
147
|
+
# Do nothing
|
148
|
+
end
|
149
|
+
|
150
|
+
def exist(path:)
|
151
|
+
Dir.exist? File.expand_path(path)
|
152
|
+
end
|
153
|
+
|
154
|
+
def delete(path:)
|
155
|
+
Dir.delete(File.expand_path(path))
|
156
|
+
end
|
157
|
+
|
137
158
|
def permit(command, path:, **)
|
138
159
|
@entitlement.paths.permitted? path
|
139
160
|
end
|
data/lib/terminalwire/client.rb
CHANGED
@@ -17,12 +17,15 @@ module Terminalwire
|
|
17
17
|
@program_arguments = arguments
|
18
18
|
@program_name = program_name
|
19
19
|
|
20
|
+
FileUtils.mkdir_p entitlement.storage_path
|
21
|
+
|
20
22
|
@resources = Resource::Handler.new do |it|
|
21
23
|
it << Resource::STDOUT.new("stdout", @adapter, entitlement:)
|
22
24
|
it << Resource::STDIN.new("stdin", @adapter, entitlement:)
|
23
25
|
it << Resource::STDERR.new("stderr", @adapter, entitlement:)
|
24
26
|
it << Resource::Browser.new("browser", @adapter, entitlement:)
|
25
27
|
it << Resource::File.new("file", @adapter, entitlement:)
|
28
|
+
it << Resource::Directory.new("directory", @adapter, entitlement:)
|
26
29
|
end
|
27
30
|
end
|
28
31
|
|
@@ -53,14 +56,14 @@ module Terminalwire
|
|
53
56
|
def self.tcp(...)
|
54
57
|
socket = TCPSocket.new(...)
|
55
58
|
transport = Terminalwire::Transport::Socket.new(socket)
|
56
|
-
adapter = Terminalwire::Adapter.new(transport)
|
59
|
+
adapter = Terminalwire::Adapter::Socket.new(transport)
|
57
60
|
Terminalwire::Client::Handler.new(adapter)
|
58
61
|
end
|
59
62
|
|
60
63
|
def self.socket(...)
|
61
64
|
socket = UNIXSocket.new(...)
|
62
65
|
transport = Terminalwire::Transport::Socket.new(socket)
|
63
|
-
adapter = Terminalwire::Adapter.new(transport)
|
66
|
+
adapter = Terminalwire::Adapter::Socket.new(transport)
|
64
67
|
Terminalwire::Client::Handler.new(adapter)
|
65
68
|
end
|
66
69
|
|
@@ -84,7 +87,7 @@ module Terminalwire
|
|
84
87
|
|
85
88
|
Async::WebSocket::Client.connect(endpoint) do |adapter|
|
86
89
|
transport = Terminalwire::Transport::WebSocket.new(adapter)
|
87
|
-
adapter = Terminalwire::Adapter.new(transport)
|
90
|
+
adapter = Terminalwire::Adapter::Socket.new(transport)
|
88
91
|
entitlement ||= Entitlement.from_url(url)
|
89
92
|
Terminalwire::Client::Handler.new(adapter, arguments:, entitlement:).connect
|
90
93
|
end
|
data/lib/terminalwire/rails.rb
CHANGED
@@ -18,7 +18,7 @@ module Terminalwire::Rails
|
|
18
18
|
|
19
19
|
def initialize(context:, path: nil, secret_key: self.class.secret_key)
|
20
20
|
@context = context
|
21
|
-
@path = path || context.storage_path
|
21
|
+
@path = Pathname.new(path || context.storage_path)
|
22
22
|
@config_file_path = @path.join(FILENAME)
|
23
23
|
@secret_key = secret_key
|
24
24
|
|
@@ -57,7 +57,7 @@ module Terminalwire::Rails
|
|
57
57
|
def ensure_file
|
58
58
|
return true if @context.file.exist? @config_file_path
|
59
59
|
# Create the path if it doesn't exist on the client.
|
60
|
-
@context.
|
60
|
+
@context.directory.create @path
|
61
61
|
# Write an empty configuration on initialization
|
62
62
|
write(EMPTY_SESSION)
|
63
63
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
|
3
|
+
module Terminalwire::Server
|
4
|
+
class Context
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
attr_reader :stdout, :stdin, :stderr, :browser, :file, :directory, :storage_path
|
8
|
+
|
9
|
+
def_delegators :@stdout, :puts, :print
|
10
|
+
def_delegators :@stdin, :gets, :getpass
|
11
|
+
|
12
|
+
def initialize(adapter:, entitlement:)
|
13
|
+
@adapter = adapter
|
14
|
+
|
15
|
+
@entitlement = entitlement
|
16
|
+
@storage_path = Pathname.new(entitlement.fetch(:storage_path))
|
17
|
+
|
18
|
+
@stdout = Resource::STDOUT.new("stdout", @adapter)
|
19
|
+
@stdin = Resource::STDIN.new("stdin", @adapter)
|
20
|
+
@stderr = Resource::STDERR.new("stderr", @adapter)
|
21
|
+
@browser = Resource::Browser.new("browser", @adapter)
|
22
|
+
@file = Resource::File.new("file", @adapter)
|
23
|
+
@directory = Resource::Directory.new("directory", @adapter)
|
24
|
+
|
25
|
+
if block_given?
|
26
|
+
begin
|
27
|
+
yield self
|
28
|
+
ensure
|
29
|
+
exit
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def exit(status = 0)
|
35
|
+
@adapter.write(event: "exit", status: status)
|
36
|
+
end
|
37
|
+
|
38
|
+
def close
|
39
|
+
@adapter.close
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module Terminalwire::Server
|
2
|
+
module Resource
|
3
|
+
class Base < Terminalwire::Resource::Base
|
4
|
+
private
|
5
|
+
|
6
|
+
def command(command, **parameters)
|
7
|
+
@adapter.write(
|
8
|
+
event: "resource",
|
9
|
+
name: @name,
|
10
|
+
action: "command",
|
11
|
+
command: command,
|
12
|
+
parameters: parameters
|
13
|
+
)
|
14
|
+
|
15
|
+
response = @adapter.recv
|
16
|
+
case response.fetch(:status)
|
17
|
+
when "success"
|
18
|
+
response.fetch(:response)
|
19
|
+
when "failure"
|
20
|
+
raise Terminalwire::Error, response.inspect
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class STDOUT < Base
|
26
|
+
def puts(data)
|
27
|
+
command("print_line", data: data)
|
28
|
+
end
|
29
|
+
|
30
|
+
def print(data)
|
31
|
+
command("print", data: data)
|
32
|
+
end
|
33
|
+
|
34
|
+
def flush
|
35
|
+
# Do nothing
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class STDERR < STDOUT
|
40
|
+
end
|
41
|
+
|
42
|
+
class STDIN < Base
|
43
|
+
def getpass
|
44
|
+
command("read_password")
|
45
|
+
end
|
46
|
+
|
47
|
+
def gets
|
48
|
+
command("read_line")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class File < Base
|
53
|
+
def read(path)
|
54
|
+
command("read", path: path.to_s)
|
55
|
+
end
|
56
|
+
|
57
|
+
def write(path, content)
|
58
|
+
command("write", path: path.to_s, content:)
|
59
|
+
end
|
60
|
+
|
61
|
+
def append(path, content)
|
62
|
+
command("append", path: path.to_s, content:)
|
63
|
+
end
|
64
|
+
|
65
|
+
def delete(path)
|
66
|
+
command("delete", path: path.to_s)
|
67
|
+
end
|
68
|
+
alias :rm :delete
|
69
|
+
|
70
|
+
def exist?(path)
|
71
|
+
command("exist", path: path.to_s)
|
72
|
+
end
|
73
|
+
|
74
|
+
def change_mode(path, mode)
|
75
|
+
command("change_mode", path: path.to_s, mode:)
|
76
|
+
end
|
77
|
+
alias :chmod :change_mode
|
78
|
+
end
|
79
|
+
|
80
|
+
class Directory < Base
|
81
|
+
def list(path)
|
82
|
+
command("list", path: path.to_s)
|
83
|
+
end
|
84
|
+
alias :ls :list
|
85
|
+
|
86
|
+
def create(path)
|
87
|
+
command("create", path: path.to_s)
|
88
|
+
end
|
89
|
+
alias :mkdir :create
|
90
|
+
|
91
|
+
def exist?(path)
|
92
|
+
command("exist", path: path.to_s)
|
93
|
+
end
|
94
|
+
|
95
|
+
def delete(path)
|
96
|
+
command("delete", path: path.to_s)
|
97
|
+
end
|
98
|
+
alias :rm :delete
|
99
|
+
end
|
100
|
+
|
101
|
+
class Browser < Base
|
102
|
+
def launch(url)
|
103
|
+
command("launch", url: url)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
data/lib/terminalwire/server.rb
CHANGED
@@ -2,121 +2,6 @@ require "thor"
|
|
2
2
|
|
3
3
|
module Terminalwire
|
4
4
|
module Server
|
5
|
-
module Resource
|
6
|
-
class Base < Terminalwire::Resource::Base
|
7
|
-
private
|
8
|
-
|
9
|
-
def command(command, **parameters)
|
10
|
-
@adapter.write(
|
11
|
-
event: "resource",
|
12
|
-
name: @name,
|
13
|
-
action: "command",
|
14
|
-
command: command,
|
15
|
-
parameters: parameters
|
16
|
-
)
|
17
|
-
@adapter.recv&.fetch(:response)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
class STDOUT < Base
|
22
|
-
def puts(data)
|
23
|
-
command("print_line", data: data)
|
24
|
-
end
|
25
|
-
|
26
|
-
def print(data)
|
27
|
-
command("print", data: data)
|
28
|
-
end
|
29
|
-
|
30
|
-
def flush
|
31
|
-
# Do nothing
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
class STDERR < STDOUT
|
36
|
-
end
|
37
|
-
|
38
|
-
class STDIN < Base
|
39
|
-
def getpass
|
40
|
-
command("read_password")
|
41
|
-
end
|
42
|
-
|
43
|
-
def gets
|
44
|
-
command("read_line")
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
class File < Base
|
49
|
-
def read(path)
|
50
|
-
command("read", path: path.to_s)
|
51
|
-
end
|
52
|
-
|
53
|
-
def write(path, content)
|
54
|
-
command("write", path: path.to_s, content:)
|
55
|
-
end
|
56
|
-
|
57
|
-
def append(path, content)
|
58
|
-
command("append", path: path.to_s, content:)
|
59
|
-
end
|
60
|
-
|
61
|
-
def mkdir(path)
|
62
|
-
command("mkdir", path: path.to_s)
|
63
|
-
end
|
64
|
-
|
65
|
-
def delete(path)
|
66
|
-
command("delete", path: path.to_s)
|
67
|
-
end
|
68
|
-
|
69
|
-
def exist?(path)
|
70
|
-
command("exist", path: path.to_s)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
class Browser < Base
|
75
|
-
def launch(url)
|
76
|
-
command("launch", url: url)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
class Context
|
82
|
-
extend Forwardable
|
83
|
-
|
84
|
-
attr_reader :stdout, :stdin, :stderr, :browser, :file, :storage_path
|
85
|
-
|
86
|
-
def_delegators :@stdout, :puts, :print
|
87
|
-
def_delegators :@stdin, :gets, :getpass
|
88
|
-
|
89
|
-
def initialize(adapter:, entitlement:)
|
90
|
-
@adapter = adapter
|
91
|
-
|
92
|
-
# TODO: Encapsulate entitlement in a class instead of a hash.
|
93
|
-
@entitlement = entitlement
|
94
|
-
@storage_path = Pathname.new(entitlement.fetch(:storage_path))
|
95
|
-
|
96
|
-
@stdout = Server::Resource::STDOUT.new("stdout", @adapter)
|
97
|
-
@stdin = Server::Resource::STDIN.new("stdin", @adapter)
|
98
|
-
@stderr = Server::Resource::STDERR.new("stderr", @adapter)
|
99
|
-
@browser = Server::Resource::Browser.new("browser", @adapter)
|
100
|
-
@file = Server::Resource::File.new("file", @adapter)
|
101
|
-
|
102
|
-
if block_given?
|
103
|
-
begin
|
104
|
-
yield self
|
105
|
-
ensure
|
106
|
-
exit
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
def exit(status = 0)
|
112
|
-
@adapter.write(event: "exit", status: status)
|
113
|
-
end
|
114
|
-
|
115
|
-
def close
|
116
|
-
@adapter.close
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
5
|
class MyCLI < ::Thor
|
121
6
|
include Terminalwire::Thor
|
122
7
|
|
@@ -161,7 +46,7 @@ module Terminalwire
|
|
161
46
|
|
162
47
|
def call(env)
|
163
48
|
Async::WebSocket::Adapters::Rack.open(env, protocols: ['ws']) do |connection|
|
164
|
-
run(Adapter.new(Terminalwire::Transport::WebSocket.new(connection)))
|
49
|
+
run(Adapter::Socket.new(Terminalwire::Transport::WebSocket.new(connection)))
|
165
50
|
end or [200, { "Content-Type" => "text/plain" }, ["Connect via WebSockets"]]
|
166
51
|
end
|
167
52
|
|
data/lib/terminalwire/version.rb
CHANGED
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.9
|
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-09-
|
11
|
+
date: 2024-09-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: async-websocket
|
@@ -167,6 +167,8 @@ files:
|
|
167
167
|
- lib/terminalwire/logging.rb
|
168
168
|
- lib/terminalwire/rails.rb
|
169
169
|
- lib/terminalwire/server.rb
|
170
|
+
- lib/terminalwire/server/context.rb
|
171
|
+
- lib/terminalwire/server/resource.rb
|
170
172
|
- lib/terminalwire/thor.rb
|
171
173
|
- lib/terminalwire/transport.rb
|
172
174
|
- lib/terminalwire/version.rb
|
@@ -194,7 +196,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
194
196
|
- !ruby/object:Gem::Version
|
195
197
|
version: '0'
|
196
198
|
requirements: []
|
197
|
-
rubygems_version: 3.5.
|
199
|
+
rubygems_version: 3.5.9
|
198
200
|
signing_key:
|
199
201
|
specification_version: 4
|
200
202
|
summary: Ship a CLI for your web app. No API required.
|