self-auth-rails 0.1.1
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +68 -0
- data/Rakefile +8 -0
- data/app/assets/config/self-auth-rails/app.js +89 -0
- data/app/assets/config/self-auth-rails/cable.js +14 -0
- data/app/assets/config/self-auth-rails/channels/auth.js +7 -0
- data/app/assets/config/self-auth-rails/channels/messages_channel.js +150 -0
- data/app/assets/config/self-auth-rails/cookies.js +2 -0
- data/app/assets/config/self-auth-rails/ki.js +8 -0
- data/app/assets/config/self-auth-rails/manifest.js +8 -0
- data/app/assets/stylesheets/self-auth-rails/application.css +27 -0
- data/app/channels/application_cable/channel.rb +4 -0
- data/app/channels/application_cable/connection.rb +15 -0
- data/app/channels/messages_channel.rb +9 -0
- data/app/controllers/self_auth_rails/application_controller.rb +4 -0
- data/app/controllers/self_auth_rails/sessions_controller.rb +90 -0
- data/app/helpers/self_auth_rails/application_helper.rb +24 -0
- data/app/helpers/self_auth_rails/sessions_helper.rb +4 -0
- data/app/jobs/self_auth_rails/application_job.rb +4 -0
- data/app/mailers/self_auth_rails/application_mailer.rb +6 -0
- data/app/models/self_auth_rails/application_record.rb +5 -0
- data/app/services/self_auth_response_manager_service.rb +76 -0
- data/app/views/self_auth_rails/sessions/create.html.erb +2 -0
- data/app/views/self_auth_rails/sessions/new.html.erb +75 -0
- data/config/routes.rb +11 -0
- data/lib/self-auth-rails/engine.rb +18 -0
- data/lib/self-auth-rails/version.rb +3 -0
- data/lib/self-auth-rails.rb +50 -0
- data/lib/tasks/initializer.rb.tpl +45 -0
- data/lib/tasks/self_auth_rails_tasks.rake +69 -0
- metadata +116 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA256:
         | 
| 3 | 
            +
              metadata.gz: f7bf53acb259dc5c315fcf6222d30d099a3c95ada6b9bacb5d51554d8dc6ec08
         | 
| 4 | 
            +
              data.tar.gz: 7d0fb909e65049f4f3ae8a16ccb15d0f82510a8d1f03bab09b84b4187aad37b2
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: 51c1afac76389b629e41e293dd2e1d21826e3629602b3f7a770073a1731168cec1ccec7a66cdcf1a5c61c8d87b8772b9ee28302b6b3296cd92ad2fbe2c1ed477
         | 
| 7 | 
            +
              data.tar.gz: 10e87468d332a8106727f5ecb2c75eab382163df0fbe5468d91dbc11e3a69fcb2fd4e7befdd01a089c8dae1024ef3183b79ceb1a1e295f457ee075e8dde0e61c
         | 
    
        data/MIT-LICENSE
    ADDED
    
    | @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            Copyright 2022 Self Group Ltd.
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Permission is hereby granted, free of charge, to any person obtaining
         | 
| 4 | 
            +
            a copy of this software and associated documentation files (the
         | 
| 5 | 
            +
            "Software"), to deal in the Software without restriction, including
         | 
| 6 | 
            +
            without limitation the rights to use, copy, modify, merge, publish,
         | 
| 7 | 
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         | 
| 8 | 
            +
            permit persons to whom the Software is furnished to do so, subject to
         | 
| 9 | 
            +
            the following conditions:
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            The above copyright notice and this permission notice shall be
         | 
| 12 | 
            +
            included in all copies or substantial portions of the Software.
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         | 
| 15 | 
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         | 
| 16 | 
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         | 
| 17 | 
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         | 
| 18 | 
            +
            LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         | 
