├── .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('
');
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 =~ /^