siwe_rails 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,65 @@
1
+ html, body {
2
+ position: relative;
3
+ width: 100%;
4
+ height: 100%;
5
+ }
6
+
7
+ body {
8
+ color: #333;
9
+ margin: 0;
10
+ padding: 8px;
11
+ box-sizing: border-box;
12
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
13
+ }
14
+
15
+ a {
16
+ color: rgb(0,100,200);
17
+ text-decoration: none;
18
+ }
19
+
20
+ a:hover {
21
+ text-decoration: underline;
22
+ }
23
+
24
+ a:visited {
25
+ color: rgb(0,80,160);
26
+ }
27
+
28
+ label {
29
+ display: block;
30
+ }
31
+
32
+ input, button, select, textarea {
33
+ font-family: inherit;
34
+ font-size: inherit;
35
+ -webkit-padding: 0.4em 0;
36
+ padding: 0.4em;
37
+ margin: 0 0 0.5em 0;
38
+ box-sizing: border-box;
39
+ border: 1px solid #ccc;
40
+ border-radius: 2px;
41
+ }
42
+
43
+ input:disabled {
44
+ color: #ccc;
45
+ }
46
+
47
+ button {
48
+ color: #333;
49
+ background-color: #f4f4f4;
50
+ outline: none;
51
+ }
52
+
53
+ button:disabled {
54
+ color: #999;
55
+ }
56
+
57
+ button:not(:disabled):active {
58
+ background-color: #ddd;
59
+ }
60
+
61
+ button:focus {
62
+ border-color: #666;
63
+ }
64
+
65
+ *,:after,:before{border:0 solid;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-size:100%;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}*,:after,:before{--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-transform:translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));--tw-border-opacity:1;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;border-color:rgb(229 231 235/var(--tw-border-opacity))}.visible{visibility:visible}.invisible{visibility:hidden}.mb-8{margin-bottom:2rem}.mt-auto{margin-top:auto}.flex{display:flex}.h-screen{height:100vh}.h-96{height:24rem}.h-12{height:3rem}.h-8{height:2rem}.w-full{width:100%}.w-96{width:24rem}.w-6{width:1.5rem}.flex-grow{flex-grow:1}.transform{transform:var(--tw-transform)}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-center{justify-content:center}.justify-evenly{justify-content:space-evenly}.self-center{align-self:center}.rounded-20{border-radius:20px}.border{border-width:1px}.border-white{--tw-border-opacity:1;border-color:rgb(255 255 255/var(--tw-border-opacity))}.bg-gray{--tw-bg-opacity:1;background-color:rgb(33 33 33/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-cover{background-size:cover}.bg-center{background-position:50%}.bg-no-repeat{background-repeat:no-repeat}.p-12{padding:3rem}.text-center{text-align:center}.font-satoshi{font-family:Satoshi}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color)}.shadow-white{--tw-shadow-color:#fff;--tw-shadow:var(--tw-shadow-colored)}.transition-all{transition-duration:.15s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-100{transition-duration:.1s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.tooltip{position:absolute;visibility:hidden}.has-tooltip:hover .tooltip{visibility:visible;z-index:50}body,html{background:#ecf2fe;display:flex;flex-direction:column;font-family:Satoshi;font-size:18px;height:100vh;margin:0;overflow-x:hidden;padding:0;position:relative;width:100vw}h1,h2,h3,h4,h5,h6{font-family:Satoshi;font-weight:800}h1{font-size:76px;letter-spacing:-4.5%;line-height:129px}h2{font-size:66px;letter-spacing:-3%;line-height:101px}h3{font-size:52px;letter-spacing:-1.5%;line-height:80px}h4{font-size:48px;letter-spacing:-1%;line-height:63px}h5{font-size:32px;line-height:49px}h5,h6{letter-spacing:-.5%}h6{font-size:24px;line-height:37px}body{color:#222}a{color:#04d2ca;text-decoration:none}td,th{font-family:Satoshi;font-weight:400}pre{word-wrap:break-word;white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap}.web3modal-modal-lightbox{z-index:30!important}.walletconnect-modal__base{background-color:#273137!important}.walletconnect-qrcode__text{color:#fff!important}.walletconnect-modal__mobile__toggle{background:hsla(0,0%,100%,.1)!important}.walletconnect-qrcode__image{border:24px solid #fff!important;border-radius:8px!important}.walletconnect-modal__base__row:hover{background:hsla(0,0%,100%,.1)!important}.walletconnect-modal__mobile__toggle_selector{background:hsla(0,0%,100%,.2)!important}::-webkit-scrollbar-track{background-color:#ccc;border-radius:8px}::-webkit-scrollbar-thumb{background-color:#888;border-radius:8px}::-webkit-scrollbar{background-color:#ccc;border-radius:8px;height:6px;width:6px}.grecaptcha-badge{visibility:hidden}.hover\:scale-105:hover{--tw-scale-x:1.05;--tw-scale-y:1.05;transform:var(--tw-transform)}
@@ -0,0 +1,3 @@
1
+ body > div.background {
2
+ background-image: image-url("siwe_rails/swe-landing.svg");
3
+ }
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'siwe'
4
+
5
+ module SiweRails
6
+ class ApplicationController < ActionController::Base
7
+ SESSION_SIWE_MESSAGE_KEY = 'siwe/message' # Session key
8
+
9
+ def index
10
+ render :index
11
+ end
12
+
13
+ # /#{prefix}/message
14
+ def message
15
+ message = Siwe::Message.new(
16
+ request.host_with_port,
17
+ request.params[:address],
18
+ "#{request.protocol}#{request.host_with_port}",
19
+ '1',
20
+ sign_params
21
+ )
22
+ session[SESSION_SIWE_MESSAGE_KEY] = message.to_json_string
23
+ render plain: message.prepare_message
24
+ end
25
+
26
+ # /#{prefix}/signature
27
+ def signature
28
+ message = Siwe::Message.from_json_string session[SESSION_SIWE_MESSAGE_KEY]
29
+
30
+ if message.validate(params.require(:signature))
31
+ session[SESSION_SIWE_MESSAGE_KEY] = nil
32
+ session[SiweRails.SIWE_ENS] = params[:ens]
33
+ session[SiweRails.SIWE_ADDRESS] = message.address
34
+
35
+ redirect_to SiweRails.redirect_uri, status: 308
36
+ else
37
+ head :bad_request
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ # Calculates expiration date
44
+ def expires_at
45
+ (Time.now.utc + SiweRails.expiration_time).iso8601
46
+ end
47
+
48
+ # Default required params
49
+ def default_sign_params
50
+ {
51
+ statement: SiweRails.statement,
52
+ nonce: Siwe::Util.generate_nonce,
53
+ chain_id: request.params[:chainId]
54
+ }
55
+ end
56
+
57
+ # Add optional params if present
58
+ def sign_params
59
+ params = default_sign_params
60
+ params[:expiration_time] = expires_at unless SiweRails.expiration_time.nil?
61
+ params[:not_before] = SiweRails.not_before unless SiweRails.not_before.nil?
62
+ params[:request_id] = SecureRandom.uuid if SiweRails.request_id
63
+ params[:resources] = SiweRails.resources unless SiweRails.resources.nil?
64
+ params
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,63 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>SIWE Rails</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+
8
+ <%= stylesheet_link_tag "siwe_rails/application", media: "all" %>
9
+ <%= stylesheet_link_tag "siwe_rails/background", media: "all" %>
10
+
11
+ <link
12
+ href="https://api.fontshare.com/css?f[]=satoshi@300,301,400,401,500,501,700,701,900,901,1,2&display=swap"
13
+ rel="stylesheet"
14
+ />
15
+
16
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/ethers/5.5.2/ethers.umd.min.js"></script>
17
+ <script src="https://cdn.jsdelivr.net/npm/web3modal@1.9.5/dist/index.min.js"></script>
18
+ <%= javascript_include_tag "siwe_rails/web3bundle" %>
19
+ <%= javascript_include_tag "siwe_rails/siwe" %>
20
+ </head>
21
+ <body>
22
+
23
+ <div class="background bg-no-repeat bg-cover bg-center bg-swe-landing font-satoshi bg-gray flex-grow w-full h-screen items-center flex justify-center flex-wrap flex-col">
24
+ <div class="w-96 text-center bg-white rounded-20 text-grey flex h-96 flex-col p-12 shadow-lg shadow-white">
25
+ <%= image_tag("siwe_rails/modal_icon.png", :height => 72, :width => 72, :alt => "Ethereum logo", :class => "self-center mb-8") %>
26
+ <h5>Welcome</h5>
27
+ <span class="text-xs">Sign-In with Ethereum to continue to your application</span>
28
+
29
+ <button
30
+ class="h-12 border hover:scale-105 justify-evenly shadow-xl border-white mt-auto duration-100 ease-in-out transition-all transform flex items-center"
31
+ id="siwe"
32
+ >
33
+ <svg
34
+ xmlns="http://www.w3.org/2000/svg"
35
+ clip-rule="evenodd"
36
+ fill-rule="evenodd"
37
+ stroke-linejoin="round"
38
+ stroke-miterlimit="1.41421"
39
+ viewBox="170 30 220 350"
40
+ class="w-6 h-8"
41
+ >
42
+ <g fill-rule="nonzero" transform="matrix(.781253 0 0 .781253 180 37.1453)">
43
+ <path d="m127.961 0-2.795 9.5v275.668l2.795 2.79 127.962-75.638z" fill="#343434" /><path
44
+ d="m127.962 0-127.962 212.32 127.962 75.639v-133.801z"
45
+ fill="#8c8c8c"
46
+ />
47
+ <path d="m127.961 312.187-1.575 1.92v98.199l1.575 4.601 128.038-180.32z" fill="#3c3c3b" /><path
48
+ d="m127.962 416.905v-104.72l-127.962-75.6z"
49
+ fill="#8c8c8c"
50
+ />
51
+ <path d="m127.961 287.958 127.96-75.637-127.96-58.162z" fill="#141414" /><path
52
+ d="m.001 212.321 127.96 75.637v-133.799z"
53
+ fill="#393939"
54
+ />
55
+ </g>
56
+ </svg>
57
+ <p class="font-bold">Sign-In with Ethereum</p>
58
+ </button>
59
+ </div>
60
+ </div>
61
+
62
+ </body>
63
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,6 @@
1
+ SiweRails::Engine.routes.draw do
2
+ root to: 'application#index'
3
+
4
+ post 'message' => 'application#message'
5
+ post 'signature' => 'application#signature'
6
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SiweRails
4
+ class Engine < ::Rails::Engine
5
+ isolate_namespace SiweRails
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module SiweRails
2
+ VERSION = '0.1.0'
3
+ end
data/lib/siwe_rails.rb ADDED
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'siwe_rails/version'
4
+ require 'siwe_rails/engine'
5
+
6
+ module SiweRails
7
+ # Session address key
8
+ def self.SIWE_ADDRESS
9
+ 'siwe/address'
10
+ end
11
+
12
+ # Session address key
13
+ def self.SIWE_ENS
14
+ 'siwe/ens'
15
+ end
16
+
17
+ # Prefix to use when mounting the routes
18
+ def self.prefix
19
+ if Rails.configuration.x.siwe.prefix.nil?
20
+ 'siwe'
21
+ else
22
+ Rails.configuration.x.siwe.prefix
23
+ end
24
+ end
25
+
26
+ # Message statement
27
+ def self.statement
28
+ if Rails.configuration.x.siwe.statement.nil?
29
+ 'SIWE'
30
+ else
31
+ Rails.configuration.x.siwe.statement
32
+ end
33
+ end
34
+
35
+ # Message expiration time in milliseconds, 7 days by default
36
+ def self.expiration_time
37
+ if Rails.configuration.x.siwe.expiration_time.nil?
38
+ 7 * 24 * 60 * 60 * 1000
39
+ else
40
+ Rails.configuration.x.siwe.expiration_time
41
+ end
42
+ end
43
+
44
+ # Message minimum datetime validity
45
+ def self.not_before
46
+ if Rails.configuration.x.siwe.not_before.nil?
47
+ Time.now.utc.iso8601
48
+ else
49
+ Rails.configuration.x.siwe.not_before
50
+ end
51
+ end
52
+
53
+ # Whether to add a request id
54
+ def self.request_id
55
+ if Rails.configuration.x.siwe.request_id.nil?
56
+ false
57
+ else
58
+ Rails.configuration.x.siwe.request_id
59
+ end
60
+ end
61
+
62
+ # Resources
63
+ def self.resources
64
+ if Rails.configuration.x.siwe.resources.nil?
65
+ nil
66
+ else
67
+ Rails.configuration.x.siwe.resources
68
+ end
69
+ end
70
+
71
+ # Redirect URL to receive user information on success
72
+ def self.redirect_uri
73
+ if Rails.configuration.x.siwe.redirect_uri.nil?
74
+ '/'
75
+ else
76
+ Rails.configuration.x.siwe.redirect_uri
77
+ end
78
+ end
79
+
80
+ # Network to use with sign in
81
+ def self.network
82
+ if Rails.configuration.x.siwe.network.nil?
83
+ 'mainnet'
84
+ else
85
+ Rails.configuration.x.siwe.network
86
+ end
87
+ end
88
+
89
+ # Infura Key
90
+ def self.infura
91
+ if Rails.configuration.x.siwe.infura.nil?
92
+ ''
93
+ else
94
+ Rails.configuration.x.siwe.infura
95
+ end
96
+ end
97
+
98
+ # Portis ID
99
+ def self.portis
100
+ if Rails.configuration.x.siwe.portis.nil?
101
+ ''
102
+ else
103
+ Rails.configuration.x.siwe.portis
104
+ end
105
+ end
106
+
107
+ # Fortmatic Key
108
+ def self.fortmatic
109
+ if Rails.configuration.x.siwe.fortmatic.nil?
110
+ ''
111
+ else
112
+ Rails.configuration.x.siwe.fortmatic
113
+ end
114
+ end
115
+
116
+ # Whether to enable Torus wallet
117
+ def self.torus
118
+ if Rails.configuration.x.siwe.torus.nil?
119
+ false
120
+ else
121
+ Rails.configuration.x.siwe.torus
122
+ end
123
+ end
124
+
125
+ # Whether to enable Coinbase wallet
126
+ def self.coinbase
127
+ if Rails.configuration.x.siwe.coinbase.nil?
128
+ false
129
+ else
130
+ Rails.configuration.x.siwe.coinbase
131
+ end
132
+ end
133
+
134
+ def self.setup
135
+ yield self
136
+ end
137
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: siwe_rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Spruce Systems, Inc.
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-09-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 7.0.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 7.0.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: sass-rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: siwe
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Custom Rails Engine to server local pages for SIWE
56
+ email:
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - README.md
62
+ - Rakefile
63
+ - app/assets/config/siwe_rails_manifest.js
64
+ - app/assets/images/siwe_rails/coinbase.svg
65
+ - app/assets/images/siwe_rails/modal_icon.png
66
+ - app/assets/images/siwe_rails/swe-landing.svg
67
+ - app/assets/javascripts/siwe_rails/siwe.js.erb
68
+ - app/assets/javascripts/siwe_rails/web3bundle.js
69
+ - app/assets/stylesheets/siwe_rails/application.css
70
+ - app/assets/stylesheets/siwe_rails/background.scss
71
+ - app/controllers/siwe_rails/application_controller.rb
72
+ - app/views/siwe_rails/application/index.html.erb
73
+ - config/routes.rb
74
+ - lib/siwe_rails.rb
75
+ - lib/siwe_rails/engine.rb
76
+ - lib/siwe_rails/version.rb
77
+ homepage: https://github.com/spruceid/siwe-rails-engine
78
+ licenses:
79
+ - MIT
80
+ - Apache-2.0
81
+ metadata: {}
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubygems_version: 3.3.22
98
+ signing_key:
99
+ specification_version: 4
100
+ summary: Custom Rails Engine to server local pages for SIWE
101
+ test_files: []