| 19 | 
            +
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         | 
| 20 | 
            +
            WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         | 
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,68 @@ | |
| 1 | 
            +
            # self-auth-rails
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            self-auth-rails is rails engine to easily integrate [Self Authentication](https://docs.joinself.com/authentication/) on your authentication workflow.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            ## Usage
         | 
| 6 | 
            +
            How to use my plugin.
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            ## Getting started
         | 
| 9 | 
            +
            ### Installation
         | 
| 10 | 
            +
            Add this line to your application's Gemfile:
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            ```ruby
         | 
| 13 | 
            +
            gem "self-auth-rails"
         | 
| 14 | 
            +
            ```
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            And then execute:
         | 
| 17 | 
            +
            ```bash
         | 
| 18 | 
            +
            $ bundle install
         | 
| 19 | 
            +
            ```
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            ### Set up
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            For your convenience `self-auth-rails` comes with a script to automatically set up the initializers and mounting routes on your system.
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            ```
         | 
| 26 | 
            +
            $ rake self_auth_rails:init
         | 
| 27 | 
            +
            ```
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            This command will
         | 
| 30 | 
            +
            - [x] Generate necessary migrations
         | 
| 31 | 
            +
            - [x] Create initializers (config/initializers/self_auth_rails.rb)
         | 
| 32 | 
            +
            - [x] Mount the engine on your routes (config/routes.rb)
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            Once that's done you'll need to: 
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            - [ ] run the created migrations with `bin/rails db:migrate` 
         | 
| 37 | 
            +
            - [ ] setup the environment variables required on `config/initializers/self_auth_rails.rb`
         | 
| 38 | 
            +
            - [ ] protect the resources you want to hide from the public
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            ### Protecting routes
         | 
| 41 | 
            +
             | 
| 42 | 
            +
            You can fully protect your app by adding a controller filter to your `app/controllers/application.rb`, or specifying it only for the routes you want to be protected.
         | 
| 43 | 
            +
            ```
         | 
| 44 | 
            +
            class ApplicationController < ActionController::Base
         | 
| 45 | 
            +
                before_action :authenticate_user!
         | 
| 46 | 
            +
            end
         | 
| 47 | 
            +
            ```
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            ### Running it
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            That's it, as soon as you have the SELF required environment variables in place, you'll be able to see the authentication screen when you visit http://localhost:3000.
         | 
| 52 | 
            +
             | 
| 53 | 
            +
             | 
| 54 | 
            +
            ### Notes
         | 
| 55 | 
            +
            #### Action cable
         | 
| 56 | 
            +
            By default action cable relies on redis to work on development, if you're just testing this gem, you can switch it to `async` on `config/cable.yml`
         | 
| 57 | 
            +
            ```
         | 
| 58 | 
            +
            development:
         | 
| 59 | 
            +
              adapter: async
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            #...
         | 
| 62 | 
            +
            ```
         | 
| 63 | 
            +
             | 
| 64 | 
            +
            ## Contributing
         | 
| 65 | 
            +
            Bug reports and pull requests are welcome on GitHub at https://github.com/joinself/self-auth-rails.
         | 
| 66 | 
            +
             | 
| 67 | 
            +
            ## License
         | 
| 68 | 
            +
            The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
         | 
    
        data/Rakefile
    ADDED
    
    
| @@ -0,0 +1,89 @@ | |
| 1 | 
            +
            /* Initialize app when page loads */
         | 
| 2 | 
            +
            $(function(){ 
         | 
| 3 | 
            +
                var Messages = App.cable.subscriptions.create({
         | 
| 4 | 
            +
                  channel:'MessagesChannel',
         | 
| 5 | 
            +
                  conversation_id: connectionID()
         | 
| 6 | 
            +
                }, {
         | 
| 7 | 
            +
                  received: function(data) {
         | 
| 8 | 
            +
                      console.log(data);
         | 
| 9 | 
            +
                    if(data.type == "info") {
         | 
| 10 | 
            +
                        if(data.status == "completed") {
         | 
| 11 | 
            +
                            console.log("info request");
         | 
| 12 | 
            +
                            window.location.replace("/");
         | 
| 13 | 
            +
                        } else {
         | 
| 14 | 
            +
                            message = "Fact request has been rejected"
         | 
| 15 | 
            +
                            if(data.status == "errored") {
         | 
| 16 | 
            +
                                message = data.message
         | 
| 17 | 
            +
                            }
         | 
| 18 | 
            +
                            // TODO: this id no longer exists...
         | 
| 19 | 
            +
                            $('#info_messages').append("<div class='alert alert-danger'><button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×</button>'+message+'</div>");
         | 
| 20 | 
            +
                        }
         | 
| 21 | 
            +
                    } else {
         | 
| 22 | 
            +
                        $("#messages").removeClass('hidden');
         | 
| 23 | 
            +
                        if(data.status == "accepted") {
         | 
| 24 | 
            +
                          // Just display the 
         | 
| 25 | 
            +
                          $('#process').removeClass("hidden");
         | 
| 26 | 
            +
                          $('#non-dl-container').addClass("hidden");
         | 
| 27 | 
            +
                          $('#dl-container').addClass("hidden");
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                            // Login request accepted
         | 
| 30 | 
            +
                          $("#req-auth .activity-icon").addClass("bg-success")
         | 
| 31 | 
            +
                          $("#req-auth .activity-icon").addClass("shadow-success")
         | 
| 32 | 
            +
                          $("#req-auth .activity-icon").removeClass("bg-info")
         | 
| 33 | 
            +
                          $("#req-auth .activity-icon").removeClass("shadow-info")
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                          $("#req-info .activity-icon").removeClass("bg-secondary")
         | 
| 36 | 
            +
                          $("#req-info .activity-icon").removeClass("shadow-secondary")
         | 
| 37 | 
            +
                          $("#req-info .activity-icon").addClass("bg-info")
         | 
| 38 | 
            +
                          $("#req-info .activity-icon").addClass("shadow-info")
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                          $("#req-auth .waiting").addClass("hidden")
         | 
| 41 | 
            +
                          $("#req-auth .passed").removeClass("hidden")
         | 
| 42 | 
            +
                          $("#req-info .waiting").removeClass("hidden")
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                        } else if(data.status == "completed") {
         | 
| 45 | 
            +
                          $("#auth-ok").hide()
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                          $("#req-info .activity-icon").addClass("bg-success")
         | 
| 48 | 
            +
                          $("#req-info .activity-icon").addClass("shadow-success")
         | 
| 49 | 
            +
                          $("#req-info .activity-icon").removeClass("bg-info")
         | 
| 50 | 
            +
                          $("#req-info .activity-icon").removeClass("shadow-info")
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                          $("#req-info .waiting").addClass("hidden")
         | 
| 53 | 
            +
                          $("#req-info .passed").removeClass("hidden")
         | 
| 54 | 
            +
                          $(".logging-in").removeClass("hidden")
         | 
| 55 | 
            +
                          $(".btn-cancel").addClass("hidden")
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                          setTimeout(() => {
         | 
| 58 | 
            +
                            // Fetched user information
         | 
| 59 | 
            +
                            $("#login-token")[0].value = data.token;
         | 
| 60 | 
            +
                            $("#form-login").off("submit")
         | 
| 61 | 
            +
                            $("#form-login")[0].submit();
         | 
| 62 | 
            +
                          }, 2000);
         | 
| 63 | 
            +
              
         | 
| 64 | 
            +
                        } else {
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                          message = "Login request has been rejected"
         | 
| 67 | 
            +
                          if(data.status == "errored") {
         | 
| 68 | 
            +
                            message = data.message
         | 
| 69 | 
            +
                          }
         | 
| 70 | 
            +
                          $('#messages').append(`<div class="alert alert-warning alert-dismissible show fade"><div class="alert-body"><button class="close" data-dismiss="alert"><span>×</span></button>${message}</div></div>`);
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                          $('#messages').show();
         | 
| 73 | 
            +
                          $('#process').addClass("hidden");
         | 
| 74 | 
            +
                          $('#non-dl-container').removeClass("hidden");
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                          $("#req-auth .activity-icon").addClass("bg-info")
         | 
| 77 | 
            +
                          $("#req-auth .activity-icon").addClass("shadow-info")
         | 
| 78 | 
            +
                          $("#req-auth .activity-icon").removeClass("bg-success")
         | 
| 79 | 
            +
                          $("#req-auth .activity-icon").removeClass("shadow-success")
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                          $("#req-info .activity-icon").removeClass("bg-info")
         | 
| 82 | 
            +
                          $("#req-info .activity-icon").removeClass("shadow-info")
         | 
| 83 | 
            +
                          $("#req-info .activity-icon").addClass("bg-secondary")
         | 
| 84 | 
            +
                          $("#req-info .activity-icon").addClass("shadow-secondary")
         | 
| 85 | 
            +
                        }
         | 
| 86 | 
            +
                    }
         | 
| 87 | 
            +
                  }
         | 
| 88 | 
            +
                });    
         | 
| 89 | 
            +
             });
         | 
| @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            // Action Cable provides the framework to deal with WebSockets in Rails.
         | 
| 2 | 
            +
            // You can generate new channels where WebSocket features live using the `rails generate channel` command.
         | 
| 3 | 
            +
            //
         | 
| 4 | 
            +
            //= require actioncable
         | 
| 5 | 
            +
            //= require_self
         | 
| 6 | 
            +
            //= require_tree ./channels
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            (function() {
         | 
| 9 | 
            +
                this.App || (this.App = {});
         | 
| 10 | 
            +
              
         | 
| 11 | 
            +
                App.cable = ActionCable.createConsumer();
         | 
| 12 | 
            +
              
         | 
| 13 | 
            +
              }).call(this);
         | 
| 14 | 
            +
              
         | 
| @@ -0,0 +1,150 @@ | |
| 1 | 
            +
            function uuidv4() {
         | 
| 2 | 
            +
                return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
         | 
| 3 | 
            +
                  var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
         | 
| 4 | 
            +
                  return v.toString(16);
         | 
| 5 | 
            +
                });
         | 
| 6 | 
            +
              }
         | 
| 7 | 
            +
              
         | 
| 8 | 
            +
              function connectionID() {
         | 
| 9 | 
            +
                c = Cookies.get("auth-sess")
         | 
| 10 | 
            +
                if(c == undefined) {
         | 
| 11 | 
            +
                  Cookies.set('auth-sess', uuidv4());
         | 
| 12 | 
            +
                }
         | 
| 13 | 
            +
                return Cookies.get("auth-sess");
         | 
| 14 | 
            +
              }
         | 
| 15 | 
            +
              
         | 
| 16 | 
            +
              function displayQR() {
         | 
| 17 | 
            +
                updateQR();
         | 
| 18 | 
            +
                $('#qr-container').show();
         | 
| 19 | 
            +
                $('#page-wrapper').addClass('page-loading');
         | 
| 20 | 
            +
                window.qrInterval = window.setInterval(function(){
         | 
| 21 | 
            +
                  if($('#qr').length) {
         | 
| 22 | 
            +
                    updateQR();
         | 
| 23 | 
            +
                  }
         | 
| 24 | 
            +
                }, 30000);
         | 
| 25 | 
            +
              }
         | 
| 26 | 
            +
              
         | 
| 27 | 
            +
              function hideQR() {
         | 
| 28 | 
            +
                location.reload();
         | 
| 29 | 
            +
              }
         | 
| 30 | 
            +
              
         | 
| 31 | 
            +
              function updateQR() {
         | 
| 32 | 
            +
                  if($("#qr_url").length) {
         | 
| 33 | 
            +
                      $("#qr")[0].setAttribute("src", $("#qr_url")[0].value + "?uuid=" + connectionID());
         | 
| 34 | 
            +
                  }
         | 
| 35 | 
            +
              }
         | 
| 36 | 
            +
              
         | 
| 37 | 
            +
              function updateDL() {
         | 
| 38 | 
            +
                  if($("#dl_url").length) {
         | 
| 39 | 
            +
                      if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent)
         | 
| 40 | 
            +
                          || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0, 4))) {
         | 
| 41 | 
            +
                          $("#dl-container").removeClass("hidden");
         | 
| 42 | 
            +
                          $("#non-dl-container").addClass("hidden");
         | 
| 43 | 
            +
              
         | 
| 44 | 
            +
                          $.getJSON($("#dl_url")[0].value + "?uuid=" + connectionID(), function (data) {
         | 
| 45 | 
            +
                              $("#dl").attr("href", data["url"]);
         | 
| 46 | 
            +
              
         | 
| 47 | 
            +
                              $('#dl').unbind('click');
         | 
| 48 | 
            +
                              $('#dl').bind("click", function (e) {
         | 
| 49 | 
            +
                                  $('#page-wrapper').addClass('page-loading');
         | 
| 50 | 
            +
                                  if($("#profile_request").length) {
         | 
| 51 | 
            +
                                      hasProfile();
         | 
| 52 | 
            +
                                  }
         | 
| 53 | 
            +
                              });
         | 
| 54 | 
            +
                          });
         | 
| 55 | 
            +
                      }
         | 
