├── .gitattributes ├── .gitignore ├── .gitlab-ci.yml ├── .ruby-version ├── .travis.yml ├── CHANGES.md ├── Gemfile ├── Gemfile.lock ├── README.md ├── Rakefile ├── app ├── assets │ ├── images │ │ ├── Avatar_Pic.png │ │ ├── leap_web_users │ │ │ └── .gitkeep │ │ └── rails.png │ ├── javascripts │ │ ├── application.js │ │ ├── buttons.js │ │ ├── leap.js │ │ ├── platform.js │ │ ├── srp │ │ │ ├── .gitignore │ │ │ ├── .gitlab-ci.yml │ │ │ ├── .gitrepo │ │ │ ├── .nvmrc │ │ │ ├── .travis.yml │ │ │ ├── Readme.md │ │ │ ├── Version │ │ │ ├── index.js │ │ │ ├── karma.conf.js │ │ │ ├── lib │ │ │ │ ├── MD5.js │ │ │ │ ├── SHA1.js │ │ │ │ ├── SHA256.js │ │ │ │ ├── aes.js │ │ │ │ ├── cryptoHelpers.js │ │ │ │ ├── jsbn.js │ │ │ │ ├── jsbn2.js │ │ │ │ ├── prng4.js │ │ │ │ └── rng.js │ │ │ ├── package.json │ │ │ ├── spec │ │ │ │ ├── account_spec.js │ │ │ │ ├── calculate_spec.js │ │ │ │ ├── helper.js │ │ │ │ ├── login_spec.js │ │ │ │ ├── session_spec.js │ │ │ │ └── signup_spec.js │ │ │ └── src │ │ │ │ ├── jqueryRest.js │ │ │ │ ├── srp.js │ │ │ │ ├── srp_account.js │ │ │ │ ├── srp_calculate.js │ │ │ │ └── srp_session.js │ │ ├── typeahead.bundle.js │ │ └── users.js │ └── stylesheets │ │ ├── application.scss │ │ ├── custom │ │ ├── head-import.scss │ │ └── tail-import.scss │ │ ├── head.scss │ │ ├── leap.scss │ │ ├── leap_web_users │ │ └── .gitkeep │ │ ├── tail.scss │ │ └── twitter.scss ├── controllers │ ├── .gitkeep │ ├── account_controller.rb │ ├── api │ │ ├── certs_controller.rb │ │ ├── configs_controller.rb │ │ ├── identities_controller.rb │ │ ├── keys_controller.rb │ │ ├── messages_controller.rb │ │ ├── services_controller.rb │ │ ├── sessions_controller.rb │ │ ├── smtp_certs_controller.rb │ │ └── users_controller.rb │ ├── api_controller.rb │ ├── application_controller.rb │ ├── controller_extension │ │ ├── authentication.rb │ │ ├── errors.rb │ │ ├── fetch_user.rb │ │ ├── flash.rb │ │ ├── json_file.rb │ │ ├── json_responses.rb │ │ └── token_authentication.rb │ ├── errors_controller.rb │ ├── home_controller.rb │ ├── identities_controller.rb │ ├── invite_codes_controller.rb │ ├── keys_controller.rb │ ├── pages_controller.rb │ ├── sessions_controller.rb │ ├── static_config_controller.rb │ ├── users_controller.rb │ └── webfinger_controller.rb ├── designs │ ├── identity │ │ ├── cert_expiry_by_fingerprint.js │ │ ├── cert_fingerprints_by_expiry.js │ │ ├── disabled.js │ │ ├── keys_by_email.js │ │ └── pgp_key_by_email.js │ ├── message │ │ ├── by_user_ids_to_show.js │ │ └── by_user_ids_to_show_and_created_at.js │ └── user │ │ └── by_created_at_and_one_month_warning_not_sent.js ├── helpers │ ├── .gitkeep │ ├── application_helper.rb │ ├── core_helper.rb │ ├── download_helper.rb │ ├── email_aliases_helper.rb │ ├── link_helper.rb │ ├── navigation_helper.rb │ ├── search_helper.rb │ ├── sessions_helper.rb │ ├── table_helper.rb │ ├── twitter_helper.rb │ └── users_helper.rb ├── models │ ├── .gitkeep │ ├── account.rb │ ├── anonymous_service_level.rb │ ├── anonymous_user.rb │ ├── api_monitor_user.rb │ ├── api_token.rb │ ├── api_user.rb │ ├── client_certificate.rb │ ├── identity.rb │ ├── invite_code.rb │ ├── invite_code_validator.rb │ ├── keyring.rb │ ├── message.rb │ ├── pgp_key.rb │ ├── service_level.rb │ ├── session.rb │ ├── token.rb │ └── user.rb └── views │ ├── .gitkeep │ ├── account │ └── new.html.haml │ ├── api │ └── sessions │ │ └── new.json.erb │ ├── common │ ├── _action.html.haml │ ├── _action_buttons.html.haml │ ├── _download_button.html.haml │ ├── _home_page_buttons.html.haml │ ├── _navigation_item.html.haml │ ├── _search.html.haml │ └── _table.html.haml │ ├── emails │ └── _email.html.haml │ ├── errors │ ├── not_found.html.haml │ ├── not_found.json │ ├── server_error.html.haml │ └── server_error.json │ ├── home │ ├── _content.html.haml │ ├── _masthead.html.haml │ ├── _provider_message.html.haml │ └── index.html.haml │ ├── identities │ ├── _identity.html.haml │ └── index.html.haml │ ├── invite_codes │ ├── _invite_code.html.haml │ └── index.html.haml │ ├── kaminari │ ├── _first_page.html.haml │ ├── _gap.html.haml │ ├── _last_page.html.haml │ ├── _next_page.html.haml │ ├── _page.html.haml │ ├── _paginator.html.haml │ └── _prev_page.html.haml │ ├── layouts │ ├── _admin_navigation_item.html.haml │ ├── _content.html.haml │ ├── _footer.html.haml │ ├── _header.html.haml │ ├── _masthead.html.haml │ ├── _messages.html.haml │ ├── _navigation.html.haml │ ├── application.html.haml │ └── home.html.haml │ ├── pages │ ├── bye.html.haml │ ├── pricing.html.haml │ ├── privacy-policy.en.md │ └── terms-of-service.en.md │ ├── sessions │ ├── _warnings.html.haml │ ├── new.html.haml │ └── new.json.erb │ ├── tabs │ ├── _nav.html.haml │ ├── _tab.html.haml │ └── _tabs.html.haml │ ├── twitter │ └── _index.html.erb │ ├── users │ ├── _change_password.html.haml │ ├── _change_pgp_key.html.haml │ ├── _change_service_level.html.haml │ ├── _contact_email.html.haml │ ├── _destroy_account.html.haml │ ├── _edit.html.haml │ ├── _overview.html.haml │ ├── _user.html.haml │ ├── edit.html.haml │ ├── index.html.haml │ └── show.html.haml │ └── webfinger │ ├── host_meta.xml.erb │ └── search.xml.erb ├── bin ├── bundle ├── rails ├── rake └── setup ├── config.ru ├── config ├── application.rb ├── boot.rb ├── cert ├── ci │ ├── gitlab │ │ └── couchdb.yml │ └── travis │ │ ├── README │ │ ├── couchdb.admin.yml │ │ ├── couchdb.yml │ │ └── setup_couch.sh ├── couchdb.admin.example.yml ├── couchdb.example.yml ├── cucumber.yml ├── customization.example │ ├── locales │ │ ├── en.yml │ │ └── es.yml │ ├── public │ │ ├── favicon.ico │ │ └── img │ │ │ └── masthead.png │ ├── stylesheets │ │ └── tail.scss │ └── views │ │ └── pages │ │ ├── privacy-policy.en.md │ │ └── privacy-policy.es.md ├── customization │ └── README.md ├── defaults.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── initializers │ ├── add_controller_methods.rb │ ├── assets.rb │ ├── backtrace_silencers.rb │ ├── braintree.rb │ ├── client_side_validations.rb │ ├── couchrest_model.rb │ ├── customization.rb │ ├── error_constants.rb │ ├── exception_filter.rb │ ├── i18n.rb │ ├── inflections.rb │ ├── markdown_handler.rb │ ├── mime_types.rb │ ├── secret_token.rb │ ├── session_store.rb │ ├── simple_form.rb │ ├── simple_form_bootstrap.rb │ ├── warden.rb │ ├── webfinger.rb │ └── wrap_parameters.rb ├── locales │ ├── cs.yml │ ├── de.yml │ ├── el.yml │ ├── en │ │ ├── errors.en.yml │ │ ├── flash.en.yml │ │ ├── footer.en.yml │ │ ├── generic.en.yml │ │ ├── home.en.yml │ │ ├── messages.en.yml │ │ ├── simple_form.en.yml │ │ └── users.en.yml │ ├── es.yml │ ├── fi.yml │ ├── fr.yml │ ├── hu.yml │ ├── it.yml │ ├── lt.yml │ ├── nb.yml │ ├── nl.yml │ ├── pl.yml │ ├── pt.yml │ ├── ru.yml │ ├── tr.yml │ └── zh.yml ├── provider │ └── .gitkeep └── routes.rb ├── doc ├── CUSTOM.md ├── DEPLOY.md ├── DEVELOP.md ├── KNOWN_PROBLEMS.md ├── TROUBLESHOOT.md ├── TWITTER_FEED.md └── examples │ └── capistrano │ ├── Capfile │ └── deploy.rb ├── engines ├── billing │ ├── Gemfile │ ├── README.md │ ├── Rakefile │ ├── app │ │ ├── controllers │ │ │ ├── billing_admin_controller.rb │ │ │ ├── billing_base_controller.rb │ │ │ ├── payments_controller.rb │ │ │ └── subscriptions_controller.rb │ │ ├── helpers │ │ │ ├── billing_helper.rb │ │ │ ├── braintree_form_helper.rb │ │ │ └── braintree_helper.rb │ │ └── views │ │ │ ├── billing_admin │ │ │ └── show.html.haml │ │ │ ├── payments │ │ │ ├── _customer_form.html.haml │ │ │ ├── index.html.haml │ │ │ └── new.html.haml │ │ │ └── subscriptions │ │ │ ├── _customer_form.html.haml │ │ │ ├── _subscription_details.html.haml │ │ │ ├── index.html.haml │ │ │ └── show.html.haml │ ├── config │ │ ├── locales │ │ │ └── en.yml │ │ └── routes.rb │ ├── leap_web_billing.gemspec │ ├── lib │ │ ├── braintree_test_app.rb │ │ ├── leap_web_billing.rb │ │ └── leap_web_billing │ │ │ └── engine.rb │ ├── questions.md │ ├── script │ │ └── rails │ └── test │ │ ├── broken │ │ ├── admin_customer_test.rb │ │ ├── customer_creation_test.rb │ │ └── subscription_test.rb │ │ ├── factories.rb │ │ ├── functional │ │ ├── payments_controller_test.rb │ │ └── subscriptions_controller_test.rb │ │ ├── support │ │ ├── braintree_integration_test.rb │ │ └── customer_test_helper.rb │ │ └── test_helper.rb └── support │ ├── Gemfile │ ├── Gemfile.lock │ ├── README.md │ ├── Rakefile │ ├── app │ ├── assets │ │ └── javascripts │ │ │ └── tickets.js │ ├── controllers │ │ └── tickets_controller.rb │ ├── designs │ │ └── ticket │ │ │ ├── by_includes_post_by.js │ │ │ ├── by_includes_post_by_and_created_at.js │ │ │ ├── by_includes_post_by_and_is_open_and_created_at.js │ │ │ ├── by_includes_post_by_and_is_open_and_updated_at.js │ │ │ └── by_includes_post_by_and_updated_at.js │ ├── helpers │ │ ├── auto_tickets_path_helper.rb │ │ ├── ticket_i18n_helper.rb │ │ └── tickets_helper.rb │ ├── mailers │ │ ├── .gitkeep │ │ └── ticket_mailer.rb │ ├── models │ │ ├── ticket.rb │ │ ├── ticket_comment.rb │ │ └── ticket_selection.rb │ └── views │ │ ├── ticket_mailer │ │ └── notice.text.erb │ │ └── tickets │ │ ├── _comment.html.haml │ │ ├── _comments.html.haml │ │ ├── _edit_form.html.haml │ │ ├── _new_comment_form.html.haml │ │ ├── _tabs.html.haml │ │ ├── _ticket.html.haml │ │ ├── edit.html.haml │ │ ├── index.html.haml │ │ ├── new.html.haml │ │ └── show.html.haml │ ├── config │ ├── initializers │ │ └── account_lifecycle.rb │ ├── locales │ │ ├── en.yml │ │ └── es.yml │ └── routes.rb │ ├── leap_web_help.gemspec │ ├── lib │ ├── account_extension │ │ └── tickets.rb │ ├── leap_web_help.rb │ ├── leap_web_help │ │ └── engine.rb │ └── tasks │ │ └── leap_web_help_tasks.rake │ ├── script │ └── rails │ └── test │ ├── factories.rb │ ├── functional │ ├── ticket_comments_test.rb │ ├── ticket_mailer_test.rb │ ├── tickets_controller_test.rb │ └── tickets_list_test.rb │ ├── integration │ ├── create_ticket_test.rb │ └── navigation_test.rb │ ├── leap_web_help_test.rb │ ├── test_helper.rb │ └── unit │ ├── account_extension_test.rb │ ├── ticket_comment_test.rb │ └── ticket_test.rb ├── features ├── 1 │ ├── anonymous.feature │ ├── authentication.feature │ ├── config.feature │ ├── service.feature │ └── unauthenticated.feature ├── 2 │ └── keys.feature ├── anonymous.feature ├── authentication.feature ├── config.feature ├── messages.feature.disabled ├── service.feature ├── step_definitions │ ├── .gitkeep │ ├── api_steps.rb │ ├── auth_steps.rb │ ├── config_steps.rb │ ├── key_steps.rb │ └── messages_steps.rb ├── support │ ├── env.rb │ └── hooks.rb └── unauthenticated.feature ├── leap_web.gemspec ├── leap_web_localization.zip ├── lib ├── assets │ └── .gitkeep ├── email.rb ├── en_US.yml ├── extensions │ ├── couchrest.rb │ ├── simple_form.rb │ └── warden.rb ├── gemfile_tools.rb ├── leap_web │ └── version.rb ├── local_email.rb ├── login_format_validation.rb ├── tasks │ ├── .gitkeep │ ├── cucumber.rake │ ├── gems.rake │ ├── i18n.rake │ ├── invite_code.rake │ ├── leap_web_core_tasks.rake │ ├── leap_web_users_tasks.rake │ ├── task_helper.rb │ └── test.rake ├── temporary_user.rb ├── warden │ └── strategies │ │ └── secure_remote_password.rb ├── webfinger.rb └── webfinger │ ├── host_meta_presenter.rb │ └── user_presenter.rb ├── public ├── 422.html ├── favicon.ico ├── leap-img │ ├── 32 │ │ └── download.png │ ├── 64 │ │ └── download.png │ ├── 128 │ │ └── mask.png │ └── caution.png └── robots.txt ├── script ├── cucumber ├── generate_bearer_token ├── invalidate_bearer_token └── rails ├── test ├── factories.rb ├── files │ ├── ca.crt │ ├── ca.key │ ├── motd │ │ ├── 1.de.md │ │ ├── 1.en.md │ │ ├── 1.es.md │ │ └── 2.en.md │ └── provider.json ├── fixtures │ └── .gitkeep ├── functional │ ├── .gitkeep │ ├── account_controller_test.rb │ ├── api │ │ ├── certs_controller_test.rb │ │ ├── identities_controller_test.rb │ │ ├── messages_controller_test.rb │ │ ├── services_controller_test.rb │ │ ├── sessions_controller_test.rb │ │ ├── smtp_certs_controller_test.rb │ │ ├── token_auth_test.rb │ │ └── users_controller_test.rb │ ├── application_controller_test.rb │ ├── errors_controller_test.rb │ ├── helper_methods_test.rb │ ├── home_controller_test.rb │ ├── identities_controller_test.rb │ ├── keys_controller_test.rb │ ├── sessions_controller_test.rb │ ├── static_config_controller_test.rb │ ├── test_helpers_test.rb │ ├── users_controller_test.rb │ └── webfinger_controller_test.rb ├── integration │ ├── .gitkeep │ ├── api │ │ ├── Readme.md │ │ ├── cert_test.rb │ │ ├── login_test.rb │ │ ├── pgp_key_test.rb │ │ ├── python │ │ │ ├── flow_with_srp.py │ │ │ ├── login_wrong_username.py │ │ │ ├── signup.py │ │ │ ├── signup_and_login.py │ │ │ ├── signup_and_login_wrong_password.py │ │ │ └── umlauts.py │ │ ├── signup_test.rb │ │ ├── smtp_cert_test.rb │ │ ├── srp_test.rb │ │ ├── tmp_user_test.rb │ │ ├── token_auth_test.rb │ │ └── update_account_test.rb │ ├── browser │ │ ├── account_livecycle_test.rb │ │ ├── admin_test.rb │ │ ├── alternate_email_test.rb │ │ ├── password_validation_test.rb │ │ ├── security_test.rb │ │ └── session_test.rb │ ├── locale_path_test.rb │ ├── regression │ │ ├── key_discovery_test.rb │ │ └── provider_info_test.rb │ └── routes │ │ └── no_route_test.rb ├── nagios │ ├── soledad_sync.py │ ├── support │ │ ├── __init__.py │ │ ├── api.py │ │ ├── config.py │ │ ├── nagios_report.py │ │ ├── nagios_test.py │ │ └── user.py │ ├── webapp_login.py │ └── webapp_signup.py ├── support │ ├── api_controller_test.rb │ ├── api_integration_test.rb │ ├── assert_responses.rb │ ├── auth_test_helper.rb │ ├── browser_integration_test.rb │ ├── rack_stack_test.rb │ ├── rack_test.rb │ ├── record_assertions.rb │ ├── stub_record_helper.rb │ ├── time_test_helper.rb │ └── with_config_helper.rb ├── test_helper.rb └── unit │ ├── .gitkeep │ ├── account_test.rb │ ├── anonymous_user_test.rb │ ├── api_token_test.rb │ ├── client_certificate_test.rb │ ├── email_test.rb │ ├── helpers │ ├── session_helper_test.rb │ └── users_helper_test.rb │ ├── identity_test.rb │ ├── invite_code_test.rb │ ├── invite_code_validator_test.rb │ ├── keyring_test.rb │ ├── local_email_test.rb │ ├── temporary_user_test.rb │ ├── token_test.rb │ ├── user_test.rb │ ├── warden_strategy_secure_remote_password_test.rb │ └── webfinger │ ├── host_meta_presenter_test.rb │ └── user_presenter_test.rb └── vendor ├── assets ├── javascripts │ └── .gitkeep └── stylesheets │ └── .gitkeep ├── gems ├── certificate_authority │ ├── README.rdoc │ ├── VERSION.yml │ ├── certificate_authority.gemspec │ └── lib │ │ ├── certificate_authority.rb │ │ ├── certificate_authority │ │ ├── certificate.rb │ │ ├── certificate_revocation_list.rb │ │ ├── distinguished_name.rb │ │ ├── extensions.rb │ │ ├── key_material.rb │ │ ├── ocsp_handler.rb │ │ ├── pkcs11_key_material.rb │ │ ├── revocable.rb │ │ ├── serial_number.rb │ │ ├── signing_entity.rb │ │ └── signing_request.rb │ │ └── tasks │ │ └── certificate_authority.rake └── common_languages │ ├── LICENSE.txt │ ├── README.md │ ├── Rakefile │ ├── common_languages.gemspec │ ├── lib │ ├── common_languages.rb │ └── common_languages │ │ ├── data.rb │ │ ├── language.rb │ │ └── version.rb │ └── test │ ├── test_helper.rb │ └── usage_test.rb └── plugins └── .gitkeep /.gitattributes: -------------------------------------------------------------------------------- 1 | *.feature gitlab-language=gherkin 2 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | ruby2-1: 2 | image: "ruby:2.1" 3 | script: 4 | - bundle exec rake test 5 | artifacts: 6 | when: on_failure 7 | paths: 8 | - log/test.log 9 | - tmp/*.log 10 | - tmp/*.png 11 | 12 | ruby2-3: 13 | image: "ruby:2.3" 14 | script: 15 | - bundle exec rake test 16 | artifacts: 17 | when: on_failure 18 | paths: 19 | - log/test.log 20 | 21 | ruby2-4: 22 | image: "ruby:2.4" 23 | script: 24 | - bundle exec rake test 25 | artifacts: 26 | when: on_failure 27 | paths: 28 | - log/test.log 29 | 30 | services: 31 | - couchdb:1.6.1 32 | 33 | # Cache gems in between builds 34 | cache: 35 | key: shared 36 | paths: 37 | - vendor/ruby 38 | 39 | before_script: 40 | - ruby -v 41 | - curl -s couchdb:5984 42 | - cp config/ci/gitlab/couchdb.yml config/couchdb.admin.yml 43 | - cp config/ci/gitlab/couchdb.yml config 44 | - gem install bundler --no-ri --no-rdoc 45 | - bundle install -j $(nproc) --path vendor --without development debug 46 | - bundle exec rake RAILS_ENV=test db:rotate 47 | - bundle exec rake RAILS_ENV=test db:migrate 48 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.1.5 2 | 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | services: 3 | - couchdb 4 | notifications: 5 | email: false 6 | before_script: 7 | - "config/ci/travis/setup_couch.sh" 8 | - "mv config/ci/travis/couchdb.admin.yml config/couchdb.admin.yml" 9 | - "mv config/ci/travis/couchdb.yml config/couchdb.yml" 10 | - "bundle exec rake RAILS_ENV=test db:rotate" 11 | - "bundle exec rake RAILS_ENV=test db:migrate" 12 | after_script: 13 | - "cat tmp/*.test*.log" # printing logs from the failed integration tests 14 | bundler_args: --without development debug 15 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | # Add your own tasks in files placed in lib/tasks ending in .rake, 3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 4 | 5 | RAKE=true # let environment initialization code know if we are running via rake or not. 6 | 7 | require 'rake/packagetask' 8 | require 'rubygems/package_task' 9 | 10 | spec = eval(File.read('leap_web.gemspec')) 11 | Gem::PackageTask.new(spec) do |p| 12 | p.gem_spec = spec 13 | end 14 | 15 | require File.expand_path('../config/application', __FILE__) 16 | 17 | LeapWeb::Application.load_tasks 18 | -------------------------------------------------------------------------------- /app/assets/images/Avatar_Pic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leapcode/leap_web/fc00f46796da8a6fed381f9879e7af28f87312b4/app/assets/images/Avatar_Pic.png -------------------------------------------------------------------------------- /app/assets/images/leap_web_users/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leapcode/leap_web/fc00f46796da8a6fed381f9879e7af28f87312b4/app/assets/images/leap_web_users/.gitkeep -------------------------------------------------------------------------------- /app/assets/images/rails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leapcode/leap_web/fc00f46796da8a6fed381f9879e7af28f87312b4/app/assets/images/rails.png -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // the compiled file. 9 | // 10 | // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD 11 | // GO AFTER THE REQUIRES BELOW. 12 | // 13 | //= require jquery 14 | //= require jquery_ujs 15 | //= require srp 16 | //= require bootstrap 17 | //= require rails.validations 18 | //= require rails.validations.simple_form 19 | //= require typeahead.bundle 20 | //= require leap 21 | //= require platform 22 | //= require tickets 23 | //= require users 24 | //= require buttons 25 | -------------------------------------------------------------------------------- /app/assets/javascripts/leap.js: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // add a bootstrap alert to the page via javascript. 4 | // 5 | function alert_message(msg) { 6 | $('#messages').append('
×'+msg+'
'); 7 | } 8 | 9 | ClientSideValidations.formBuilders['SimpleForm::FormBuilder'].wrappers.bootstrap = ClientSideValidations.formBuilders['SimpleForm::FormBuilder'].wrappers["default"]; 10 | -------------------------------------------------------------------------------- /app/assets/javascripts/srp/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /app/assets/javascripts/srp/.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: ruby:latest 2 | 3 | # This folder is cached between builds 4 | # http://docs.gitlab.com/ce/ci/yaml/README.html#cache 5 | cache: 6 | paths: 7 | - node_modules/ 8 | 9 | test: 10 | script: 11 | - npm install 12 | - npm test -------------------------------------------------------------------------------- /app/assets/javascripts/srp/.gitrepo: -------------------------------------------------------------------------------- 1 | ; DO NOT EDIT (unless you know what you are doing) 2 | ; 3 | ; This subdirectory is a git "subrepo", and this file is maintained by the 4 | ; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme 5 | ; 6 | [subrepo] 7 | remote = https://leap.se/git/srp_js 8 | branch = master 9 | commit = 2088cbec310bb2c5768f4e8a1d424f8468e17c73 10 | parent = 8370b62870a3100e126e6434a09eb518c26dfd71 11 | cmdver = 0.3.1 12 | -------------------------------------------------------------------------------- /app/assets/javascripts/srp/.nvmrc: -------------------------------------------------------------------------------- 1 | v8.9 2 | -------------------------------------------------------------------------------- /app/assets/javascripts/srp/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | -------------------------------------------------------------------------------- /app/assets/javascripts/srp/Version: -------------------------------------------------------------------------------- 1 | 0.5.0 2 | -------------------------------------------------------------------------------- /app/assets/javascripts/srp/index.js: -------------------------------------------------------------------------------- 1 | //= require_tree ./lib 2 | //= require ./src/srp 3 | //= require_tree ./src 4 | -------------------------------------------------------------------------------- /app/assets/javascripts/srp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "srp_js", 3 | "version": "0.5.0", 4 | "description": "A secure remote password implementation for JavaScript", 5 | "homepage": "https://github.com/leapcode/srp_js#readme", 6 | "main": "index.js", 7 | "devDependencies": { 8 | "jasmine-core": "^2.3.4", 9 | "jasmine-jquery": "^2.1.0", 10 | "jquery": "^3.3.1", 11 | "karma": "^2.0.0", 12 | "karma-jasmine": "^1.1.1", 13 | "karma-phantomjs-launcher": "^1.0.4", 14 | "phantomjs-prebuilt": "^2.1.16", 15 | "sinon": "^4.2.1" 16 | }, 17 | "scripts": { 18 | "test": "node_modules/karma/bin/karma start --single-run" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/leapcode/srp_js.git" 23 | }, 24 | "author": "LEAP contributors", 25 | "license": "BSD-3-Clause", 26 | "bugs": { 27 | "url": "https://github.com/leapcode/srp_js/issues" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/assets/javascripts/srp/spec/account_spec.js: -------------------------------------------------------------------------------- 1 | describe("Account", function() { 2 | describe("without seeded values", function(){ 3 | beforeEach(function() { 4 | account = new srp.Account(); 5 | }); 6 | 7 | it("fetches the password from the password field", function(){ 8 | expect(account.password()).toBe("password"); 9 | }); 10 | 11 | it("fetches the login from the login field", function(){ 12 | expect(account.login()).toBe("testuser"); 13 | }); 14 | 15 | }); 16 | 17 | describe("with seeded values", function(){ 18 | beforeEach(function() { 19 | account = new srp.Account("login", "secret"); 20 | }); 21 | 22 | it("uses the seeded password", function(){ 23 | expect(account.password()).toBe("secret"); 24 | }); 25 | 26 | it("uses the seeded login", function(){ 27 | expect(account.login()).toBe("login"); 28 | }); 29 | 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /app/assets/javascripts/srp/src/srp.js: -------------------------------------------------------------------------------- 1 | var srp = (function(){ 2 | 3 | function signup() 4 | { 5 | srp.remote.signup(); 6 | }; 7 | 8 | function login() 9 | { 10 | srp.remote.login(); 11 | }; 12 | 13 | function update(submitEvent) 14 | { 15 | srp.remote.update(submitEvent); 16 | }; 17 | 18 | return { 19 | signup: signup, 20 | update: update, 21 | login: login 22 | } 23 | }()); 24 | 25 | -------------------------------------------------------------------------------- /app/assets/javascripts/srp/src/srp_account.js: -------------------------------------------------------------------------------- 1 | srp.Account = function(login, password, id) { 2 | 3 | // Returns the user's identity 4 | this.login = function() { 5 | return login || document.getElementById("srp_username").value; 6 | }; 7 | 8 | // Returns the password currently typed in 9 | this.password = function() { 10 | return password || document.getElementById("srp_password").value; 11 | }; 12 | 13 | // The user's id 14 | this.id = function() { 15 | return id || document.getElementById("user_param").value; 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.scss: -------------------------------------------------------------------------------- 1 | // 2 | // This will in turn import config/customization/stylesheets/head 3 | // It is a workaround for sass-rails defaulting to relative imports. 4 | // https://0xacab.org/leap/webapp/issues/8794 5 | // 6 | @import "custom/head-import"; 7 | 8 | // First import journal variables 9 | // @import "bootswatch/cerulean/variables"; 10 | 11 | // 12 | // import bootstrap. 13 | // 14 | @import "bootstrap-sprockets"; 15 | @import "bootstrap"; 16 | 17 | // 18 | // LEAP web app specific overrides 19 | // 20 | @import "leap"; 21 | @import "twitter"; 22 | 23 | // And finally bootswatch style itself 24 | // @import "bootswatch/cerulean/bootswatch"; 25 | 26 | // 27 | // This will in turn import config/customization/stylesheets/tail 28 | // It is a workaround for sass-rails defaulting to relative imports. 29 | // https://0xacab.org/leap/webapp/issues/8794 30 | // 31 | @import "custom/tail-import"; 32 | -------------------------------------------------------------------------------- /app/assets/stylesheets/custom/head-import.scss: -------------------------------------------------------------------------------- 1 | @import "head"; 2 | -------------------------------------------------------------------------------- /app/assets/stylesheets/custom/tail-import.scss: -------------------------------------------------------------------------------- 1 | @import "tail"; 2 | -------------------------------------------------------------------------------- /app/assets/stylesheets/head.scss: -------------------------------------------------------------------------------- 1 | // 2 | // put custom scss here that goes before all the others 3 | // 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/leap_web_users/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leapcode/leap_web/fc00f46796da8a6fed381f9879e7af28f87312b4/app/assets/stylesheets/leap_web_users/.gitkeep -------------------------------------------------------------------------------- /app/assets/stylesheets/tail.scss: -------------------------------------------------------------------------------- 1 | // 2 | // put custom scss here that goes after all the others 3 | // 4 | -------------------------------------------------------------------------------- /app/controllers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leapcode/leap_web/fc00f46796da8a6fed381f9879e7af28f87312b4/app/controllers/.gitkeep -------------------------------------------------------------------------------- /app/controllers/account_controller.rb: -------------------------------------------------------------------------------- 1 | class AccountController < ApplicationController 2 | 3 | before_filter :require_registration_allowed 4 | before_filter :redirect_if_logged_in 5 | 6 | respond_to :html 7 | 8 | def new 9 | @user = User.new 10 | end 11 | 12 | protected 13 | 14 | def require_registration_allowed 15 | unless APP_CONFIG[:allow_registration] 16 | redirect_to home_path 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /app/controllers/api/certs_controller.rb: -------------------------------------------------------------------------------- 1 | class Api::CertsController < ApiController 2 | 3 | before_filter :require_login, :unless => :anonymous_access_allowed? 4 | before_filter :require_enabled 5 | 6 | # GET /cert 7 | # deprecated - we actually create a new cert and that can 8 | # be reflected in the action. GET /cert will eventually go 9 | # away and be replaced by POST /cert 10 | def show 11 | create 12 | end 13 | 14 | # POST /cert 15 | def create 16 | @cert = ClientCertificate.new(:prefix => service_level.cert_prefix) 17 | render text: @cert.to_s, content_type: 'text/plain' 18 | end 19 | 20 | protected 21 | 22 | def require_enabled 23 | if !current_user.is_anonymous? && !current_user.enabled? 24 | access_denied 25 | end 26 | end 27 | 28 | def service_level 29 | current_user.effective_service_level 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /app/controllers/api/configs_controller.rb: -------------------------------------------------------------------------------- 1 | class Api::ConfigsController < ApiController 2 | include ControllerExtension::JsonFile 3 | 4 | before_filter :require_login, 5 | :unless => :anonymous_access_allowed?, 6 | :except => :index 7 | before_filter :sanitize_id, only: :show 8 | 9 | def index 10 | render json: {services: service_paths} 11 | end 12 | 13 | def show 14 | send_file lookup_file 15 | end 16 | 17 | protected 18 | 19 | SERVICE_IDS = { 20 | soledad: "soledad-service", 21 | eip: "eip-service", 22 | smtp: "smtp-service" 23 | } 24 | 25 | def service_paths 26 | Hash[SERVICE_IDS.map{|k,v| [k,"/#{api_version}/configs/#{v}.json"] } ] 27 | end 28 | 29 | def api_version 30 | ["1", "2"].include?(params[:version]) ? params[:version] : "2" 31 | end 32 | 33 | def sanitize_id 34 | @id = params[:id].downcase 35 | access_denied unless SERVICE_IDS.values.include? @id 36 | end 37 | 38 | def lookup_file 39 | path = APP_CONFIG[:config_file_paths][@id] 40 | not_found if path.blank? 41 | Rails.root.join path 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /app/controllers/api/identities_controller.rb: -------------------------------------------------------------------------------- 1 | module Api 2 | class IdentitiesController < ApiController 3 | before_filter :token_authenticate 4 | before_filter :require_monitor 5 | 6 | respond_to :json 7 | 8 | def show 9 | @identity = Identity.find_by_address(params[:id]) 10 | if @identity 11 | respond_with @identity 12 | else 13 | render_not_found 14 | end 15 | end 16 | 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /app/controllers/api/services_controller.rb: -------------------------------------------------------------------------------- 1 | class Api::ServicesController < ApiController 2 | 3 | before_filter :require_login, :unless => :anonymous_access_allowed? 4 | 5 | respond_to :json 6 | 7 | def show 8 | respond_with current_user.effective_service_level 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/controllers/api/sessions_controller.rb: -------------------------------------------------------------------------------- 1 | module Api 2 | class SessionsController < ApiController 3 | 4 | before_filter :require_login, only: :destroy 5 | respond_to :json 6 | 7 | def new 8 | @session = Session.new 9 | if authentication_errors 10 | @errors = authentication_errors 11 | render :status => 422 12 | end 13 | end 14 | 15 | def create 16 | logout if logged_in? 17 | if params['A'] 18 | authenticate! 19 | else 20 | @user = User.find_by_login(params['login']) 21 | render :json => {salt: @user.salt} 22 | end 23 | end 24 | 25 | def update 26 | authenticate! 27 | @token = Token.create(:user_id => current_user.id) 28 | session[:token] = @token.to_s 29 | render :json => login_response 30 | end 31 | 32 | def destroy 33 | logout 34 | head :no_content 35 | end 36 | 37 | protected 38 | 39 | def login_response 40 | handshake = session.delete(:handshake) || {} 41 | handshake.to_hash.merge(:id => current_user.id, :token => @token.to_s) 42 | end 43 | 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /app/controllers/api/smtp_certs_controller.rb: -------------------------------------------------------------------------------- 1 | class Api::SmtpCertsController < ApiController 2 | 3 | before_filter :require_login 4 | before_filter :require_email_account 5 | before_filter :fetch_identity 6 | before_filter :require_enabled 7 | 8 | # POST /1/smtp_cert 9 | def create 10 | @cert = ClientCertificate.new common_name: current_user.email_address 11 | @identity.register_cert(@cert) 12 | @identity.save 13 | render text: @cert.to_s, content_type: 'text/plain' 14 | end 15 | 16 | protected 17 | 18 | # 19 | # Filters 20 | # 21 | 22 | def require_email_account 23 | access_denied unless service_level.provides? 'email' 24 | end 25 | 26 | def require_enabled 27 | access_denied unless current_user.enabled? 28 | end 29 | 30 | def fetch_identity 31 | @identity = current_user.identity 32 | end 33 | 34 | # 35 | # Helper methods 36 | # 37 | 38 | def service_level 39 | current_user.effective_service_level 40 | end 41 | 42 | end 43 | -------------------------------------------------------------------------------- /app/controllers/api_controller.rb: -------------------------------------------------------------------------------- 1 | class ApiController < ApplicationController 2 | 3 | skip_before_filter :verify_authenticity_token 4 | 5 | protected 6 | 7 | def require_login 8 | require_token 9 | end 10 | 11 | def anonymous_access_allowed? 12 | APP_CONFIG[:allow_anonymous_certs] 13 | end 14 | 15 | end 16 | 17 | -------------------------------------------------------------------------------- /app/controllers/controller_extension/errors.rb: -------------------------------------------------------------------------------- 1 | module ControllerExtension::Errors 2 | extend ActiveSupport::Concern 3 | 4 | protected 5 | 6 | def access_denied 7 | render_error :not_authorized, :forbidden, home_url 8 | end 9 | alias_method :render_access_denied, :access_denied 10 | 11 | def login_required 12 | # Warden will intercept the 401 response and call 13 | # SessionController#unauthenticated instead. 14 | render_error :not_authorized_login, :unauthorized, login_url 15 | end 16 | alias_method :render_login_required, :login_required 17 | 18 | def not_found(msg=nil, url=nil) 19 | render_error(msg || :not_found, :not_found, url || home_url) 20 | end 21 | alias_method :render_not_found, :not_found 22 | 23 | private 24 | 25 | def render_error(message, status=nil, redirect=nil) 26 | error = message 27 | message = t(message) if message.is_a?(Symbol) 28 | respond_to do |format| 29 | format.html do 30 | redirect_to redirect, alert: message 31 | end 32 | format.json do 33 | status ||= :unprocessable_entity 34 | render json: {error: error, message: message}, status: status 35 | end 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /app/controllers/controller_extension/fetch_user.rb: -------------------------------------------------------------------------------- 1 | # 2 | # fetch the user taking into account permissions. 3 | # While normal users can only change settings for themselves 4 | # admins can change things for all users. 5 | # 6 | module ControllerExtension::FetchUser 7 | extend ActiveSupport::Concern 8 | 9 | protected 10 | 11 | # 12 | # fetch @user from params, but enforce permissions: 13 | # 14 | # * admins may fetch any user 15 | # * monitors may fetch test users 16 | # * users may fetch themselves 17 | # 18 | # these permissions matter, it is what protects 19 | # users from being updated or deleted by other users. 20 | # 21 | def fetch_user 22 | @user = User.find(params[:user_id] || params[:id]) 23 | if current_user.is_admin? || current_user.is_monitor? 24 | if @user.nil? 25 | not_found(t(:no_such_user), users_url) 26 | elsif current_user.is_monitor? 27 | access_denied unless @user.is_test? 28 | end 29 | elsif @user != current_user 30 | access_denied 31 | end 32 | end 33 | 34 | end 35 | -------------------------------------------------------------------------------- /app/controllers/controller_extension/json_file.rb: -------------------------------------------------------------------------------- 1 | module ControllerExtension::JsonFile 2 | extend ActiveSupport::Concern 3 | include ControllerExtension::Errors 4 | 5 | protected 6 | 7 | def send_file(filename) 8 | file = fetch_file(filename) 9 | if file.present? 10 | send_file_or_cache_hit(file) 11 | else 12 | not_found 13 | end 14 | end 15 | 16 | def send_file_or_cache_hit(file) 17 | if stale?(:last_modified => file.mtime) 18 | response.content_type = 'application/json' 19 | render :text => file.read 20 | end 21 | end 22 | 23 | def fetch_file(filename) 24 | File.new(filename) if File.exist?(filename) 25 | end 26 | 27 | end 28 | 29 | -------------------------------------------------------------------------------- /app/controllers/controller_extension/json_responses.rb: -------------------------------------------------------------------------------- 1 | module ControllerExtension::JsonResponses 2 | extend ActiveSupport::Concern 3 | 4 | private 5 | 6 | def success(key) 7 | json_message :success, key 8 | end 9 | 10 | def error(key) 11 | json_message :error, key 12 | end 13 | 14 | def json_message(type, key) 15 | long_key = "#{controller_string}.#{action_string}.#{key}" 16 | { type => key.to_s, 17 | :message => I18n.t(long_key, cascade: true) } 18 | end 19 | 20 | def controller_string 21 | self.class.name.underscore. 22 | sub(/_controller$/, ''). 23 | sub(/^v\d\//, '') 24 | end 25 | 26 | def action_string 27 | params[:action] 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /app/controllers/controller_extension/token_authentication.rb: -------------------------------------------------------------------------------- 1 | module ControllerExtension::TokenAuthentication 2 | extend ActiveSupport::Concern 3 | 4 | protected 5 | 6 | def token 7 | @token ||= authenticate_with_http_token do |token, options| 8 | Token.find_by_token(token) || ApiToken.find_by_token(token, request.headers['REMOTE_ADDR']) 9 | end 10 | end 11 | 12 | def token_authenticate 13 | @token_authenticated ||= token.authenticate if token 14 | end 15 | 16 | def require_token 17 | login_required unless token_authenticate 18 | end 19 | 20 | def logout 21 | super 22 | clear_token 23 | end 24 | 25 | def clear_token 26 | token.destroy if token 27 | end 28 | end 29 | 30 | -------------------------------------------------------------------------------- /app/controllers/errors_controller.rb: -------------------------------------------------------------------------------- 1 | class ErrorsController < ApplicationController 2 | 3 | # 404 4 | def not_found 5 | render status: 404 6 | end 7 | 8 | # 500 9 | def server_error 10 | render status: 500 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | class HomeController < ApplicationController 2 | layout 'home' 3 | 4 | respond_to :html 5 | 6 | def index 7 | if logged_in? 8 | redirect_to current_user 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/controllers/identities_controller.rb: -------------------------------------------------------------------------------- 1 | class IdentitiesController < ApplicationController 2 | 3 | respond_to :html, :json 4 | before_filter :require_login 5 | before_filter :require_admin 6 | before_filter :fetch_identity, only: :destroy 7 | before_filter :protect_main_email, only: :destroy 8 | 9 | def index 10 | if params[:query].present? 11 | @identities = Identity.address_starts_with(params[:query]).limit(100) 12 | else 13 | @identities = [] 14 | end 15 | respond_with @identities.map(&:login).sort 16 | end 17 | 18 | def destroy 19 | @identity.destroy 20 | redirect_to identities_path 21 | end 22 | 23 | protected 24 | def fetch_identity 25 | @identity = Identity.find(params[:id]) 26 | end 27 | 28 | def protect_main_email 29 | if @identity.status == :main_email 30 | flash[:error] = "You cannot destroy the main email. Remove or Rename the user instead." 31 | redirect_to identities_path 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /app/controllers/invite_codes_controller.rb: -------------------------------------------------------------------------------- 1 | class InviteCodesController < ApplicationController 2 | 3 | respond_to :html 4 | before_filter :require_login 5 | before_filter :require_admin 6 | before_filter :fetch_invite, only: :destroy 7 | 8 | def index 9 | @invite = InviteCode.new # for the creation form. 10 | @invites = InviteCode.by_updated_at.descending. 11 | page(params[:page]). 12 | per(APP_CONFIG[:pagination_size]) 13 | respond_with @invites 14 | end 15 | 16 | def create 17 | @invite = InviteCode.new(params[:invite_code]) 18 | @invite.save # throws exception on error (!) 19 | flash[:success] = t('created') + " #{@invite.invite_code}" 20 | rescue 21 | flash[:error] = "could not save invite code" # who knows why, invite.errors is empty 22 | ensure 23 | redirect_to invite_codes_path 24 | end 25 | 26 | def destroy 27 | @invite.destroy 28 | redirect_to invite_codes_path 29 | end 30 | 31 | protected 32 | 33 | def fetch_invite 34 | @invite = InviteCode.find(params[:id]) 35 | end 36 | 37 | end 38 | -------------------------------------------------------------------------------- /app/controllers/keys_controller.rb: -------------------------------------------------------------------------------- 1 | class KeysController < ApplicationController 2 | 3 | # 4 | # Render the user's key as plain text, without a layout. 5 | # 6 | # 404 error if user doesn't exist 7 | # 8 | # blank result if user doesn't have key (which shouldn't generally occur) 9 | # 10 | def show 11 | user = User.find_by_login(params[:login]) 12 | if user 13 | render text: user.public_key, content_type: 'text/text' 14 | else 15 | head 404 16 | end 17 | end 18 | 19 | end 20 | -------------------------------------------------------------------------------- /app/controllers/pages_controller.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Render static pages 3 | # 4 | 5 | 6 | class PagesController < ApplicationController 7 | respond_to :html 8 | 9 | def show 10 | @show_navigation = false 11 | render page_name 12 | rescue ActionView::MissingTemplate 13 | raise ActionController::RoutingError.new('Not Found') 14 | end 15 | 16 | private 17 | 18 | def page_name 19 | request.path.sub(/^\/(#{CommonLanguages.match_available}\/)?/, '') 20 | end 21 | 22 | end 23 | -------------------------------------------------------------------------------- /app/controllers/sessions_controller.rb: -------------------------------------------------------------------------------- 1 | class SessionsController < ApplicationController 2 | 3 | before_filter :redirect_if_logged_in, :only => [:new] 4 | respond_to :html, :json 5 | 6 | def new 7 | @session = Session.new 8 | if authentication_errors 9 | @errors = authentication_errors 10 | render :status => 422 11 | end 12 | end 13 | 14 | def destroy 15 | logout 16 | redirect_to home_url 17 | end 18 | 19 | # 20 | # Warden will catch all 401s and triggers this action: 21 | # 22 | def unauthenticated 23 | login_required 24 | end 25 | 26 | # 27 | # this is a bad hack, but user_url(user) is not available 28 | # also, this doesn't work because the redirect happens as a PUT. no idea why. 29 | # 30 | #Warden::Manager.after_authentication do |user, auth, opts| 31 | # response = Rack::Response.new 32 | # response.redirect "/users/#{user.id}" 33 | # throw :warden, response.finish 34 | #end 35 | 36 | Warden::Manager.after_set_user do |user, auth, opts| 37 | scope = opts[:scope] 38 | unless user.enabled? 39 | auth.logout(scope) 40 | throw(:warden, scope: scope, reason: "User not active") 41 | end 42 | end 43 | 44 | 45 | end 46 | -------------------------------------------------------------------------------- /app/controllers/static_config_controller.rb: -------------------------------------------------------------------------------- 1 | # 2 | # This controller is responsible for returning some static config files, such as /provider.json 3 | # 4 | class StaticConfigController < ActionController::Base 5 | include ControllerExtension::JsonFile 6 | 7 | before_filter :set_minimum_client_version 8 | 9 | def provider 10 | send_file provider_json 11 | end 12 | 13 | protected 14 | 15 | # ensure that the header X-Minimum-Client-Version is sent 16 | # regardless if a 200 or 304 (not modified) or 404 response is sent. 17 | def set_minimum_client_version 18 | response.headers["X-Minimum-Client-Version"] = 19 | APP_CONFIG[:minimum_client_version].to_s 20 | end 21 | 22 | def provider_json 23 | Rails.root.join APP_CONFIG[:config_file_paths]['provider'] 24 | end 25 | 26 | end 27 | -------------------------------------------------------------------------------- /app/controllers/webfinger_controller.rb: -------------------------------------------------------------------------------- 1 | class WebfingerController < ApplicationController 2 | 3 | respond_to :xml, :json 4 | layout false 5 | 6 | def host_meta 7 | @host_meta = Webfinger::HostMetaPresenter.new(request) 8 | respond_with @host_meta 9 | end 10 | 11 | def search 12 | username = params[:q].split('@')[0].to_s.downcase 13 | user = User.find_by_login(username) 14 | raise RECORD_NOT_FOUND, 'User not found' unless user.present? 15 | @presenter = Webfinger::UserPresenter.new(user, request) 16 | respond_with @presenter 17 | end 18 | 19 | end 20 | -------------------------------------------------------------------------------- /app/designs/identity/cert_expiry_by_fingerprint.js: -------------------------------------------------------------------------------- 1 | function(doc) { 2 | if (doc.type != 'Identity') { 3 | return; 4 | } 5 | if (typeof doc.cert_fingerprints === "object") { 6 | for (fp in doc.cert_fingerprints) { 7 | if (doc.cert_fingerprints.hasOwnProperty(fp)) { 8 | emit(fp, doc.cert_fingerprints[fp]); 9 | } 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/designs/identity/cert_fingerprints_by_expiry.js: -------------------------------------------------------------------------------- 1 | function(doc) { 2 | if (doc.type != 'Identity') { 3 | return; 4 | } 5 | if (typeof doc.cert_fingerprints === "object") { 6 | for (fp in doc.cert_fingerprints) { 7 | if (doc.cert_fingerprints.hasOwnProperty(fp)) { 8 | emit(doc.cert_fingerprints[fp], fp); 9 | } 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/designs/identity/disabled.js: -------------------------------------------------------------------------------- 1 | function(doc) { 2 | if (doc.type != 'Identity') { 3 | return; 4 | } 5 | if (typeof doc.user_id === "undefined") { 6 | emit(doc._id, 1); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /app/designs/identity/keys_by_email.js: -------------------------------------------------------------------------------- 1 | function(doc) { 2 | if (doc.type != 'Identity') { 3 | return; 4 | } 5 | if (typeof doc.keys === "object") { 6 | emit(doc.address, doc.keys); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /app/designs/identity/pgp_key_by_email.js: -------------------------------------------------------------------------------- 1 | function(doc) { 2 | if (doc.type != 'Identity') { 3 | return; 4 | } 5 | if (typeof doc.keys === "object") { 6 | emit(doc.address, doc.keys["pgp"]); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /app/designs/message/by_user_ids_to_show.js: -------------------------------------------------------------------------------- 1 | function (doc) { 2 | if (doc.type === 'Message' && doc.user_ids_to_show && Array.isArray(doc.user_ids_to_show)) { 3 | doc.user_ids_to_show.forEach(function (userId) { 4 | emit(userId, 1); 5 | }); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /app/designs/message/by_user_ids_to_show_and_created_at.js: -------------------------------------------------------------------------------- 1 | // not using at moment 2 | // call with something like Message.by_user_ids_to_show_and_created_at.startkey([user_id, start_date]).endkey([user_id,end_date]) 3 | function (doc) { 4 | if (doc.type === 'Message' && doc.user_ids_to_show && Array.isArray(doc.user_ids_to_show)) { 5 | doc.user_ids_to_show.forEach(function (userId) { 6 | emit([userId, doc.created_at], 1); 7 | }); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /app/designs/user/by_created_at_and_one_month_warning_not_sent.js: -------------------------------------------------------------------------------- 1 | function (doc) { 2 | if ((doc['type'] == 'User') && (doc['created_at'] != null) && (doc['one_month_warning_sent'] == null)) { 3 | emit(doc['created_at'], 1); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /app/helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leapcode/leap_web/fc00f46796da8a6fed381f9879e7af28f87312b4/app/helpers/.gitkeep -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | 3 | # 4 | # determine title for the page 5 | # 6 | def html_title 7 | if content_for?(:title) 8 | yield(:title) 9 | elsif @title 10 | [@title, ' - ', APP_CONFIG[:domain]].join 11 | else 12 | APP_CONFIG[:domain] 13 | end 14 | end 15 | 16 | # 17 | # markup for bootstrap icon 18 | # 19 | # http://twitter.github.io/bootstrap/base-css.html#icons 20 | # 21 | def icon(name, color=nil) 22 | content_tag :span, '', 23 | class: "glyphicon glyphicon-#{name} #{color_class(color)}" 24 | end 25 | 26 | def big_icon(name, color=nil) 27 | " ".html_safe 28 | end 29 | 30 | def huge_icon(name, color=nil) 31 | " ".html_safe 32 | end 33 | 34 | def color_class(color) 35 | if color.nil? 36 | nil 37 | elsif color == :black 38 | 'icon-black' 39 | elsif color == :white 40 | 'icon-white' 41 | end 42 | end 43 | 44 | # fairly strict sanitation for flash messages 45 | def format_flash(msg) 46 | sanitize(msg, tags: %w(em strong b br), attributes: []) 47 | end 48 | 49 | end 50 | -------------------------------------------------------------------------------- /app/helpers/core_helper.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Misc. helpers needed throughout. 3 | # 4 | module CoreHelper 5 | 6 | # 7 | # insert common buttons (download, login, etc) 8 | # 9 | def home_page_buttons 10 | render 'common/home_page_buttons' 11 | end 12 | 13 | # 14 | # returns true if the configured service levels contain a level with a price attached 15 | # 16 | def paid_service_level? 17 | APP_CONFIG[:service_levels].present? && APP_CONFIG[:service_levels].detect{|k,v| v['rate'].present?} 18 | end 19 | 20 | # 21 | # a bunch of links to the different languages that are available. 22 | # 23 | def locales_links 24 | CommonLanguages.available.collect { |lang| 25 | link_to(lang.name, 26 | {:action => params[:action], :controller => params[:controller], :locale => lang.code}, 27 | {:class => (lang.code == I18n.locale ? 'locale active' : 'locale')} 28 | ) 29 | }.join(" ").html_safe 30 | end 31 | 32 | # 33 | # displays the datetime as time ago in words, 34 | # but has the absolute time in a tooltip. 35 | # 36 | def simple_date(datetime) 37 | content_tag :span, time_ago_in_words(datetime), :title => datetime.to_s, :class => 'date' 38 | end 39 | 40 | end 41 | -------------------------------------------------------------------------------- /app/helpers/download_helper.rb: -------------------------------------------------------------------------------- 1 | module DownloadHelper 2 | 3 | def alternative_client_links(os = nil) 4 | alternative_clients(os).map do |client| 5 | link_to(I18n.t("os."+client), client_download_url(client)) 6 | end 7 | end 8 | 9 | def alternative_clients(os = nil) 10 | available_clients - [os] 11 | end 12 | 13 | def client_download_url(os = nil) 14 | client_download_domain + client_download_path(os) 15 | end 16 | 17 | def client_download_path(os) 18 | download_paths[os.to_s] || download_paths['other'] || '' 19 | end 20 | 21 | def available_clients 22 | APP_CONFIG[:available_clients] || [] 23 | end 24 | 25 | def client_download_domain 26 | APP_CONFIG[:client_download_domain] || '' 27 | end 28 | 29 | def download_paths 30 | APP_CONFIG[:download_paths] || {} 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /app/helpers/email_aliases_helper.rb: -------------------------------------------------------------------------------- 1 | module EmailAliasesHelper 2 | 3 | def email_alias_form(options = {}) 4 | simple_form_for [@user, EmailAlias.new()], 5 | :html => {:class => "form-horizontal email-alias form"}, 6 | :validate => true do |f| 7 | yield f 8 | end 9 | end 10 | 11 | end 12 | -------------------------------------------------------------------------------- /app/helpers/search_helper.rb: -------------------------------------------------------------------------------- 1 | module SearchHelper 2 | 3 | def search(target) 4 | render 'common/search', path: url_for(target), 5 | id: target.to_s.singularize, 6 | submit_label: t('.search', cascade: true) 7 | end 8 | 9 | end 10 | -------------------------------------------------------------------------------- /app/helpers/sessions_helper.rb: -------------------------------------------------------------------------------- 1 | module SessionsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/table_helper.rb: -------------------------------------------------------------------------------- 1 | module TableHelper 2 | 3 | # we do the translation here so the .key lookup is relative 4 | # to the partial the helper was called from. 5 | def table(content, columns) 6 | render 'common/table', 7 | content: content, 8 | columns: columns, 9 | headers: columns.map {|h| t(".#{h}", cascading: true) }, 10 | none: t('.none', cascading: true) 11 | end 12 | 13 | end 14 | -------------------------------------------------------------------------------- /app/helpers/users_helper.rb: -------------------------------------------------------------------------------- 1 | module UsersHelper 2 | 3 | def user_form_class(*classes) 4 | (classes + ['user', 'hidden', 'js-show', (@user.new_record? ? 'new' : 'edit')]).compact.join(' ') 5 | end 6 | 7 | def wrapped(item, options = {}) 8 | options[:as] ||= :div 9 | content_tag options[:as], :class => dom_class(item), :id => dom_id(item) do 10 | yield 11 | end 12 | end 13 | 14 | 15 | def destroy_account_text 16 | if @user == current_user 17 | t(:destroy_my_account) 18 | else 19 | t(:admin_destroy_account, :username => @user.login) 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leapcode/leap_web/fc00f46796da8a6fed381f9879e7af28f87312b4/app/models/.gitkeep -------------------------------------------------------------------------------- /app/models/anonymous_service_level.rb: -------------------------------------------------------------------------------- 1 | class AnonymousServiceLevel 2 | 3 | delegate :to_json, to: :config_hash 4 | 5 | def cert_prefix 6 | if APP_CONFIG[:allow_limited_certs] 7 | APP_CONFIG[:limited_cert_prefix] 8 | elsif APP_CONFIG[:allow_unlimited_certs] 9 | APP_CONFIG[:unlimited_cert_prefix] 10 | end 11 | end 12 | 13 | def description 14 | if APP_CONFIG[:allow_anonymous_certs] 15 | "anonymous access to the VPN" 16 | else 17 | "please login to access our services" 18 | end 19 | end 20 | 21 | protected 22 | 23 | def config_hash 24 | { name: "anonymous", 25 | description: description, 26 | eip_rate_limit: APP_CONFIG[:allow_limited_certs] 27 | } 28 | end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /app/models/anonymous_user.rb: -------------------------------------------------------------------------------- 1 | # The nil object for the user class 2 | class AnonymousUser < Object 3 | 4 | def effective_service_level 5 | AnonymousServiceLevel.new 6 | end 7 | 8 | def is_admin? 9 | false 10 | end 11 | 12 | def is_monitor? 13 | false 14 | end 15 | 16 | def id 17 | nil 18 | end 19 | 20 | def has_payment_info? 21 | false 22 | end 23 | 24 | def email 25 | nil 26 | end 27 | 28 | def email_address 29 | nil 30 | end 31 | 32 | def login 33 | nil 34 | end 35 | 36 | def messages 37 | [] 38 | end 39 | 40 | def is_anonymous? 41 | true 42 | end 43 | 44 | def enabled? 45 | false 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /app/models/api_monitor_user.rb: -------------------------------------------------------------------------------- 1 | # 2 | # A user that has limited admin access, to be used 3 | # for running monitor tests against a live production 4 | # installation. 5 | # 6 | class ApiMonitorUser < ApiUser 7 | def is_monitor? 8 | true 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /app/models/api_user.rb: -------------------------------------------------------------------------------- 1 | 2 | class ApiUser < AnonymousUser 3 | end 4 | 5 | # 6 | # Not yet supported: 7 | # 8 | #class ApiAdminUser < ApiUser 9 | # def is_admin? 10 | # true 11 | # end 12 | #end 13 | -------------------------------------------------------------------------------- /app/models/invite_code.rb: -------------------------------------------------------------------------------- 1 | require 'base64' 2 | require 'securerandom' 3 | 4 | class InviteCode < CouchRest::Model::Base 5 | use_database 'invite_codes' 6 | property :invite_code, String, :read_only => true 7 | property :invite_count, Integer, :default => 0, :accessible => true 8 | property :max_uses, Integer, :default => 1 9 | 10 | timestamps! 11 | 12 | design do 13 | view :by_invite_code 14 | view :by_invite_count 15 | view :by_created_at 16 | view :by_updated_at 17 | end 18 | 19 | def initialize(attributes = {}, options = {}) 20 | attributes[:id] = attributes["invite_code"] || InviteCode.generate_invite 21 | super(attributes, options) 22 | if new? 23 | write_attribute('invite_code', attributes[:id]) 24 | write_attribute('max_uses', attributes[:max_uses] || 1) 25 | end 26 | end 27 | 28 | def self.generate_invite 29 | Base64.encode64(SecureRandom.random_bytes).downcase.gsub(/[0oil1+_\/]/,'')[0..7].scan(/..../).join('-') 30 | end 31 | end 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/models/invite_code_validator.rb: -------------------------------------------------------------------------------- 1 | class InviteCodeValidator < ActiveModel::Validator 2 | 3 | def validate(user) 4 | 5 | user_invite_code = InviteCode.find_by_invite_code user.invite_code 6 | 7 | if not_existent?(user_invite_code) 8 | add_error_to_user("This is not a valid code", user) 9 | 10 | elsif has_no_uses_left?(user_invite_code) 11 | add_error_to_user("This code has already been used", user) 12 | end 13 | end 14 | 15 | private 16 | def not_existent?(code) 17 | code == nil 18 | end 19 | 20 | def has_no_uses_left?(code) 21 | code.invite_count >= code.max_uses 22 | end 23 | 24 | def add_error_to_user(error, user) 25 | user.errors[:invite_code] << error 26 | end 27 | end 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/models/message.rb: -------------------------------------------------------------------------------- 1 | class Message < CouchRest::Model::Base 2 | 3 | use_database :messages 4 | 5 | property :text, String 6 | property :user_ids_to_show, [String] 7 | property :user_ids_have_shown, [String] # is this necessary to store? 8 | 9 | timestamps! 10 | 11 | design do 12 | own_path = Pathname.new(File.dirname(__FILE__)) 13 | load_views(own_path.join('..', 'designs', 'message')) 14 | end 15 | 16 | def mark_as_read_by(user) 17 | user_ids_to_show.delete(user.id) 18 | # is it necessary to keep track of what users have already seen it? 19 | user_ids_have_shown << user.id unless read_by?(user) 20 | end 21 | 22 | def read_by?(user) 23 | user_ids_have_shown.include?(user.id) 24 | end 25 | 26 | def unread_by?(user) 27 | user_ids_to_show.include?(user.id) 28 | end 29 | 30 | def as_json(*args, &block) 31 | {"id" => id, "text" => text}.as_json(*args, &block) 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /app/models/pgp_key.rb: -------------------------------------------------------------------------------- 1 | class PgpKey 2 | include ActiveModel::Validations 3 | 4 | KEYBLOCK_IDENTIFIERS = [ 5 | '-----BEGIN PGP PUBLIC KEY BLOCK-----', 6 | '-----END PGP PUBLIC KEY BLOCK-----', 7 | ] 8 | 9 | # mostly for testing. 10 | attr_accessor :keyblock 11 | 12 | validate :validate_keyblock_format 13 | 14 | def initialize(keyblock = nil) 15 | @keyblock = keyblock 16 | end 17 | 18 | def to_s 19 | @keyblock 20 | end 21 | 22 | def present? 23 | @keyblock.present? 24 | end 25 | 26 | # allow comparison with plain keyblock strings. 27 | def ==(other) 28 | return false if (self.present? != other.present?) 29 | self.equal?(other) or 30 | # relax the comparison on line ends. 31 | self.to_s.tr_s("\n\r", '') == other.tr_s("\n\r", '') 32 | end 33 | 34 | protected 35 | 36 | def validate_keyblock_format 37 | if keyblock_identifier_missing? 38 | errors.add :public_key_block, 39 | "does not look like an armored pgp public key block" 40 | end 41 | end 42 | 43 | def keyblock_identifier_missing? 44 | KEYBLOCK_IDENTIFIERS.find do |identify| 45 | !@keyblock.include?(identify) 46 | end 47 | end 48 | 49 | end 50 | -------------------------------------------------------------------------------- /app/models/service_level.rb: -------------------------------------------------------------------------------- 1 | class ServiceLevel 2 | 3 | def initialize(attributes = {}) 4 | @id = attributes[:id] || APP_CONFIG[:default_service_level] 5 | end 6 | 7 | def self.select_options 8 | APP_CONFIG[:service_levels].map do |id,config_hash| 9 | [config_hash[:description], id] 10 | end 11 | end 12 | 13 | def id 14 | @id 15 | end 16 | 17 | delegate :to_json, to: :config_hash 18 | 19 | def cert_prefix 20 | if limited_cert? 21 | APP_CONFIG[:limited_cert_prefix] 22 | elsif APP_CONFIG[:allow_unlimited_certs] 23 | APP_CONFIG[:unlimited_cert_prefix] 24 | end 25 | end 26 | 27 | def provides?(service) 28 | services.include? service 29 | end 30 | 31 | def services 32 | config_hash[:services] || [] 33 | end 34 | 35 | protected 36 | 37 | def limited_cert? 38 | APP_CONFIG[:allow_limited_certs] && 39 | (!APP_CONFIG[:allow_unlimited_certs] || config_hash[:eip_rate_limit]) 40 | end 41 | 42 | def config_hash 43 | @config_hash || APP_CONFIG[:service_levels][@id].with_indifferent_access 44 | end 45 | 46 | end 47 | -------------------------------------------------------------------------------- /app/models/session.rb: -------------------------------------------------------------------------------- 1 | require 'login_format_validation' 2 | 3 | class Session < SRP::Session 4 | include ActiveModel::Validations 5 | include LoginFormatValidation 6 | 7 | attr_accessor :login 8 | 9 | validates :login, :presence => true 10 | 11 | def initialize(user = nil, aa = nil) 12 | super(user, aa) if user 13 | end 14 | 15 | def persisted? 16 | false 17 | end 18 | 19 | def new_record? 20 | true 21 | end 22 | 23 | def to_model 24 | self 25 | end 26 | 27 | def to_key 28 | [object_id] 29 | end 30 | 31 | def to_param 32 | nil 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /app/views/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leapcode/leap_web/fc00f46796da8a6fed381f9879e7af28f87312b4/app/views/.gitkeep -------------------------------------------------------------------------------- /app/views/api/sessions/new.json.erb: -------------------------------------------------------------------------------- 1 | { 2 | "errors": <%= raw @errors.to_json %> 3 | } 4 | -------------------------------------------------------------------------------- /app/views/common/_action.html.haml: -------------------------------------------------------------------------------- 1 | %li.action{class: action.class} 2 | =link_to action.label, action.url, action.html_options 3 | -------------------------------------------------------------------------------- /app/views/common/_action_buttons.html.haml: -------------------------------------------------------------------------------- 1 | .home-buttons 2 | .row.second 3 | .login.col-md-4 4 | %span.link= btn icon('ok-sign') + t(:login), login_path 5 | %span.info= t(:login_info, default: "") 6 | - if APP_CONFIG[:allow_registration] 7 | .signup.col-md-4 8 | %span.link= btn icon('user') + t(:signup), signup_path 9 | %span.info= t(:signup_info, default: "") 10 | - else 11 | .signup.col-md-4 12 | .help.col-md-4 13 | %span.link= btn icon('question-sign') + t(:get_help), new_ticket_path 14 | %span.info= t(:support_info, default: "") 15 | -------------------------------------------------------------------------------- /app/views/common/_download_button.html.haml: -------------------------------------------------------------------------------- 1 | .home-buttons 2 | .row.first 3 | .col-md-2 4 | .download.col-md-8 5 | = btn client_download_url, type: [:large, :primary] do 6 | = big_icon('download') 7 | = t(:download_bitmask) 8 | .col-md-2 9 | -------------------------------------------------------------------------------- /app/views/common/_home_page_buttons.html.haml: -------------------------------------------------------------------------------- 1 | = render 'common/download_button' 2 | - if local_assigns[:divider] 3 | .row 4 | .col-md-12 5 | = render local_assigns[:divider] 6 | = render 'common/action_buttons' 7 | -------------------------------------------------------------------------------- /app/views/common/_navigation_item.html.haml: -------------------------------------------------------------------------------- 1 | -# 2 | -# A very simple navigation link. It takes a symbol, uses it for the 3 | -# translation, path and determining if the link is active. 4 | -# 5 | -# For something more complex use link_to_navigation directly instead. 6 | -# 7 | - item = navigation_item.to_s 8 | = link_to_navigation ".#{item}", polymorphic_url(item), 9 | active: controller?(item) 10 | -------------------------------------------------------------------------------- /app/views/common/_search.html.haml: -------------------------------------------------------------------------------- 1 | = form_tag path, :method => :get, :class => "form-search" do 2 | .input-append 3 | = text_field_tag :query, params[:query], 4 | id: "#{id}-typeahead", 5 | class: "search-query", 6 | autocomplete: :off 7 | %button.btn{:type => :submit}= submit_label 8 | 9 | -------------------------------------------------------------------------------- /app/views/common/_table.html.haml: -------------------------------------------------------------------------------- 1 | -# 2 | -# A simple table with headers, content and a message if there is no 3 | -# content. 4 | -# You can use the table helper method to translate the headers and 5 | -# error message. 6 | -# 7 | %table.table.table-striped.table-bordered 8 | %thead 9 | %tr 10 | - headers.each do |header| 11 | %th= header 12 | %tbody 13 | - if content.present? 14 | = render content.all 15 | - else 16 | %tr 17 | %td{:colspan=>headers.count}= none 18 | 19 | -------------------------------------------------------------------------------- /app/views/emails/_email.html.haml: -------------------------------------------------------------------------------- 1 | = wrapped(email, local_assigns) do 2 | = email 3 | - if local_assigns[:with].try(:include?, :delete) 4 | = link_to(user_email_alias_path(@user, email), :method => :delete) do 5 | =icon :remove 6 | 7 | -------------------------------------------------------------------------------- /app/views/errors/not_found.html.haml: -------------------------------------------------------------------------------- 1 | .hero-unit 2 | %h1=t 'errors.title.page_not_found' 3 | %h2=t 'errors.subtitle.page_not_found', default: '' 4 | %p.lead=t 'errors.text.page_not_found', default: '' 5 | %a.btn.btn-primary.btn-large{href:'/'} 6 | =icon :home 7 | =t :home 8 | -------------------------------------------------------------------------------- /app/views/errors/not_found.json: -------------------------------------------------------------------------------- 1 | { 2 | "error": "not_found", 3 | "message": "Not Found" 4 | } -------------------------------------------------------------------------------- /app/views/errors/server_error.html.haml: -------------------------------------------------------------------------------- 1 | .hero-unit 2 | %h1=t 'errors.title.server_error' 3 | %h2=t 'errors.subtitle.server_error', default: '' 4 | %p.lead=t 'errors.text.server_error', default: '' 5 | %a.btn.btn-primary.btn-large{href:'/'} 6 | =icon :home 7 | =t :home 8 | -------------------------------------------------------------------------------- /app/views/errors/server_error.json: -------------------------------------------------------------------------------- 1 | { 2 | "error": "server failed", 3 | "message": "Server Error" 4 | } 5 | -------------------------------------------------------------------------------- /app/views/home/_content.html.haml: -------------------------------------------------------------------------------- 1 | - if twitter_enabled == true 2 | .col-md-8 3 | .row 4 | %h1= t(:welcome, :provider => APP_CONFIG[:domain]) 5 | .p=t(:welcome_message_html) 6 | 7 | .row 8 | = home_page_buttons 9 | .row 10 | = render 'home/provider_message' 11 | 12 | .col-md-1 13 | 14 | .col-md-3 15 | .row 16 | = render 'twitter/index' 17 | - else 18 | .row 19 | %h1= t(:welcome, :provider => APP_CONFIG[:domain]) 20 | .p=t(:welcome_message_html) 21 | 22 | .row 23 | = home_page_buttons 24 | .row 25 | = render 'home/provider_message' 26 | 27 | - if Rails.env == 'development' 28 | .row 29 | %hr 30 | %p 31 | = link_to "make donation", new_payment_path if APP_CONFIG[:payment].present? 32 | -------------------------------------------------------------------------------- /app/views/home/_masthead.html.haml: -------------------------------------------------------------------------------- 1 | -# masthead for the home page. 2 | #masthead 3 | .title 4 | %span.sitename 5 | %a{:href => home_path}= APP_CONFIG[:domain] 6 | -------------------------------------------------------------------------------- /app/views/home/_provider_message.html.haml: -------------------------------------------------------------------------------- 1 | -# please overwrite me in your customization files at 2 | -# config/customization/views/home/_provider_message.html.haml 3 | -------------------------------------------------------------------------------- /app/views/home/index.html.haml: -------------------------------------------------------------------------------- 1 | #wrap 2 | = render 'home/masthead' 3 | #main 4 | .container-fluid 5 | = render 'home/content' 6 | #push 7 | -# #push is used for sticky footer in bootstrap 2. remove when upgrading to bootstrap 3 8 | #footer 9 | = render 'layouts/footer' -------------------------------------------------------------------------------- /app/views/identities/_identity.html.haml: -------------------------------------------------------------------------------- 1 | %tr[identity]{class: identity.status} 2 | %td 3 | %span.label= t(".#{identity.status}", cascading: true) 4 | %td= identity.login 5 | %td= identity.destination 6 | %td 7 | %ul.list-inline= render actions(identity) 8 | -------------------------------------------------------------------------------- /app/views/identities/index.html.haml: -------------------------------------------------------------------------------- 1 | -@show_navigation = false 2 | 3 | = search :identities 4 | = table @identities, %w(type username destination actions) 5 | -# = paginate @identities 6 | -------------------------------------------------------------------------------- /app/views/invite_codes/_invite_code.html.haml: -------------------------------------------------------------------------------- 1 | %tr 2 | %td 3 | = simple_date(invite_code.updated_at) 4 | %td 5 | = simple_date(invite_code.created_at) 6 | %td 7 | %input.invite-code{:value => invite_code.invite_code} 8 | %td 9 | = "#{invite_code.invite_count}/#{invite_code.max_uses}" 10 | %td 11 | = btn t(".destroy", cascade: true), invite_code_path(invite_code), :method => 'delete' 12 | -------------------------------------------------------------------------------- /app/views/invite_codes/index.html.haml: -------------------------------------------------------------------------------- 1 | - @show_navigation = false 2 | 3 | = form_for @invite, :url => { :action => "create" } do |f| 4 | %table 5 | %tr 6 | %td= t "code" 7 | %td= t "uses" 8 | %td 9 | %tr 10 | %td= f.text_field :invite_code, style: 'width: 10em' 11 | %td= f.text_field :max_uses, style: 'width: 4em' 12 | %td= f.submit t("helpers.submit.invites.create"), style: 'margin-bottom: 10px', class: 'btn btn-default' 13 | 14 | = table @invites, %w(updated created code uses actions) 15 | 16 | -# select the text of the invite code when you click on it: 17 | :javascript 18 | $("input.invite-code").focus(function(){ 19 | this.select(); 20 | }); 21 | -------------------------------------------------------------------------------- /app/views/kaminari/_first_page.html.haml: -------------------------------------------------------------------------------- 1 | -# Link to the "First" page 2 | -# available local variables 3 | -# url: url to the first page 4 | -# current_page: a page object for the currently displayed page 5 | -# num_pages: total number of pages 6 | -# per_page: number of items to fetch per page 7 | -# remote: data-remote 8 | %li 9 | = link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, :remote => remote 10 | -------------------------------------------------------------------------------- /app/views/kaminari/_gap.html.haml: -------------------------------------------------------------------------------- 1 | -# Non-link tag that stands for skipped pages... 2 | -# available local variables 3 | -# current_page: a page object for the currently displayed page 4 | -# num_pages: total number of pages 5 | -# per_page: number of items to fetch per page 6 | -# remote: data-remote 7 | %li.disabled 8 | = raw(t 'views.pagination.truncate') 9 | -------------------------------------------------------------------------------- /app/views/kaminari/_last_page.html.haml: -------------------------------------------------------------------------------- 1 | -# Link to the "Last" page 2 | -# available local variables 3 | -# url: url to the last page 4 | -# current_page: a page object for the currently displayed page 5 | -# num_pages: total number of pages 6 | -# per_page: number of items to fetch per page 7 | -# remote: data-remote 8 | %li 9 | = link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {:remote => remote} 10 | -------------------------------------------------------------------------------- /app/views/kaminari/_next_page.html.haml: -------------------------------------------------------------------------------- 1 | -# Link to the "Next" page 2 | -# available local variables 3 | -# url: url to the next page 4 | -# current_page: a page object for the currently displayed page 5 | -# num_pages: total number of pages 6 | -# per_page: number of items to fetch per page 7 | -# remote: data-remote 8 | - if current_page.last? 9 | %li.disabled 10 | %span= raw(t 'views.pagination.next') 11 | - else 12 | %li= link_to(raw(t 'views.pagination.next'), url, :rel => 'next', :remote => remote) 13 | -------------------------------------------------------------------------------- /app/views/kaminari/_page.html.haml: -------------------------------------------------------------------------------- 1 | -# Link showing page number 2 | -# available local variables 3 | -# page: a page object for "this" page 4 | -# url: url to this page 5 | -# current_page: a page object for the currently displayed page 6 | -# num_pages: total number of pages 7 | -# per_page: number of items to fetch per page 8 | -# remote: data-remote 9 | 10 | - if page.current? 11 | %li.active 12 | %span= page 13 | - else 14 | %li= link_to(page, url, {:remote => remote, :rel => page.next? ? 'next' : page.prev? ? 'prev' : nil}) 15 | -------------------------------------------------------------------------------- /app/views/kaminari/_paginator.html.haml: -------------------------------------------------------------------------------- 1 | -# The container tag 2 | -# available local variables 3 | -# current_page: a page object for the currently displayed page 4 | -# num_pages: total number of pages 5 | -# per_page: number of items to fetch per page 6 | -# remote: data-remote 7 | -# paginator: the paginator that renders the pagination tags inside 8 | = paginator.render do 9 | .pagination 10 | %ul 11 | -#= first_page_tag unless current_page.first? 12 | = prev_page_tag #unless current_page.first? 13 | - each_page do |page| 14 | - if page.left_outer? || page.right_outer? || page.inside_window? 15 | = page_tag page 16 | - elsif !page.was_truncated? 17 | = gap_tag 18 | = next_page_tag #unless current_page.last? 19 | -#= last_page_tag unless current_page.last? 20 | -------------------------------------------------------------------------------- /app/views/kaminari/_prev_page.html.haml: -------------------------------------------------------------------------------- 1 | -# Link to the "Previous" page 2 | -# available local variables 3 | -# url: url to the previous page 4 | -# current_page: a page object for the currently displayed page 5 | -# num_pages: total number of pages 6 | -# per_page: number of items to fetch per page 7 | -# remote: data-remote 8 | - if current_page.first? 9 | %li.disabled 10 | %span= raw(t 'views.pagination.previous') 11 | - else 12 | %li= link_to(raw(t 'views.pagination.previous'), url, :rel => 'prev', :remote => remote) 13 | -------------------------------------------------------------------------------- /app/views/layouts/_admin_navigation_item.html.haml: -------------------------------------------------------------------------------- 1 | - item = admin_navigation_item.to_s 2 | %li{:class => ("active" if controller?(item))} 3 | = link_to t(".#{item}", cascade: true), path_for(item) 4 | -------------------------------------------------------------------------------- /app/views/layouts/_content.html.haml: -------------------------------------------------------------------------------- 1 | -# 2 | -# Partial for displaying the page content. This is the only place that content should be displayed (except for home layout) 3 | -# 4 | 5 | - if content_for?(:content) 6 | - content = yield(:content) 7 | - else 8 | - content = yield 9 | 10 | - if @show_navigation && @user 11 | .col-md-2 12 | = render 'layouts/navigation' 13 | .col-md-10 14 | = render 'layouts/messages' 15 | = content 16 | - else 17 | .col-md-12 18 | = render 'layouts/messages' 19 | = content 20 | -------------------------------------------------------------------------------- /app/views/layouts/_footer.html.haml: -------------------------------------------------------------------------------- 1 | - if CommonLanguages.available.size > 1 2 | .locales.row 3 | .wrap-text 4 | = locales_links 5 | - else 6 | .locales.row 7 | .links.row 8 | .wrap-text 9 | = link_to icon('home') + t(:home), home_path 10 | = link_to icon('eye-close') + t(:privacy_policy), privacy_policy_path 11 | = link_to icon('file') + t(:terms_of_service), terms_of_service_path 12 | - if lookup_context.exists?('pages/about') 13 | = link_to icon('info-sign') + t(:about), about_path 14 | - if lookup_context.exists?('pages/contact') 15 | = link_to icon('comment') + t(:contact), contact_path 16 | - if paid_service_level? 17 | = link_to icon('shopping-cart') + t(:pricing), pricing_path 18 | = link_to icon('barcode') + t(:Donations), new_payment_path if APP_CONFIG[:payment].present? 19 | -------------------------------------------------------------------------------- /app/views/layouts/_header.html.haml: -------------------------------------------------------------------------------- 1 | - if admin? 2 | %ul.nav.nav-pills.admin-area 3 | = render partial: 'common/navigation_item', 4 | collection: [:users, :identities, :invite_codes, :tickets] 5 | = link_to_navigation :logout, logout_path, :method => :delete 6 | - if @user && @show_navigation 7 | .lead 8 | = @user.email_address 9 | -------------------------------------------------------------------------------- /app/views/layouts/_masthead.html.haml: -------------------------------------------------------------------------------- 1 | #masthead 2 | .title 3 | %span.sitename 4 | %a{:href => home_path}= APP_CONFIG[:domain] 5 | -------------------------------------------------------------------------------- /app/views/layouts/_messages.html.haml: -------------------------------------------------------------------------------- 1 | #messages 2 | - flash.each do |name, msg| 3 | - if msg.is_a?(String) 4 | %div{:class => "alert alert-#{name == :notice ? "success" : name}"} 5 | %a.close{"data-dismiss" => "alert"} × 6 | = content_tag :div, format_flash(msg), :id => "flash_#{name}" 7 | -------------------------------------------------------------------------------- /app/views/layouts/_navigation.html.haml: -------------------------------------------------------------------------------- 1 | %ul.nav.sidenav 2 | = link_to_navigation :overview, @user, 3 | active: (controller?(:users) && action?(:show)) 4 | = link_to_navigation :account_settings, edit_user_path(@user), 5 | active: (controller?(:users) && !action?(:show)) 6 | - # will want link for identity settings 7 | = link_to_navigation ".tickets", auto_tickets_path, 8 | active: controller?(:tickets) 9 | - if APP_CONFIG[:billing] 10 | = link_to_navigation :donations, new_payment_path, 11 | active: (controller?(:donations) and action?(:new)) 12 | = link_to_navigation :subscriptions, billing_top_link(@braintree_customer_id), 13 | active: controller?(:subscriptions) 14 | - unless admin? 15 | = link_to_navigation :logout, logout_path, method: :delete 16 | -------------------------------------------------------------------------------- /app/views/layouts/application.html.haml: -------------------------------------------------------------------------------- 1 | - @show_navigation = true if @show_navigation.nil? && logged_in? 2 | !!! 3 | %html 4 | %head 5 | %meta{:content => "width=device-width, initial-scale=1.0", :name => "viewport"} 6 | %title= html_title 7 | %meta{:content => content_for?(:description) ? yield(:description) : "Leap Web", :name => "description"} 8 | = stylesheet_link_tag "application", :media => "all" 9 | = javascript_include_tag "application" 10 | = csrf_meta_tags 11 | = yield(:head) 12 | %body 13 | #wrap 14 | = render 'layouts/masthead' 15 | #main 16 | .container-fluid 17 | - if @show_navigation && !admin? 18 | .row 19 | %h1= t(:user_control_panel) 20 | - if logged_in? 21 | .row 22 | .col-md-12 23 | = render 'layouts/header' 24 | .row 25 | = render 'layouts/content' 26 | #push 27 | -# #push is used for sticky footer in bootstrap 2. remove when upgrading to bootstrap 3 28 | #footer 29 | = render 'layouts/footer' 30 | -------------------------------------------------------------------------------- /app/views/layouts/home.html.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %head 4 | %meta{:content => "width=device-width, initial-scale=1.0", :name => "viewport"} 5 | %title= html_title 6 | %meta{:content => content_for?(:description) ? yield(:description) : "LEAP Web", :name => "description"} 7 | = stylesheet_link_tag "application", :media => "all" 8 | = javascript_include_tag "application" 9 | = csrf_meta_tags 10 | = yield(:head) 11 | %body.home 12 | = yield -------------------------------------------------------------------------------- /app/views/pages/bye.html.haml: -------------------------------------------------------------------------------- 1 | %br/ 2 | .hero-unit 3 | %h2= t :bye 4 | = t :bye_message 5 | 6 | = render 'common/home_page_buttons' -------------------------------------------------------------------------------- /app/views/pages/pricing.html.haml: -------------------------------------------------------------------------------- 1 | %h1= t(:pricing) 2 | %p= btn icon('user') + t(:signup), signup_path 3 | 4 | - levels = APP_CONFIG[:service_levels] 5 | - if levels 6 | %table.table.table-striped.table-bordered 7 | %tr 8 | %th= t :plan 9 | %th= t :description 10 | %th= t :monthly_cost 11 | - levels.each do |id, level| 12 | %tr 13 | %td= level[:name] 14 | %td= level[:description] 15 | %td 16 | - if level[:rate].nil? || level[:rate] == 0 17 | = t(:free) 18 | - else 19 | = level[:rate].collect{|currency, price| "#{currency} #{price}"}.join(', ') 20 | - else 21 | No service levels are configured. 22 | -------------------------------------------------------------------------------- /app/views/sessions/_warnings.html.haml: -------------------------------------------------------------------------------- 1 | %noscript 2 | %div.alert.alert-error=t :js_required_html 3 | #cookie_warning.alert.alert-error{:style => "display:none"} 4 | =t :cookie_disabled_warning 5 | :javascript 6 | document.cookie = "testing=cookies_enabled; path=/"; 7 | if(document.cookie.indexOf("testing=cookies_enabled") < 0) 8 | { 9 | document.getElementById('cookie_warning').style.display = 'block'; 10 | } else { 11 | document.getElementById('cookie_warning').style.display = 'none'; 12 | } 13 | -------------------------------------------------------------------------------- /app/views/sessions/new.html.haml: -------------------------------------------------------------------------------- 1 | .col-md-1 2 | .col-md-9 3 | %h2=t :login 4 | .lead=t :login_info 5 | = render 'warnings' 6 | = simple_form_for [:api, @session], validate: true, html: { id: :new_session, class: 'form-horizontal hidden js-show', style: "display:none;" } do |f| 7 | = f.input :login, :required => false, :label => t(:username), :input_html => { :id => :srp_username } 8 | = f.input :password, :required => false, :input_html => { :id => :srp_password } 9 | = f.button :wrapped, value: t(:login), cancel: home_path 10 | -------------------------------------------------------------------------------- /app/views/sessions/new.json.erb: -------------------------------------------------------------------------------- 1 | { 2 | "errors": <%= raw @errors.to_json %> 3 | } 4 | -------------------------------------------------------------------------------- /app/views/tabs/_nav.html.haml: -------------------------------------------------------------------------------- 1 | %li{:class => (:active if nav == @anchor)} 2 | %a{:href => "##{nav}", 'data-toggle' => 'tab'}= t("tabs.#{nav}") 3 | -------------------------------------------------------------------------------- /app/views/tabs/_tab.html.haml: -------------------------------------------------------------------------------- 1 | .tab-pane{:id => tab, :class => (:active if tab == @anchor)} 2 | = content_for tab 3 | -------------------------------------------------------------------------------- /app/views/tabs/_tabs.html.haml: -------------------------------------------------------------------------------- 1 | %ul.nav.nav-tabs 2 | = render :partial => '/tabs/nav', :collection => tabs 3 | .tab-content 4 | = render :partial => '/tabs/tab', :collection => tabs 5 | -------------------------------------------------------------------------------- /app/views/users/_change_pgp_key.html.haml: -------------------------------------------------------------------------------- 1 | -# 2 | -# CHANGE PGP KEY 3 | -# 4 | -# this will be replaced by a identities controller/view at some point 5 | -# 6 | 7 | - form_options = {:html => {:class => user_form_class('form-horizontal'), :id => 'update_pgp_key', :data => {token: session[:token]}}, :validate => true} 8 | = simple_form_for [:api, @user], form_options do |f| 9 | %legend= t(:advanced_options) 10 | = f.input :public_key, :as => :text, :hint => t(:use_ascii_key), :input_html => {:class => "full-width", :rows => 4} 11 | .form-group 12 | .controls 13 | = f.submit t(:save), :class => 'btn', :data => {"loading-text" => "Saving..."} 14 | -------------------------------------------------------------------------------- /app/views/users/_change_service_level.html.haml: -------------------------------------------------------------------------------- 1 | :ruby 2 | # DISABLED! this form points to a route that does not exist. 3 | # It's a draft for implementing service levels. 4 | # TODO: probably won't want here, but here for now. 5 | # We will need way to ensure payment for a non-free plan. 6 | # 7 | # SERVICE LEVEL 8 | # 9 | # 10 | - if APP_CONFIG[:service_levels] && false 11 | - form_options = {:html => {:class => user_form_class('form-horizontal'), :id => 'update_service_level', :data => {token: session[:token]}}, :validate => true} 12 | = simple_form_for @user, form_options do |f| 13 | %legend= t(:service_level) 14 | - if @user != current_user 15 | = t(:desired_service_level) 16 | = f.select :desired_service_level_code, ServiceLevel.select_options, :selected => @user.desired_service_level.id 17 | - if @user != current_user 18 | %p 19 | = t(:effective_service_level) 20 | = f.select :effective_service_level_code, ServiceLevel.select_options, :selected => @user.effective_service_level.id 21 | .form-group 22 | .controls 23 | = f.submit t(:save), :class => 'btn', :data => {"loading-text" => "Saving..."} 24 | -------------------------------------------------------------------------------- /app/views/users/_contact_email.html.haml: -------------------------------------------------------------------------------- 1 | %legend= t(:contact_email) 2 | = simple_form_for @user, {:validate => true} do |f| 3 | %p= t(:contact_email_info) 4 | = f.input :contact_email, :label => false 5 | -# %p= t(:public_key) 6 | -# = f.text_area :contact_email_key, {:class => "full-width", :rows => 4} 7 | .form-group 8 | .controls 9 | = f.submit t(:save), :class => 'btn', :data => {"loading-text" => "Saving..."} -------------------------------------------------------------------------------- /app/views/users/_destroy_account.html.haml: -------------------------------------------------------------------------------- 1 | -# 2 | -# DESTROY ACCOUNT 3 | -# 4 | 5 | %legend 6 | = destroy_account_text 7 | %p= t(:destroy_account_info) 8 | = form_tag user_path(@user), method: :delete do 9 | .checkbox 10 | = label_tag do 11 | = check_box_tag 'block_username', 1, true 12 | = t(:keep_username_blocked) 13 | = button_tag class: "btn btn-danger" do 14 | = icon(:remove) 15 | = @user == current_user ? destroy_account_text : t(:destroy) 16 | 17 | - if @user != current_user and @user.enabled? 18 | %legend 19 | = t(:deactivate_account, :username => @user.login) 20 | %p= t(:deactivate_description) 21 | = btn deactivate_user_path(@user), :method => :post, :type => "warning" do 22 | = icon :pause 23 | = t(:deactivate) 24 | - elsif @user != current_user and !@user.enabled? 25 | %legend 26 | = t(:enable_account, :username => @user.login) 27 | %p= t(:enable_description) 28 | = btn enable_user_path(@user), :method => :post, :type => "warning" do 29 | = icon :ok 30 | = t(:enable) 31 | -------------------------------------------------------------------------------- /app/views/users/_edit.html.haml: -------------------------------------------------------------------------------- 1 | -# 2 | -# edit user form, used by both show and edit actions. 3 | -# 4 | -# We render a bunch of forms here. Which we use depends upon config settings 5 | -# user_actions and admin_actions. They both include an array of actions 6 | -# allowed to users and admins. 7 | -# Possible forms are: 8 | -# 'change_password' 9 | -# 'change_pgp_key' 10 | -# 'change_service_level' 11 | -# 'contact_email' 12 | -# 'destroy_account' 13 | - actions = APP_CONFIG[admin? ? :admin_actions : :user_actions] || [] 14 | - actions.each do |action| 15 | = render action 16 | -------------------------------------------------------------------------------- /app/views/users/_overview.html.haml: -------------------------------------------------------------------------------- 1 | .overview 2 | 3 | %h2.first= t(".welcome", username: @user.login, cascade: true) 4 | 5 | - if admin? 6 | %p 7 | = t(:created) 8 | = @user.created_at 9 | %br 10 | = t(:updated) 11 | = @user.updated_at 12 | %br 13 | = t(:enabled) 14 | = @user.enabled? 15 | 16 | %p= t(:overview_intro, default: "") 17 | 18 | %ul.list-unstyled 19 | %li= icon('user') + link_to(t(".account"), edit_user_path(@user)) 20 | - # %li= icon('envelope') + link_to(t(:overview_email), {insert path for user identities, presuambly} 21 | %li= icon('question-sign') + link_to(t(".tickets"), user_tickets_path(@user)) 22 | - if APP_CONFIG[:billing] 23 | %li= icon('shopping-cart') + link_to(t(".billing"), billing_top_link(@user)) 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/views/users/edit.html.haml: -------------------------------------------------------------------------------- 1 | = render 'edit' 2 | -------------------------------------------------------------------------------- /app/views/users/index.html.haml: -------------------------------------------------------------------------------- 1 | - @show_navigation = false 2 | 3 | = search :users 4 | = table @users, %w(username created updated actions) 5 | -------------------------------------------------------------------------------- /app/views/users/show.html.haml: -------------------------------------------------------------------------------- 1 | = render 'overview' 2 | .container-fluid 3 | .row 4 | %h4 To use bitmask services: 5 | = btn client_download_url, type: "primary", class: "download" do 6 | = icon :download 7 | = t(:download_bitmask) 8 | -------------------------------------------------------------------------------- /app/views/webfinger/host_meta.xml.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= @host_meta.subject %> 5 | 6 | <%- @host_meta.links.each do |rel, link| %> 7 | 10 | <%- end %> 11 | 12 | -------------------------------------------------------------------------------- /app/views/webfinger/search.xml.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%= @presenter.subject %> 4 | <%- @presenter.links.each do |rel, link| %> 5 | type=<%=link[:type]%> href="<%= link[:href] %>"/> 6 | <% end %> 7 | 8 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path('../../config/application', __FILE__) 3 | require_relative '../config/boot' 4 | require 'rails/commands' 5 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative '../config/boot' 3 | require 'rake' 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | 4 | # path to your application root. 5 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 6 | 7 | Dir.chdir APP_ROOT do 8 | # This script is a starting point to setup your application. 9 | # Add necessary setup steps to this file: 10 | 11 | puts "== Installing dependencies ==" 12 | system "gem install bundler --conservative" 13 | system "bundle check || bundle install" 14 | 15 | # puts "\n== Copying sample files ==" 16 | # unless File.exist?("config/database.yml") 17 | # system "cp config/database.yml.sample config/database.yml" 18 | # end 19 | 20 | puts "\n== Preparing database ==" 21 | system "bin/rake db:setup" 22 | 23 | puts "\n== Removing old logs and tempfiles ==" 24 | system "rm -f log/*" 25 | system "rm -rf tmp/cache" 26 | 27 | puts "\n== Restarting application server ==" 28 | system "touch tmp/restart.txt" 29 | end 30 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | 5 | require 'http_accept_language' 6 | use HttpAcceptLanguage::Middleware 7 | 8 | run LeapWeb::Application 9 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 2 | 3 | require 'bundler/setup' # Set up gems listed in the Gemfile. 4 | -------------------------------------------------------------------------------- /config/ci/gitlab/couchdb.yml: -------------------------------------------------------------------------------- 1 | test: 2 | auto_update_design_doc: false 3 | host: "couchdb" 4 | -------------------------------------------------------------------------------- /config/ci/travis/README: -------------------------------------------------------------------------------- 1 | These files are used for Travis tests to test admin and user permissions: 2 | 3 | couchdb.yml.admin: 4 | 5 | when activated, leap_web has admin permissions (e.g. ability to create 6 | databases, upload design docs). 7 | 8 | couchdb.yml.user: 9 | 10 | when activited, leap_web has normal permissions (e.g. can modify all the 11 | records). 12 | 13 | The term 'user' here is misleading. It is really two different types of admin 14 | permissions. 15 | 16 | Rails or rake must be run with 'test' environment for these configs to be 17 | used. 18 | -------------------------------------------------------------------------------- /config/ci/travis/couchdb.admin.yml: -------------------------------------------------------------------------------- 1 | test: 2 | auto_update_design_doc: false 3 | username: "anna" 4 | password: "secret" 5 | 6 | -------------------------------------------------------------------------------- /config/ci/travis/couchdb.yml: -------------------------------------------------------------------------------- 1 | test: 2 | auto_update_design_doc: false 3 | username: "me" 4 | password: "pwd" 5 | -------------------------------------------------------------------------------- /config/ci/travis/setup_couch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | HOST="http://localhost:5984" 4 | echo "couch version :" 5 | curl -X GET $HOST 6 | echo "creating user :" 7 | curl -HContent-Type:application/json -XPUT $HOST/_users/org.couchdb.user:me --data-binary '{"_id": "org.couchdb.user:me","name": "me","roles": [],"type": "user","password": "pwd"}' 8 | echo "creating databases :" 9 | curl -X PUT $HOST/sessions 10 | curl -X PUT $HOST/users 11 | curl -X PUT $HOST/tickets 12 | echo "restricting database access :" 13 | curl -X PUT $HOST/sessions/_security -Hcontent-type:application/json --data-binary '{"admins":{"names":[],"roles":[]},"members":{"names":["me"],"roles":[]}}' 14 | curl -X PUT $HOST/users/_security -Hcontent-type:application/json --data-binary '{"admins":{"names":[],"roles":[]},"members":{"names":["me"],"roles":[]}}' 15 | curl -X PUT $HOST/tickets/_security -Hcontent-type:application/json --data-binary '{"admins":{"names":[],"roles":[]},"members":{"names":["me"],"roles":[]}}' 16 | echo "adding admin :" 17 | curl -X PUT $HOST/_config/admins/anna -d '"secret"' 18 | -------------------------------------------------------------------------------- /config/couchdb.admin.example.yml: -------------------------------------------------------------------------------- 1 | development: 2 | auto_update_design_doc: false 3 | username: "anna" 4 | password: "secret" 5 | prefix: "" 6 | -------------------------------------------------------------------------------- /config/couchdb.example.yml: -------------------------------------------------------------------------------- 1 | development: 2 | auto_update_design_doc: false 3 | username: "me" 4 | password: "pwd" 5 | prefix: "" 6 | -------------------------------------------------------------------------------- /config/cucumber.yml: -------------------------------------------------------------------------------- 1 | <% 2 | rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : "" 3 | rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}" 4 | std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags ~@wip" 5 | %> 6 | default: <%= std_opts %> features 7 | wip: --tags @wip:3 --wip features 8 | rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip 9 | -------------------------------------------------------------------------------- /config/customization.example/locales/en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | login_info: Authenticate to change your "Prehistoric Computer" settings. -------------------------------------------------------------------------------- /config/customization.example/locales/es.yml: -------------------------------------------------------------------------------- 1 | es: 2 | login_info: Autenticar a cambiar la configuración de "Computer Prehistoria." -------------------------------------------------------------------------------- /config/customization.example/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leapcode/leap_web/fc00f46796da8a6fed381f9879e7af28f87312b4/config/customization.example/public/favicon.ico -------------------------------------------------------------------------------- /config/customization.example/public/img/masthead.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leapcode/leap_web/fc00f46796da8a6fed381f9879e7af28f87312b4/config/customization.example/public/img/masthead.png -------------------------------------------------------------------------------- /config/customization.example/stylesheets/tail.scss: -------------------------------------------------------------------------------- 1 | $custom-color: #66bbaa; 2 | 3 | a { 4 | color: $custom-color; 5 | } 6 | 7 | // 8 | // MASTHEAD 9 | // 10 | 11 | #masthead { 12 | background-color: $custom-color; 13 | border-bottom: none; 14 | 15 | // make the masthead clickable by replacing the 16 | // site name link with the masthead image: 17 | .title { 18 | padding: 0px; 19 | .sitename a { 20 | display: block; 21 | background: url(/img/masthead.png) 0 0 no-repeat; 22 | font-size: 0px; 23 | height: 100px; 24 | background-size: auto 100px; 25 | } 26 | } 27 | } 28 | 29 | // make the home page masthead slightly larger 30 | body.home #masthead { 31 | .sitename a { 32 | height: 150px; 33 | background-size: auto 150px; 34 | } 35 | } 36 | 37 | // 38 | // FOOTER 39 | // 40 | 41 | #footer .links { 42 | background-color: $custom-color; 43 | } -------------------------------------------------------------------------------- /config/customization.example/views/pages/privacy-policy.en.md: -------------------------------------------------------------------------------- 1 | # Custom Privacy Policy 2 | 3 | This is our privacy policy. -------------------------------------------------------------------------------- /config/customization.example/views/pages/privacy-policy.es.md: -------------------------------------------------------------------------------- 1 | # Custom Política de Privacidad 2 | 3 | Esta es nuestra política de privacidad. -------------------------------------------------------------------------------- /config/customization/README.md: -------------------------------------------------------------------------------- 1 | Customizing LEAP Webapp 2 | ============================================ 3 | 4 | By default, this directory is empty. Any file you place here will override the default files for the application. 5 | 6 | For example: 7 | 8 | stylesheets/ -- overrides files Rails.root/app/assets/stylesheets 9 | tail.scss -- included before all others 10 | head.scss -- included after all others 11 | 12 | public/ -- overrides files in Rails.root/public 13 | favicon.ico -- custom favicon 14 | img/ -- customary directory to put images in 15 | 16 | views/ -- overrides files Rails.root/app/views 17 | home/ 18 | index.html.haml -- this file is what shows up on the home page 19 | 20 | locales/ -- overrides files in Rails.root/config/locales 21 | en.yml -- overrides for English 22 | de.yml -- overrides for German 23 | and so on... 24 | 25 | For most changes, the web application must be restarted after any changes are made to the customization directory. 26 | 27 | Sometimes a `rake tmp:clear` and a rails restart is required to pick up a new stylesheet. 28 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the rails application. 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /config/initializers/add_controller_methods.rb: -------------------------------------------------------------------------------- 1 | ActiveSupport.on_load(:application_controller) do 2 | include ControllerExtension::Authentication 3 | include ControllerExtension::TokenAuthentication 4 | include ControllerExtension::Flash 5 | include ControllerExtension::JsonResponses 6 | include ControllerExtension::Errors 7 | end 8 | -------------------------------------------------------------------------------- /config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | Rails.application.config.assets.precompile += %w( Avatar_Pic.png ) 2 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /config/initializers/braintree.rb: -------------------------------------------------------------------------------- 1 | if defined? Braintree 2 | 3 | # 4 | # set logger 5 | # 6 | if APP_CONFIG[:logfile].blank? 7 | require 'syslog/logger' 8 | Braintree::Configuration.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new('webapp')) 9 | else 10 | Braintree::Configuration.logger = Logger.new('log/braintree.log') 11 | end 12 | 13 | # 14 | # You can set these per environment in config/config.yml: 15 | # 16 | # Environment must be one of: :development, :qa, :sandbox, :production 17 | # 18 | if billing = APP_CONFIG[:billing] 19 | if braintree = billing[:braintree] 20 | Braintree::Configuration.environment = braintree[:environment].downcase.to_sym 21 | Braintree::Configuration.merchant_id = braintree[:merchant_id] 22 | Braintree::Configuration.public_key = braintree[:public_key] 23 | Braintree::Configuration.private_key = braintree[:private_key] 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /config/initializers/client_side_validations.rb: -------------------------------------------------------------------------------- 1 | # ClientSideValidations Initializer 2 | 3 | # Disabled validators. The uniqueness validator is disabled by default for security issues. Enable it on your own responsibility! 4 | 5 | ClientSideValidations::Config.disabled_validators = [:uniqueness, :confirmation] 6 | 7 | # Uncomment to validate number format with current I18n locale 8 | # ClientSideValidations::Config.number_format_with_locale = true 9 | 10 | # Uncomment the following block if you want each input field to have the validation messages attached. 11 | # 12 | # Note: client_side_validation requires the error to be encapsulated within 13 | # 14 | 15 | ActionView::Base.field_error_proc = Proc.new do |html_tag, instance| 16 | unless html_tag =~ /^