terminalwire-rails 0.3.0.alpha1

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: 6ba7bd27bf86aee365f4f45139d8a125e08fa01295d872a059570de818b834f9
4
+ data.tar.gz: 9f71189cbd898c0c4b5033e1dcaadec72126e96f35e5860fa58e6711189a7982
5
+ SHA512:
6
+ metadata.gz: 49fe21592da92e7587a2c2bd93f920d1bde2b2e4d40af8076a4d43a9405497c58e7fe343d50f4a6e831a7ea1c6f0106466904127ad2a575492c13cf7d4edcedc
7
+ data.tar.gz: 0fe43f8b5f6658131efe122161d5700bccdf8e4d958da4ba7c9cd6d72c2e9dc62cc490b2141b2cd8d26ad3068bd4683bf14274e493fb2230d2d034e0222de96d
@@ -0,0 +1,9 @@
1
+ Description:
2
+ Installs Terminalwire
3
+
4
+ Example:
5
+ bin/rails generate terminalwire:install
6
+
7
+ This will create:
8
+ app/terminal/application_terminal.rb
9
+ bin/<your-app>
@@ -0,0 +1,43 @@
1
+ require "bundler"
2
+
3
+ class Terminalwire::InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path("templates", __dir__)
5
+
6
+ argument :binary_name, type: :string, required: true, banner: "binary_name"
7
+
8
+ def create_terminal_files
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")
11
+ end
12
+
13
+ def create_binary_files
14
+ copy_file "bin/terminalwire", binary_path
15
+ chmod binary_path, 0755, verbose: false
16
+ end
17
+
18
+ def add_route
19
+ route <<~ROUTE
20
+ match "/terminal",
21
+ to: Terminalwire::Rails::Thor.new(MainTerminal),
22
+ via: [:get, :connect]
23
+ ROUTE
24
+ end
25
+
26
+ def bundle_development_dependencies
27
+ # Add the terminalwire gem to the development group in the Gemfile.
28
+ gem "terminalwire", group: :development
29
+ end
30
+
31
+ def print_post_install_message
32
+ say ""
33
+ say "Terminalwire has been successfully installed!", :green
34
+ say "Run `#{binary_path.relative_path_from(Rails.root)}` to verify everything is in working order. For support visit https://terminalwire.com."
35
+ say ""
36
+ end
37
+
38
+ private
39
+
40
+ def binary_path
41
+ Rails.root.join("bin", binary_name)
42
+ end
43
+ end
@@ -0,0 +1,21 @@
1
+ # Learn how to use Thor at http://whatisthor.com.
2
+ class ApplicationTerminal < Thor
3
+ # Enables IO Streaming.
4
+ include Terminalwire::Thor
5
+
6
+ # The name of your binary. Thor uses this for its help output.
7
+ def self.basename = "<%= binary_name %>"
8
+
9
+ private
10
+
11
+ def current_user=(user)
12
+ # The Session object is a hash-like object that encrypts and signs a hash that's
13
+ # stored on the client's file sytem. Conceptually, it's similar to Rails signed
14
+ # and encrypted client-side cookies.
15
+ session["user_id"] = user.id
16
+ end
17
+
18
+ def current_user
19
+ @current_user ||= User.find(session["user_id"])
20
+ end
21
+ end
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env terminalwire-exec
2
+ url: "ws://localhost:3000/terminal"
@@ -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
+ fail "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
+ fail "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
@@ -0,0 +1,116 @@
1
+ require "terminalwire-server"
2
+ require "thor"
3
+ require "rails"
4
+ require "jwt"
5
+
6
+ module Terminalwire
7
+ module Rails
8
+ class Session
9
+ # JWT file name for the session file.
10
+ FILENAME = "session.jwt"
11
+
12
+ # Empty dictionary the user can stash all their session data into.
13
+ EMPTY_SESSION = {}.freeze
14
+
15
+ extend Forwardable
16
+
17
+ # Delegate `dig` and `fetch` to the `read` method
18
+ def_delegators :read,
19
+ :dig, :fetch, :[]
20
+
21
+ def initialize(context:, path: nil, secret_key: self.class.secret_key)
22
+ @context = context
23
+ @path = Pathname.new(path || context.storage_path)
24
+ @config_file_path = @path.join(FILENAME)
25
+ @secret_key = secret_key
26
+
27
+ ensure_file
28
+ end
29
+
30
+ def read
31
+ jwt_token = @context.file.read(@config_file_path)
32
+ decoded_data = JWT.decode(jwt_token, @secret_key, true, algorithm: 'HS256')
33
+ decoded_data[0] # JWT payload is the first element in the array
34
+ rescue JWT::DecodeError => e
35
+ raise "Invalid or tampered file: #{e.message}"
36
+ end
37
+
38
+ def reset
39
+ @context.file.delete @config_file_path
40
+ end
41
+
42
+ def edit
43
+ config = read
44
+ yield config
45
+ write(config)
46
+ end
47
+
48
+ def []=(key, value)
49
+ edit { |config| config[key] = value }
50
+ end
51
+
52
+ def write(config)
53
+ token = JWT.encode(config, @secret_key, 'HS256')
54
+ @context.file.write(@config_file_path, token)
55
+ end
56
+
57
+ private
58
+
59
+ def ensure_file
60
+ return true if @context.file.exist? @config_file_path
61
+ # Create the path if it doesn't exist on the client.
62
+ @context.directory.create @path
63
+ # Write an empty configuration on initialization
64
+ write(EMPTY_SESSION)
65
+ end
66
+
67
+ def self.secret_key
68
+ ::Rails.application.secret_key_base
69
+ end
70
+ end
71
+
72
+ class Thor < Server::WebSocket
73
+ include Logging
74
+
75
+ def initialize(cli_class)
76
+ @cli_class = cli_class
77
+
78
+ unless @cli_class.included_modules.include?(Terminalwire::Server::Thor)
79
+ raise 'Add `include Terminalwire::Server::Thor` to the #{@cli_class.inspect} class.'
80
+ end
81
+ end
82
+
83
+ def error_message
84
+ "An error occurred. Please try again."
85
+ end
86
+
87
+ def handle(adapter)
88
+ logger.info "ThorServer: Running #{@cli_class.inspect}"
89
+ while message = adapter.read
90
+ case message
91
+ in { event: "initialization", protocol:, program: { arguments: }, entitlement: }
92
+ context = Terminalwire::Server::Context.new(adapter:, entitlement:)
93
+
94
+ begin
95
+ @cli_class.start(arguments, context:)
96
+ context.exit
97
+ rescue StandardError => e
98
+ if ::Rails.application.config.consider_all_requests_local
99
+ # Show the full error message with stack trace in development
100
+ context.stderr.puts "#{e.inspect}\n#{e.backtrace.join("\n")}"
101
+ else
102
+ # Show a generic message in production
103
+ context.stderr.puts error_message
104
+ end
105
+ context.exit 1
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ # Alias so we can put off breaking `include Terminalwire::Thor`
114
+ # in the ApplicationTerminal class.
115
+ Thor = Terminalwire::Server::Thor
116
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'terminalwire/rails'
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: terminalwire-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0.alpha1
5
+ platform: ruby
6
+ authors:
7
+ - Brad Gessler
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-12-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: terminalwire-server
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.3.0.alpha1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.3.0.alpha1
27
+ - !ruby/object:Gem::Dependency
28
+ name: rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '7.2'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '7.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: jwt
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
55
+ description: Stream command-line apps from your server without a web API
56
+ email:
57
+ - brad@terminalwire.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - lib/generators/terminalwire/install/USAGE
63
+ - lib/generators/terminalwire/install/install_generator.rb
64
+ - lib/generators/terminalwire/install/templates/application_terminal.rb.tt
65
+ - lib/generators/terminalwire/install/templates/bin/terminalwire
66
+ - lib/generators/terminalwire/install/templates/main_terminal.rb
67
+ - lib/terminalwire-rails.rb
68
+ - lib/terminalwire/rails.rb
69
+ homepage: https://terminalwire.com/ruby
70
+ licenses:
71
+ - Proprietary (https://terminalwire.com/license)
72
+ metadata:
73
+ allowed_push_host: https://rubygems.org/
74
+ homepage_uri: https://terminalwire.com/ruby
75
+ source_code_uri: https://github.com/terminalwire/ruby/tree/main/terminalwire-rails
76
+ changelog_uri: https://github.com/terminalwire/ruby/tags
77
+ funding_uri: https://terminalwire.com/funding
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: 3.0.0
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubygems_version: 3.5.9
94
+ signing_key:
95
+ specification_version: 4
96
+ summary: Ship a CLI for your web app. No API required.
97
+ test_files: []