| 56 | 
            +
                  }
         | 
| 57 | 
            +
              }
         | 
| 58 | 
            +
              
         | 
| 59 | 
            +
              function hasProfile() {
         | 
| 60 | 
            +
                  $.ajax({
         | 
| 61 | 
            +
                      type: "GET",
         | 
| 62 | 
            +
                      contentType: "application/json",
         | 
| 63 | 
            +
                      url: "/session/has_profile",
         | 
| 64 | 
            +
                      dataType: 'json',
         | 
| 65 | 
            +
                      timeout: 600000,
         | 
| 66 | 
            +
                      success: function (data) {
         | 
| 67 | 
            +
                          window.location.replace("/");
         | 
| 68 | 
            +
                      },
         | 
| 69 | 
            +
                      error: function (e) {
         | 
| 70 | 
            +
                          setTimeout(function(){ hasProfile(); }, 2000);
         | 
| 71 | 
            +
                      }
         | 
| 72 | 
            +
                  });
         | 
| 73 | 
            +
              }
         | 
| 74 | 
            +
              
         | 
| 75 | 
            +
              ready = function() {
         | 
| 76 | 
            +
                  
         | 
| 77 | 
            +
                  if($("#qr-container")){
         | 
| 78 | 
            +
                    displayQR();
         | 
| 79 | 
            +
                  }
         | 
| 80 | 
            +
                  if($("#dl-container")) {
         | 
| 81 | 
            +
                    updateDL();
         | 
| 82 | 
            +
                  }
         | 
| 83 | 
            +
              
         | 
| 84 | 
            +
                  $("#switch-not-dl").bind("click", function(e){
         | 
| 85 | 
            +
                      $("#dl-container").addClass("hidden");
         | 
| 86 | 
            +
                      $("#non-dl-container").removeClass("hidden");
         | 
| 87 | 
            +
                      $("#selfid-field").focus();
         | 
| 88 | 
            +
                      $("#qr").width($(".qr-wrapper").width());
         | 
| 89 | 
            +
                      $("#qr").height($(".qr-wrapper").width());
         | 
| 90 | 
            +
                  });
         | 
| 91 | 
            +
              
         | 
| 92 | 
            +
                  $("#profile_request").bind("click", function (e) {
         | 
| 93 | 
            +
                      e.preventDefault(e);
         | 
| 94 | 
            +
                      $("#profile_help_block").show();
         | 
| 95 | 
            +
                      console.log("sending ajax request")
         | 
| 96 | 
            +
                      $.ajax({
         | 
| 97 | 
            +
                          type: "POST",
         | 
| 98 | 
            +
                          contentType: "application/json",
         | 
| 99 | 
            +
                          url: "/profile/fetch",
         | 
| 100 | 
            +
                          dataType: 'json',
         | 
| 101 | 
            +
                          data: '{"user":{"connection_id":"'+connectionID()+'"}}',
         | 
| 102 | 
            +
                          beforeSend: $.rails.CSRFProtection,
         | 
| 103 | 
            +
                          timeout: 600000,
         | 
| 104 | 
            +
                          success: function (data) {
         | 
| 105 | 
            +
                          },
         | 
| 106 | 
            +
                          error: function (e) {
         | 
| 107 | 
            +
                              if(e.status == 502) {
         | 
| 108 | 
            +
                                  $('#info_messages').append("<div class='alert alert-danger'><button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×</button>Request timed out, try again later</div>");
         | 
| 109 | 
            +
                              } else {
         | 
| 110 | 
            +
                                  $('#info_messages').append("<div class='alert alert-danger'><button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×</button>"+e.responseJSON.error+"</div>");
         | 
| 111 | 
            +
                              }
         | 
| 112 | 
            +
                              $("#profile_help_block").hide();
         | 
| 113 | 
            +
                          }
         | 
| 114 | 
            +
                      });
         | 
| 115 | 
            +
              
         | 
| 116 | 
            +
                  });
         | 
| 117 | 
            +
              
         | 
| 118 | 
            +
                $('#form-login').bind("submit", function(e){
         | 
| 119 | 
            +
                  e.preventDefault();
         | 
| 120 | 
            +
                  var val = $('#selfid-field')[0].value
         | 
| 121 | 
            +
                  if(val == null) {
         | 
| 122 | 
            +
                      return;
         | 
| 123 | 
            +
                  }
         | 
| 124 | 
            +
                  if (val.length != 11) {
         | 
| 125 | 
            +
                    $('#selfid-field').addClass("is-invalid")
         | 
| 126 | 
            +
                    return;
         | 
| 127 | 
            +
                  }
         | 
| 128 | 
            +
                  $('#selfid-field').removeClass("is-invalid")
         | 
| 129 | 
            +
                  $('#page-wrapper').addClass('page-loading');
         | 
| 130 | 
            +
                  $(this).blur();
         | 
| 131 | 
            +
              
         | 
| 132 | 
            +
                  //do some verification
         | 
| 133 | 
            +
                  $("#connection_id")[0].value = connectionID();
         | 
| 134 | 
            +
                  $("#process").removeClass("hidden");
         | 
| 135 | 
            +
                  $('#non-dl-container').addClass("hidden");
         | 
| 136 | 
            +
                  
         | 
| 137 | 
            +
                  $.ajax({
         | 
| 138 | 
            +
                    type: 'POST',
         | 
| 139 | 
            +
                    url: $(this).context.action,
         | 
| 140 | 
            +
                    data: $(this).serialize()
         | 
| 141 | 
            +
                  });
         | 
| 142 | 
            +
                });
         | 
| 143 | 
            +
              
         | 
| 144 | 
            +
              };
         | 
| 145 | 
            +
              
         | 
| 146 | 
            +
            $(function () {
         | 
| 147 | 
            +
                updateQR()
         | 
| 148 | 
            +
            })
         | 
| 149 | 
            +
             | 
| 150 | 
            +
              
         | 
| @@ -0,0 +1,2 @@ | |
| 1 | 
            +
            /*! js-cookie v2.1.4 | MIT */
         | 
| 2 | 
            +
            !function(a){var b=!1;if("function"==typeof define&&define.amd&&(define(a),b=!0),"object"==typeof exports&&(module.exports=a(),b=!0),!b){var c=window.Cookies,d=window.Cookies=a();d.noConflict=function(){return window.Cookies=c,d}}}(function(){function a(){for(var a=0,b={};a<arguments.length;a++){var c=arguments[a];for(var d in c)b[d]=c[d]}return b}function b(c){function d(b,e,f){var g;if("undefined"!=typeof document){if(arguments.length>1){if(f=a({path:"/"},d.defaults,f),"number"==typeof f.expires){var h=new Date;h.setMilliseconds(h.getMilliseconds()+864e5*f.expires),f.expires=h}f.expires=f.expires?f.expires.toUTCString():"";try{g=JSON.stringify(e),/^[\{\[]/.test(g)&&(e=g)}catch(p){}e=c.write?c.write(e,b):encodeURIComponent(e+"").replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent),b=encodeURIComponent(b+""),b=b.replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent),b=b.replace(/[\(\)]/g,escape);var i="";for(var j in f)f[j]&&(i+="; "+j,!0!==f[j]&&(i+="="+f[j]));return document.cookie=b+"="+e+i}b||(g={});for(var k=document.cookie?document.cookie.split("; "):[],l=0;l<k.length;l++){var m=k[l].split("="),n=m.slice(1).join("=");'"'===n.charAt(0)&&(n=n.slice(1,-1));try{var o=m[0].replace(/(%[0-9A-Z]{2})+/g,decodeURIComponent);if(n=c.read?c.read(n,o):c(n,o)||n.replace(/(%[0-9A-Z]{2})+/g,decodeURIComponent),this.json)try{n=JSON.parse(n)}catch(p){}if(b===o){g=n;break}b||(g[o]=n)}catch(p){}}return g}}return d.set=d,d.get=function(a){return d.call(d,a)},d.getJSON=function(){return d.apply({json:!0},[].slice.call(arguments))},d.defaults={},d.remove=function(b,c){d(b,"",a(c,{expires:-1}))},d.withConverter=b,d}return b(function(){})});
         | 
| @@ -0,0 +1,8 @@ | |
| 1 | 
            +
            /*!
         | 
| 2 | 
            +
             * ki.js v1.1.0 - 2015-10-06
         | 
| 3 | 
            +
             * Copyright (c) 2015 Denis Ciccale (@tdecs)
         | 
| 4 | 
            +
             * Released under MIT license
         | 
| 5 | 
            +
             */
         | 
| 6 | 
            +
            !function(a,b,c,d){function e(c){b.push.apply(this,c&&c.nodeType?[c]:""+c===c?a.querySelectorAll(c):d)}$=function(b){return/^f/.test(typeof b)?/c/.test(a.readyState)?b():$(a).on("DOMContentLoaded",b):new e(b)},$[c]=e[c]=$.fn=e.fn={length:0,on:function(a,b){return this.each(function(c){c.addEventListener(a,b)})},off:function(a,b){return this.each(function(c){c.removeEventListener(a,b)})},each:function(a,c){return b.forEach.call(this,a,c),this},splice:b.splice}}(document,[],"prototype");
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            !function(){$.each=function(a,b){for(var c=0,d=a.length;d>c;++c)b.call(a[c],c,a[c]);return this};var a=["addClass","removeClass","toggleClass"],b=["add","remove","toggle"];a.forEach(function(a,c){$.prototype[a]=function(a){return this.each(function(d){d.classList[b[c]](a)})}}),$.prototype.hasClass=function(a){return this[0].classList.contains(a)},$.prototype.append=function(a){return this.each(function(b){b.appendChild(a[0])})},$.prototype.prepend=function(a){return this.each(function(b){b.insertBefore(a[0],b.firstChild)})},$.prototype.hide=function(){return this.each(function(a){a.style.display="none"})},$.prototype.show=function(){return this.each(function(a){a.style.display=""})},$.prototype.attr=function(a,b){return b===[]._?this[0].getAttribute(a):this.each(function(c){c.setAttribute(a,b)})},$.prototype.removeAttr=function(a){return this.each(function(b){b.removeAttribute(a)})},$.prototype.hasAttr=function(a){return this[0].hasAttribute(a)},$.prototype.before=function(a){return this.each(function(b){b.insertAdjacentHTML("beforebegin",a)})},$.prototype.after=function(a){return this.each(function(b){b.insertAdjacentHTML("afterend",a)})},$.prototype.css=function(a,b){if("object"==typeof a){for(var c in a)this.each(function(b){b.style[c]=a[c]});return this}return b===[]._?this[0].style[a]:this.each(function(c){c.style[a]=b})},$.prototype.first=function(){return $(this[0])},$.prototype.last=function(){return $(this[this.length-1])},$.prototype.get=function(a){return $(this[a])},$.prototype.text=function(a){return a===[]._?this[0].textContent:this.each(function(b){b.textContent=a})},$.prototype.html=function(a){return a===[]._?this[0].innerHTML:this.each(function(b){b.innerHTML=a})},$.prototype.parent=function(){return this.length<2?$(this[0].parentNode):[]},$.prototype.remove=function(){return this.each(function(a){a.parentNode.removeChild(a)})},$.trim=function(a){return a.replace(/^\s+|\s+$/g,"")},$.prototype.trigger=function(a){if(document.createEvent){var b=document.createEvent("HTMLEvents");b.initEvent(a,!0,!1),this.each(function(a){a.dispatchEvent(b)})}else this.each(function(b){b.fireEvent("on"+a)})},$.prototype.is=function(a){var b=this[0].matches||this[0].matchesSelector||this[0].msMatchesSelector||this[0].mozMatchesSelector||this[0].webkitMatchesSelector||this[0].oMatchesSelector;if(b)return b.call(this[0],a);for(var c=this[0].parentNode.querySelectorAll(a),d=c.length;d--;)if(c[d]===this[0])return!0;return!1},"filter map".split(" ").forEach(function(a){$[a]=function(b,c){return b[a](c)}}),$.stop=function(a){a.preventDefault?a.preventDefault():a.returnValue=!1},$.param=function(a,b){var c=[];for(var d in a){var e=b?b+"["+d+"]":d,f=a[d];c.push("object"==typeof f?$.param(f,e):encodeURIComponent(e)+"="+encodeURIComponent(f))}return c.join("&")},$.ajax=function(a,b,c){var d=new XMLHttpRequest,e=new $.Deferred,f="object"==typeof b?1:0,g=["GET","POST"];d.open(g[f],a,!0);var h=f?c:b;return"undefined"==typeof c&&"function"!=typeof b&&(h=function(){}),d.onerror=function(){e.reject(this),h(this,!0)},d.onreadystatechange=function(){4===this.readyState&&(this.status>=200&&this.status<400?(e.resolve(this.response),h(this.response,!0)):(e.reject(this),h(this,!0)))},f?(d.setRequestHeader("Content-type","application/x-www-form-urlencoded"),d.send($.param(b))):d.send(),d=null,e.promise()},function(a){function b(a){return"[object Array]"===Object.prototype.toString.call(a)}function c(a,c){if(b(a))for(var d=0;d<a.length;d++)c(a[d]);else c(a)}function d(a){var e="pending",f=[],g=[],h=[],i=[],j={done:function(){for(var a=0;a<arguments.length;a++)if(arguments[a])if(b(arguments[a]))for(var c=arguments[a],d=0;d<c.length;d++)"resolved"===e&&c[d].apply(this,i),f.push(c[d]);else"resolved"===e&&arguments[a].apply(this,i),f.push(arguments[a]);return this},fail:function(){for(var a=0;a<arguments.length;a++)if(arguments[a])if(b(arguments[a]))for(var c=arguments[a],d=0;d<c.length;d++)"rejected"===e&&c[d].apply(this,i),g.push(c[d]);else"rejected"===e&&arguments[a].apply(this,i),g.push(arguments[a]);return this},always:function(){return this.done.apply(this,arguments).fail.apply(this,arguments)},progress:function(){for(var a=0;a<arguments.length;a++)if(arguments[a])if(b(arguments[a]))for(var c=arguments[a],d=0;d<c.length;d++)"pending"===e&&h.push(c[d]);else"pending"===e&&h.push(arguments[a]);return this},then:function(){arguments.length>1&&arguments[1]&&this.fail(arguments[1]),arguments.length>0&&arguments[0]&&this.done(arguments[0]),arguments.length>2&&arguments[2]&&this.progress(arguments[2])},promise:function(a){if("undefined"==typeof a)return j;for(var b in j)a[b]=j[b];return a},state:function(){return e},debug:function(){console.log("[debug]",f,g,e)},isRejected:function(){return"rejected"===e},isResolved:function(){return"resolved"===e},pipe:function(a,b,e){return d(function(d){c(a,function(a){"function"==typeof a?k.done(function(){var b=a.apply(this,arguments);b&&"function"==typeof b?b.promise().then(d.resolve,d.reject,d.notify):d.resolve(b)}):k.done(d.resolve)}),c(b,function(a){"function"==typeof a?k.fail(function(){var b=a.apply(this,arguments);b&&"function"==typeof b?b.promise().then(d.resolve,d.reject,d.notify):d.reject(b)}):k.fail(d.reject)})}).promise()}},k={resolveWith:function(a){if("pending"===e){e="resolved";for(var b=i=arguments.length>1?arguments[1]:[],c=0;c<f.length;c++)f[c].apply(a,b)}return this},rejectWith:function(a){if("pending"===e){e="rejected";for(var b=i=arguments.length>1?arguments[1]:[],c=0;c<g.length;c++)g[c].apply(a,b)}return this},notifyWith:function(a){if("pending"===e)for(var b=i=arguments.length>1?arguments[1]:[],c=0;c<h.length;c++)h[c].apply(a,b);return this},resolve:function(){return this.resolveWith(this,arguments)},reject:function(){return this.rejectWith(this,arguments)},notify:function(){return this.notifyWith(this,arguments)}},l=j.promise(k);return a&&a.apply(l,[l]),l}var e=function(){if(arguments.length<2){var a=arguments.length?arguments[0]:void 0;return a&&"function"==typeof a.isResolved&&"function"==typeof a.isRejected?a.promise():d().resolve(a).promise()}return function(a){for(var b=d(),c=a.length,e=0,f=new Array(c),g=0;g<a.length;g++)!function(d){var g=null;a[d].done?a[d].done(function(){f[d]=arguments.length<2?arguments[0]:arguments,++e==c&&b.resolve.apply(b,f)}).fail(function(){b.reject(arguments)}):(g=a[d],a[d]=new Deferred,a[d].done(function(){f[d]=arguments.length<2?arguments[0]:arguments,++e==c&&b.resolve.apply(b,f)}).fail(function(){b.reject(arguments)}).resolve(g))}(g);return b.promise()}(arguments)};a.Deferred=d,a.when=d.when=e}($)}();
         | 
| @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            /*
         | 
| 2 | 
            +
             * This is a manifest file that'll be compiled into application.css, which will include all the files
         | 
| 3 | 
            +
             * listed below.
         | 
| 4 | 
            +
             *
         | 
| 5 | 
            +
             * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
         | 
| 6 | 
            +
             * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
         | 
| 7 | 
            +
             *
         | 
| 8 | 
            +
             * You're free to add application-wide styles to this file and they'll appear at the bottom of the
         | 
| 9 | 
            +
             * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
         | 
| 10 | 
            +
             * files in this directory. Styles in this file should be added after the last require_* statement.
         | 
| 11 | 
            +
             * It is generally better to create a new file per style scope.
         | 
| 12 | 
            +
             *
         | 
| 13 | 
            +
             *= require_tree .
         | 
| 14 | 
            +
             *= require_self
         | 
| 15 | 
            +
             */
         | 
| 16 | 
            +
             | 
| 17 | 
            +
             #auth-ok {
         | 
| 18 | 
            +
                position: absolute;
         | 
| 19 | 
            +
                padding-left: 190px;
         | 
| 20 | 
            +
                padding-top: 110px;
         | 
| 21 | 
            +
                font-size: 100px;
         | 
| 22 | 
            +
                display: none;
         | 
| 23 | 
            +
            }
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            div.hidden {
         | 
| 26 | 
            +
                display: none;
         | 
| 27 | 
            +
            }
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            module ApplicationCable
         | 
| 2 | 
            +
              class Connection < ActionCable::Connection::Base
         | 
| 3 | 
            +
                identified_by :current_user
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def connect
         | 
| 6 | 
            +
                  self.current_user = find_verified_user
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                protected
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def find_verified_user
         | 
| 12 | 
            +
                  SecureRandom.urlsafe_base64
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| @@ -0,0 +1,90 @@ | |
| 1 | 
            +
            module SelfAuthRails
         | 
| 2 | 
            +
              class SessionsController < ::ApplicationController
         | 
| 3 | 
            +
                def new; end
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                # Authenticates a user with the given token
         | 
| 6 | 
            +
                def create
         | 
| 7 | 
            +
                  if session_params[:token].empty? # AJAX request
         | 
| 8 | 
            +
                    SelfAuthRails.self_client.facts.request(session_params[:selfid],
         | 
| 9 | 
            +
                                                    [:display_name],
         | 
| 10 | 
            +
                                                    auth: true,
         | 
| 11 | 
            +
                                                    cid: session_params[:connection_id],
         | 
| 12 | 
            +
                                                    async: true)
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                    request.format = :json
         | 
| 15 | 
            +
                    respond_to do |format|
         | 
| 16 | 
            +
                      format.json { head :no_content }
         | 
| 17 | 
            +
                    end
         | 
| 18 | 
            +
                  else # Form submission
         | 
| 19 | 
            +
                    reset_user_token(session_params[:token])
         | 
| 20 | 
            +
                    respond_to do |format|
         | 
| 21 | 
            +
                      format.html { redirect_to SelfAuthRails.authenticated_path, notice: 'Welcome.' }
         | 
| 22 | 
            +
                    end
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                # Logs out the current user.
         | 
| 27 | 
            +
                def logout
         | 
| 28 | 
            +
                  session[:user_id] = nil
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  respond_to do |format|
         | 
| 31 | 
            +
                    format.html { redirect_to new_url }
         | 
| 32 | 
            +
                    format.json { head :no_content }
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                # Generates a QR code for authenticating users.
         | 
| 37 | 
            +
                def qr
         | 
| 38 | 
            +
                  if Rails.env.test?
         | 
| 39 | 
            +
                    send_data("test")
         | 
| 40 | 
            +
                  else
         | 
| 41 | 
            +
                    uuid = "qr::#{params[:uuid]}"
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                    img = ::SelfClient.authentication.generate_qr(
         | 
| 44 | 
            +
                      facts: SelfAuthRails.auth_facts,
         | 
| 45 | 
            +
                      cid: uuid,
         | 
| 46 | 
            +
                      exp_timeout: 86_400
         | 
| 47 | 
            +
                    )
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                    send_data(img.as_png(border: 0, size: 400),
         | 
| 50 | 
            +
                              type: 'image/png',
         | 
| 51 | 
            +
                              disposition: 'inline')
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                # Generates a dynamic link to authenticate users.
         | 
| 56 | 
            +
                def dl
         | 
| 57 | 
            +
                  link = '#'
         | 
| 58 | 
            +
                  unless Rails.env.test?
         | 
| 59 | 
            +
                    uuid = "dl::#{params[:uuid]}"
         | 
| 60 | 
            +
                    link = SelfAuthRails.self_client.facts.generate_deep_link(SelfAuthRails.auth_facts,
         | 
| 61 | 
            +
                                                                              SelfAuthRails.authenticated_path,
         | 
| 62 | 
            +
                                                                              cid: uuid,
         | 
| 63 | 
            +
                                                                              auth: true)
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
                  render json: { url: link }
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                protected
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                # Never trust parameters from the scary internet, only allow the white list through.
         | 
| 71 | 
            +
                def session_params
         | 
| 72 | 
            +
                  params.permit(:selfid, :token, :connection_id, :qr_url, :dl_url, :authenticity_token)
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                def auto_join_authenticated_users
         | 
| 76 | 
            +
                  redirect_to SelfAuthRails.authenticated_path unless session[:user_id].nil?
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                def reset_user_token(token)
         | 
| 80 | 
            +
                  @user = SelfAuthRails.session_class.find_by(token: token)
         | 
| 81 | 
            +
                  if @user.nil? # The user is already created on a different tab
         | 
| 82 | 
            +
                    @user = helpers.current_user
         | 
| 83 | 
            +
                  else
         | 
| 84 | 
            +
                    @user.token = ''
         | 
| 85 | 
            +
                    @user.save!
         | 
| 86 | 
            +
                    session[:user_id] = @user.id.to_s
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
                end
         | 
| 89 | 
            +
              end
         | 
| 90 | 
            +
            end
         | 
| @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            module SelfAuthRails
         | 
| 2 | 
            +
              module ApplicationHelper
         | 
| 3 | 
            +
                def authenticate_user!
         | 
| 4 | 
            +
                  current_url = request.base_url + request.path
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  uri = URI(main_app.root_url)
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  new_url = SelfAuthRails::Engine.routes.url_helpers.new_url(host: uri.host, port: uri.port)
         | 
| 9 | 
            +
                  create_url = SelfAuthRails::Engine.routes.url_helpers.create_url(host: uri.host, port: uri.port)
         | 
| 10 | 
            +
                  qr_url = SelfAuthRails::Engine.routes.url_helpers.qr_url(host: uri.host, port: uri.port)
         | 
| 11 | 
            +
                  dl_url = SelfAuthRails::Engine.routes.url_helpers.dl_url(host: uri.host, port: uri.port)
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  if [new_url, create_url, qr_url, dl_url].include? current_url
         | 
| 14 | 
            +
                    redirect_to root_url unless current_user.nil?
         | 
| 15 | 
            +
                  else
         | 
| 16 | 
            +
                    redirect_to new_url if current_user.nil?
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def current_user
         | 
| 21 | 
            +
                  SelfAuthRails.session_class.find_by(id: session[:user_id])
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
            end
         | 
| @@ -0,0 +1,76 @@ | |
| 1 | 
            +
            # Manages self authentication responses
         | 
| 2 | 
            +
            class SelfAuthResponseManagerService
         | 
| 3 | 
            +
              STATUS_ERR = 'errored'.freeze
         | 
| 4 | 
            +
              STATUS_REJ = 'rejected'.freeze
         | 
| 5 | 
            +
              STATUS_OK = 'accepted'.freeze
         | 
| 6 | 
            +
              STATUS_COM = 'completed'.freeze
         | 
| 7 | 
            +
              STATUS_RECIEVED = 'received'.freeze
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              def initialize(broadcaster)
         | 
| 10 | 
            +
                @broadcaster = broadcaster
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              # Processes a Self authentication response
         | 
| 14 | 
            +
              def process_response(self_auth_response)
         | 
| 15 | 
            +
                return if self_auth_response.nil?
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                cid = self_auth_response.id.split('_').first.split('::').last
         | 
| 18 | 
            +
                channel = "conversation_#{cid}_channel"
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                if self_auth_response.errored?
         | 
| 21 | 
            +
                  broadcast_status_change channel, STATUS_ERR, message: 'A timeout ocured while waiting for your device response'
         | 
| 22 | 
            +
                  return
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                if self_auth_response.rejected?
         | 
| 26 | 
            +
                  broadcast_status_change channel, STATUS_REJ
         | 
| 27 | 
            +
                  return
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                unless admin?(self_auth_response.from)
         | 
| 31 | 
            +
                  broadcast_status_change channel, STATUS_ERR, message: 'You are forbidden to access this service'
         | 
| 32 | 
            +
                  return
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                user = set_user_token(self_auth_response.from, self_auth_response)
         | 
| 36 | 
            +
                broadcast_status_change channel, STATUS_COM, token: user[:token]
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              private
         | 
| 40 | 
            +
             | 
| 41 | 
            +
              # creates or updates a user setting a random token.
         | 
| 42 | 
            +
              def set_user_token(selfid, self_auth_response)
         | 
| 43 | 
            +
                user = {
         | 
| 44 | 
            +
                  token: SecureRandom.uuid,
         | 
| 45 | 
            +
                  selfid: selfid,
         | 
| 46 | 
            +
                  facts: {}
         | 
| 47 | 
            +
                }
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                SelfAuthRails.auth_facts.each do |fact|
         | 
| 50 | 
            +
                  user[:facts][fact] = self_auth_response.attestation_values_for(fact).first
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                u = SelfAuthRails.session_class.find_by(selfid: user[:selfid])
         | 
| 54 | 
            +
                u = SelfAuthRails.session_class.new(selfid: user[:selfid]) if u.nil?
         | 
| 55 | 
            +
                u.token = user[:token]
         | 
| 56 | 
            +
                SelfAuthRails.fact_mapping.each do |fact_name, field|
         | 
| 57 | 
            +
                  u.send("#{field}=", user[:facts][fact_name.to_sym])
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
                u.save!
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                user
         | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
              # broadcasts a status change through websockets to the web client
         | 
| 65 | 
            +
              def broadcast_status_change(channel, status, opts = {})
         | 
| 66 | 
            +
                token = opts.fetch(:token, '')
         | 
| 67 | 
            +
                message = opts.fetch(:message, '')
         | 
| 68 | 
            +
                type = opts.fetch(:type, 'auth')
         | 
| 69 | 
            +
                @broadcaster.broadcast channel, { status: status, token: token, message: message, type: type }
         | 
| 70 | 
            +
              end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
              # checks if the given id is in the admins list
         | 
| 73 | 
            +
              def admin?(id)
         | 
| 74 | 
            +
                ENV['ADMIN_IDS'].split(',').include? id
         | 
| 75 | 
            +
              end
         | 
| 76 | 
            +
            end
         | 
| @@ -0,0 +1,75 @@ | |
| 1 | 
            +
            <%= hidden_field_tag "conversation_id", "", id: "conversation_id" %>
         | 
| 2 | 
            +
            <%= form_with(model: @user, url: create_path, local: true, id: "form-login", class: "form-horizontal form-bordered form-control-borderless") do |form| %>
         | 
| 3 | 
            +
              <%= form.hidden_field 'qr_url', id: 'qr_url', value: qr_path %>
         | 
| 4 | 
            +
              <%= form.hidden_field 'dl_url', id: 'dl_url', value: dl_path %>
         | 
| 5 | 
            +
              <%= form.hidden_field 'connection_id', id: "connection_id" %>
         | 
| 6 | 
            +
              <%= form.hidden_field :token, id: "login-token" %>
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              <div id="app">
         | 
| 9 | 
            +
                <section class="section">
         | 
| 10 | 
            +
                  <div class="container mt-5">
         | 
| 11 | 
            +
                    <div class="row">
         | 
| 12 | 
            +
                      <div class="col-12 col-sm-8 offset-sm-2 col-md-6 offset-md-3 col-lg-6 offset-lg-3 col-xl-6 offset-xl-3">
         | 
| 13 | 
            +
                        <div class="card card-primary">
         | 
| 14 | 
            +
                          <div class="card-body">
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                            <div id="dl-container" class="hidden">
         | 
| 17 | 
            +
                                <div class="col-xs-12">
         | 
| 18 | 
            +
                                    <h4>Welcome to Self</h4>
         | 
| 19 | 
            +
                                    <p>Please click the button below to authenticate using your Self App</p>
         | 
| 20 | 
            +
                                </div>
         | 
| 21 | 
            +
                                <div class="text-center form-group" style="border:0px; background-color: #f4f4f4; padding-top:20px; padding-bottom:20px">
         | 
| 22 | 
            +
                                    <a href="#" class='btn btn-success' id="dl">Authenticate with <strong>Self</strong></a>
         | 
| 23 | 
            +
                                    <button id="switch-not-dl" class="btn btn-info"><i class="fa fa-qrcode"></i> </button>
         | 
| 24 | 
            +
                                </div>
         | 
| 25 | 
            +
                            </div>
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                            <div id="non-dl-container">
         | 
| 28 | 
            +
                                <div id="qr-container" class='text-center form-group' style="border:0px;">
         | 
| 29 | 
            +
                                <div class="qr-wrapper" style='min-height:400px'>
         | 
| 30 | 
            +
                                    <div id="auth-ok">
         | 
| 31 | 
            +
                                        <i class="fa fa-check text-success"></i>
         | 
| 32 | 
            +
                                    </div>
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                                    <img src="" id="qr" style="max-width:400px;max-height:400px;width: inherit;height: inherit;">
         | 
| 35 | 
            +
                                </div>
         | 
| 36 | 
            +
                                </div>
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                                <div id='login-form-group' class="form-group" style="padding: 0 25px 0 25px;">
         | 
| 39 | 
            +
                                    <div class="input-group mb-3">
         | 
| 40 | 
            +
                                        <div class="input-group-prepend">
         | 
| 41 | 
            +
                                            <div class="input-group-text">
         | 
| 42 | 
            +
                                            <i class="fas fa-user"></i>
         | 
| 43 | 
            +
                                            </div>
         | 
| 44 | 
            +
                                        </div>        
         | 
| 45 | 
            +
                                        <%= form.text_field :selfid, placeholder: "Self identifier", class: "form-control input-lg", id: "selfid-field", required: true %>
         | 
| 46 | 
            +
                                        <div class="invalid-feedback invalid-pad">Oh no! Self identifier does not exist.</div>
         | 
| 47 | 
            +
                                        <div class="input-group-append">
         | 
| 48 | 
            +
                                            <button id="sign-in" class="btn btn-primary"><i class="fa fa-angle-right"></i> Sign in</button>
         | 
| 49 | 
            +
                                        </div>
         | 
| 50 | 
            +
                                    </div>
         | 
| 51 | 
            +
                                </div>
         | 
| 52 | 
            +
             | 
| 53 | 
            +
             | 
| 54 | 
            +
                                <div class="form-group form-actions login-new-identifier">
         | 
| 55 | 
            +
                                <div class="row justify-content-md-center">
         | 
| 56 | 
            +
                                    <div class="col">
         | 
| 57 | 
            +
                                        <small>Don't have a Self Identifier?</small><br />
         | 
| 58 | 
            +
                                        <a href="javascript:void(0)" id="link-register-login"><small class="text-info">Download the Self app and create a Self identifier</small></a>
         | 
| 59 | 
            +
                                    </div>
         | 
| 60 | 
            +
                                    <div class="col col-lg-4 text-right" style="padding-top:10px;">
         | 
| 61 | 
            +
                                    <button class="btn btn-sm btn-info"><i class="fa fa-angle-right"></i> Get the app</button>
         | 
| 62 | 
            +
                                    </div>
         | 
| 63 | 
            +
                                </div>
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                                </div>
         | 
| 66 | 
            +
                            </div>
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                          </div>
         | 
| 69 | 
            +
                        </div>
         | 
| 70 | 
            +
                      </div>
         | 
| 71 | 
            +
                    </div>
         | 
| 72 | 
            +
                  </div>
         | 
| 73 | 
            +
                </section>
         | 
| 74 | 
            +
              </div>
         | 
| 75 | 
            +
            <% end %>
         | 
    
        data/config/routes.rb
    ADDED
    
    | @@ -0,0 +1,11 @@ | |
| 1 | 
            +
            SelfAuthRails::Engine.routes.draw do
         | 
| 2 | 
            +
              get 'new', to: 'sessions#new'
         | 
| 3 | 
            +
              post 'create', to: 'sessions#create'
         | 
| 4 | 
            +
              get 'qr', to: 'sessions#qr'
         | 
| 5 | 
            +
              get 'dl', to: 'sessions#dl'
         | 
| 6 | 
            +
              get 'logout', to: 'sessions#logout'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              # Serve websocket cable requests in-process
         | 
| 9 | 
            +
              mount ActionCable.server => '/auth'
         | 
| 10 | 
            +
            end
         | 
| 11 | 
            +
             | 
| @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            module SelfAuthRails
         | 
| 2 | 
            +
              class Engine < ::Rails::Engine
         | 
| 3 | 
            +
                isolate_namespace SelfAuthRails
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                initializer "self-auth-rails.helpers" do
         | 
| 6 | 
            +
                  ActiveSupport.on_load(:action_controller_base) do
         | 
| 7 | 
            +
                    helper SelfAuthRails::Engine.helpers
         | 
| 8 | 
            +
                    include SelfAuthRails::Engine.helpers
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                initializer "self-auth-rails.assets.precompile" do |app|
         | 
| 13 | 
            +
                  app.config.assets.precompile << "manifest.js"
         | 
| 14 | 
            +
                  app.config.assets.precompile << "application.css"
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         | 
| @@ -0,0 +1,50 @@ | |
| 1 | 
            +
            require "self-auth-rails/version"
         | 
| 2 | 
            +
            require "self-auth-rails/engine"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module SelfAuthRails
         | 
| 5 | 
            +
              mattr_accessor :self_client,
         | 
| 6 | 
            +
                             :session_class_name,
         | 
| 7 | 
            +
                             :auth_facts,
         | 
| 8 | 
            +
                             :fact_mapping,
         | 
| 9 | 
            +
                             :authenticated_path,
         | 
| 10 | 
            +
                             :authenticated_path
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              class Engine < ::Rails::Engine
         | 
| 13 | 
            +
                default_auth_facts = [:display_name]
         | 
| 14 | 
            +
                default_authenticated_path = '/'
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                config.after_initialize do
         | 
| 17 | 
            +
                  unless SelfAuthRails::self_client.nil?
         | 
| 18 | 
            +
                    SelfAuthRails.auth_facts ||= default_auth_facts
         | 
| 19 | 
            +
                    SelfAuthRails.authenticated_path ||= default_authenticated_path
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                    response_manager = SelfAuthResponseManagerService.new(ActionCable.server)
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                    # Subscribe to fact responses
         | 
| 24 | 
            +
                    SelfAuthRails::self_client.facts.subscribe do |auth|
         | 
| 25 | 
            +
                      response_manager.process_response(auth)
         | 
| 26 | 
            +
                    end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                    # Subscribe to authentication responses
         | 
| 29 | 
            +
                    SelfAuthRails::self_client.authentication.subscribe do |auth|
         | 
| 30 | 
            +
                      response_manager.process_response(auth)
         | 
| 31 | 
            +
                    end
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              def self.session_class
         | 
| 37 | 
            +
                class_name = session_class_name || 'User'
         | 
| 38 | 
            +
                Object.const_get(class_name)
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
              # this function maps the vars from your app into your engine
         | 
| 42 | 
            +
              def self.setup(&block)
         | 
| 43 | 
            +
                yield self
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              def authenticated_path
         | 
| 47 | 
            +
                SelfAuthRails::authenticated_path || SelfAuthRails::default_authenticated_path
         | 
| 48 | 
            +
              end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            end
         | 
| @@ -0,0 +1,45 @@ | |
| 1 | 
            +
            require 'selfsdk'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            if defined?(Rails::Server) && !defined?(::SelfClient)
         | 
| 4 | 
            +
              # If self client is already initialized skip this initialization
         | 
| 5 | 
            +
              return unless defined?(::SelfClient).nil?
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              # Initializes self client
         | 
| 8 | 
            +
              ::SelfClient = SelfSDK::App.new(
         | 
| 9 | 
            +
                ENV['SELF_APP_ID'],
         | 
| 10 | 
            +
                ENV['SELF_APP_KEY'],
         | 
| 11 | 
            +
                ENV['SELF_STORAGE_KEY'],
         | 
| 12 | 
            +
                ENV['SELF_STORAGE_DIR'],
         | 
| 13 | 
            +
                env: ENV['SELF_ENVIRONMENT'],
         | 
| 14 | 
            +
              )
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              # Setup self-auth-rails engine
         | 
| 17 | 
            +
              SelfAuthRails.setup do |config|
         | 
| 18 | 
            +
                # Initializes the self-ruby-sdk client.
         | 
| 19 | 
            +
                config.self_client = ::SelfClient
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                # Sets rails logger as default self-ruby-sdk logger (optional).
         | 
| 22 | 
            +
                SelfSDK.logger = Rails.logger
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                # Defines the facts we're going to require for a user to authenticate.
         | 
| 25 | 
            +
                # If not provided it will default to [:display_name].
         | 
| 26 | 
            +
                config.auth_facts = [:display_name, :email_address]
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                # Defines the model class name to be used for persistance. The active
         | 
| 29 | 
            +
                # model provided must have `selfid` and `token` attributes. 
         | 
| 30 | 
            +
                # Note this config entry is optional and defaults to `User`.
         | 
| 31 | 
            +
                config.session_class_name = 'User'
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                # Defines the path to redirect the user when authentication succeeds.
         | 
| 34 | 
            +
                # Optional entry defaulting to '/'.
         | 
| 35 | 
            +
                config.authenticated_path = '/'
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                # In case you want to persist the authentication returning facts, you 
         | 
| 38 | 
            +
                # can provide a map for the fact_name and the ActiveModel object property.
         | 
| 39 | 
            +
                #
         | 
| 40 | 
            +
                # This is an optional entry and you only need to provide it if you're intending
         | 
| 41 | 
            +
                # to request and store facts during the authentication process with 
         | 
| 42 | 
            +
                # config.auth_facts
         | 
| 43 | 
            +
                config.fact_mapping = { display_name: :name }
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
            end
         | 
| @@ -0,0 +1,69 @@ | |
| 1 | 
            +
            # desc "Explaining what the task does"
         | 
| 2 | 
            +
            # task :self-auth-rails do
         | 
| 3 | 
            +
            #   # Task goes here
         | 
| 4 | 
            +
            # end
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            desc 'Creates the self-auth-rails initializer on your application'
         | 
| 7 | 
            +
            namespace :self_auth_rails do
         | 
| 8 | 
            +
              task :init do
         | 
| 9 | 
            +
                # Getting model to be used as authentication
         | 
| 10 | 
            +
                puts "What model do you want to use for authentication? (Defaults to \"User\")"
         | 
| 11 | 
            +
                model_name = STDIN.gets.strip
         | 
| 12 | 
            +
                model_name = 'User' if model_name.empty?
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                log 'Generating migrations'
         | 
| 15 | 
            +
                if Object.const_defined? model_name
         | 
| 16 | 
            +
                  log "#{model_name} already initialized, adding necessary columns"
         | 
| 17 | 
            +
                  system "SKIP_SELF=1 bin/rails g migration add_auth_to_#{model_name.downcase}s selfid:string name:string token:string"
         | 
| 18 | 
            +
                else
         | 
| 19 | 
            +
                  system "SKIP_SELF=1 bin/rails g model #{model_name.downcase} selfid:string name:string token:string"
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
                log 'migration file created!'
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                # Adding initializer to your application
         | 
| 24 | 
            +
                log 'Creating self-auth-rails initializer from template'
         | 
| 25 | 
            +
                body = File.read(__FILE__.gsub('self_auth_rails_tasks.rake', 'initializer.rb.tpl'))
         | 
| 26 | 
            +
                body.gsub!("{{AuthModel}}", model_name)
         | 
| 27 | 
            +
                File.open("#{Dir.pwd}/config/initializers/self_auth_rails.rb", 'w') { |file| file << body }
         | 
| 28 | 
            +
                log 'config/initializers/self_auth_rails.rb created'
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                # Adding routes to your application
         | 
| 31 | 
            +
                puts "What alias do you want to use to mount this rails engine? (Defaults to \"auth\")"
         | 
| 32 | 
            +
                as = STDIN.gets.strip
         | 
| 33 | 
            +
                as = 'auth' if as.empty?
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                log 'Adding routes to config/routes.rb'
         | 
| 36 | 
            +
                file_path = "#{Dir.pwd}/config/routes.rb"
         | 
| 37 | 
            +
                body = File.read(file_path)
         | 
| 38 | 
            +
                if body.include? 'SelfAuthRails'
         | 
| 39 | 
            +
                  log 'skipping... (self-auth-rails routes already added)'
         | 
| 40 | 
            +
                else
         | 
| 41 | 
            +
                  pattern = 'Rails.application.routes.draw do'
         | 
| 42 | 
            +
                  content = body.gsub(pattern, "#{pattern}\n  # Mounting self-auth-rails engine\n  mount SelfAuthRails::Engine => \"/auth\", as: \"#{as}\"")
         | 
| 43 | 
            +
                  File.open(file_path, 'w') { |file| file << content }
         | 
| 44 | 
            +
                  log 'self-auth-rails routes added'
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                puts 'Adding assets headers'
         | 
| 48 | 
            +
                assets_file_path = "#{Dir.pwd}/app/views/layouts/application.html.erb"
         | 
| 49 | 
            +
                body = File.read(assets_file_path)
         | 
| 50 | 
            +
                header1 = '<%= javascript_include_tag "self-auth-rails/manifest" %>'
         | 
| 51 | 
            +
                header2 = '<%= stylesheet_link_tag "self-auth-rails/application.css" %>'
         | 
| 52 | 
            +
                body.gsub!("</head>", "#{header1}\n\t#{header2}\n\t</head>")
         | 
| 53 | 
            +
                File.open(assets_file_path, 'w') { |file| file << body }
         | 
| 54 | 
            +
                log 'asset headers set'
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                manifest_file_path = "#{Dir.pwd}/app/assets/config/manifest.js"
         | 
| 57 | 
            +
                body = File.read(manifest_file_path)
         | 
| 58 | 
            +
                body += "\n//= link self-auth-rails/manifest.js"
         | 
| 59 | 
            +
                File.open(manifest_file_path, 'w') { |file| file << body }
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                log 'All set!'
         | 
| 62 | 
            +
                puts 'Remember to run `bin/rails db:migrate` to create your authentication table'
         | 
| 63 | 
            +
              end
         | 
| 64 | 
            +
            end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
            def log(str)
         | 
| 67 | 
            +
              str = "[self_auth_rails::init] #{str}"
         | 
| 68 | 
            +
              puts "\e[#{36}m#{str}\e[0m"
         | 
| 69 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,116 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: self-auth-rails
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.1.1
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Adrià Cidre
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: bin
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2022-08-11 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'
         | 
| 20 | 
            +
                - - ">="
         | 
| 21 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 22 | 
            +
                    version: 7.0.2.3
         | 
| 23 | 
            +
              type: :runtime
         | 
| 24 | 
            +
              prerelease: false
         | 
| 25 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 26 | 
            +
                requirements:
         | 
| 27 | 
            +
                - - "~>"
         | 
| 28 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 29 | 
            +
                    version: '7.0'
         | 
| 30 | 
            +
                - - ">="
         | 
| 31 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 32 | 
            +
                    version: 7.0.2.3
         | 
| 33 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 34 | 
            +
              name: selfsdk
         | 
| 35 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 36 | 
            +
                requirements:
         | 
| 37 | 
            +
                - - "~>"
         | 
| 38 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 39 | 
            +
                    version: '0.0'
         | 
| 40 | 
            +
                - - ">="
         | 
| 41 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 42 | 
            +
                    version: 0.0.200
         | 
| 43 | 
            +
              type: :runtime
         | 
| 44 | 
            +
              prerelease: false
         | 
| 45 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 46 | 
            +
                requirements:
         | 
| 47 | 
            +
                - - "~>"
         | 
| 48 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 49 | 
            +
                    version: '0.0'
         | 
| 50 | 
            +
                - - ">="
         | 
| 51 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 52 | 
            +
                    version: 0.0.200
         | 
| 53 | 
            +
            description: Provides an out of the box implementation for self authentication
         | 
| 54 | 
            +
            email:
         | 
| 55 | 
            +
            - 593270+adriacidre@users.noreply.github.com
         | 
| 56 | 
            +
            executables: []
         | 
| 57 | 
            +
            extensions: []
         | 
| 58 | 
            +
            extra_rdoc_files: []
         | 
| 59 | 
            +
            files:
         | 
| 60 | 
            +
            - MIT-LICENSE
         | 
| 61 | 
            +
            - README.md
         | 
| 62 | 
            +
            - Rakefile
         | 
| 63 | 
            +
            - app/assets/config/self-auth-rails/app.js
         | 
| 64 | 
            +
            - app/assets/config/self-auth-rails/cable.js
         | 
| 65 | 
            +
            - app/assets/config/self-auth-rails/channels/auth.js
         | 
| 66 | 
            +
            - app/assets/config/self-auth-rails/channels/messages_channel.js
         | 
| 67 | 
            +
            - app/assets/config/self-auth-rails/cookies.js
         | 
| 68 | 
            +
            - app/assets/config/self-auth-rails/ki.js
         | 
| 69 | 
            +
            - app/assets/config/self-auth-rails/manifest.js
         | 
| 70 | 
            +
            - app/assets/stylesheets/self-auth-rails/application.css
         | 
| 71 | 
            +
            - app/channels/application_cable/channel.rb
         | 
| 72 | 
            +
            - app/channels/application_cable/connection.rb
         | 
| 73 | 
            +
            - app/channels/messages_channel.rb
         | 
| 74 | 
            +
            - app/controllers/self_auth_rails/application_controller.rb
         | 
| 75 | 
            +
            - app/controllers/self_auth_rails/sessions_controller.rb
         | 
| 76 | 
            +
            - app/helpers/self_auth_rails/application_helper.rb
         | 
| 77 | 
            +
            - app/helpers/self_auth_rails/sessions_helper.rb
         | 
| 78 | 
            +
            - app/jobs/self_auth_rails/application_job.rb
         | 
| 79 | 
            +
            - app/mailers/self_auth_rails/application_mailer.rb
         | 
| 80 | 
            +
            - app/models/self_auth_rails/application_record.rb
         | 
| 81 | 
            +
            - app/services/self_auth_response_manager_service.rb
         | 
| 82 | 
            +
            - app/views/self_auth_rails/sessions/create.html.erb
         | 
| 83 | 
            +
            - app/views/self_auth_rails/sessions/new.html.erb
         | 
| 84 | 
            +
            - config/routes.rb
         | 
| 85 | 
            +
            - lib/self-auth-rails.rb
         | 
| 86 | 
            +
            - lib/self-auth-rails/engine.rb
         | 
| 87 | 
            +
            - lib/self-auth-rails/version.rb
         | 
| 88 | 
            +
            - lib/tasks/initializer.rb.tpl
         | 
| 89 | 
            +
            - lib/tasks/self_auth_rails_tasks.rake
         | 
| 90 | 
            +
            homepage: https://joinself.com
         | 
| 91 | 
            +
            licenses:
         | 
| 92 | 
            +
            - MIT
         | 
| 93 | 
            +
            metadata:
         | 
| 94 | 
            +
              homepage_uri: https://joinself.com
         | 
| 95 | 
            +
              source_code_uri: https://joinself.com
         | 
| 96 | 
            +
              changelog_uri: https://joinself.com/changelog
         | 
| 97 | 
            +
            post_install_message: 
         | 
| 98 | 
            +
            rdoc_options: []
         | 
| 99 | 
            +
            require_paths:
         | 
| 100 | 
            +
            - lib
         | 
| 101 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 102 | 
            +
              requirements:
         | 
| 103 | 
            +
              - - ">="
         | 
| 104 | 
            +
                - !ruby/object:Gem::Version
         | 
| 105 | 
            +
                  version: '0'
         | 
| 106 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 107 | 
            +
              requirements:
         | 
| 108 | 
            +
              - - ">="
         | 
| 109 | 
            +
                - !ruby/object:Gem::Version
         | 
| 110 | 
            +
                  version: '0'
         | 
| 111 | 
            +
            requirements: []
         | 
| 112 | 
            +
            rubygems_version: 3.1.6
         | 
| 113 | 
            +
            signing_key: 
         | 
| 114 | 
            +
            specification_version: 4
         | 
| 115 | 
            +
            summary: Joinself rails authentication gem
         | 
| 116 | 
            +
            test_files: []
         |