Showing preview only (563K chars total). Download the full file or copy to clipboard to get everything.
Repository: gate-sso/gate
Branch: master
Commit: 958d5b920b07
Files: 370
Total size: 479.5 KB
Directory structure:
gitextract_ouflf_22/
├── .deepsource.toml
├── .dockerignore
├── .gitignore
├── .rspec
├── .rubocop.yml
├── .ruby-version
├── .travis.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Dockerfile
├── Gemfile
├── LICENSE
├── README.md
├── Rakefile
├── VERSION
├── api_blueprint/
│ ├── bin/
│ │ └── dredd_server.sh
│ ├── group.apib
│ ├── hooks/
│ │ └── dredd_hooks.rb
│ ├── user.apib
│ └── vpns.apib
├── app/
│ ├── assets/
│ │ ├── config/
│ │ │ └── manifest.js
│ │ ├── images/
│ │ │ └── .keep
│ │ ├── javascripts/
│ │ │ ├── admin.coffee
│ │ │ ├── api_resources.coffee
│ │ │ ├── application.js
│ │ │ ├── bootstrap.js.coffee
│ │ │ ├── group.coffee
│ │ │ ├── groups.coffee
│ │ │ ├── home.coffee
│ │ │ ├── host_access_groups.coffee
│ │ │ ├── host_machine_groups.coffee
│ │ │ ├── host_machines.coffee
│ │ │ ├── nss.coffee
│ │ │ ├── omniauth_callbacks.coffee
│ │ │ ├── profile.coffee
│ │ │ ├── users.coffee
│ │ │ ├── utilities.coffee
│ │ │ └── viewport.js
│ │ └── stylesheets/
│ │ ├── application.scss
│ │ ├── bootstrap-social.scss
│ │ ├── general.css
│ │ ├── home.scss.erb
│ │ ├── profile.css
│ │ └── scaffolds.scss
│ ├── clients/
│ │ └── data_dog_client.rb
│ ├── controllers/
│ │ ├── admin_controller.rb
│ │ ├── api/
│ │ │ └── v1/
│ │ │ ├── base_controller.rb
│ │ │ ├── endpoints_controller.rb
│ │ │ ├── groups_controller.rb
│ │ │ ├── users_controller.rb
│ │ │ └── vpns_controller.rb
│ │ ├── api_resources_controller.rb
│ │ ├── application_controller.rb
│ │ ├── concerns/
│ │ │ └── .keep
│ │ ├── groups_controller.rb
│ │ ├── home_controller.rb
│ │ ├── host_controller.rb
│ │ ├── host_machine_groups_controller.rb
│ │ ├── host_machines_controller.rb
│ │ ├── nss_controller.rb
│ │ ├── organisations_controller.rb
│ │ ├── pings_controller.rb
│ │ ├── profile_controller.rb
│ │ ├── saml_idp_controller.rb
│ │ ├── users/
│ │ │ ├── auth_controller.rb
│ │ │ └── omniauth_callbacks_controller.rb
│ │ ├── users_controller.rb
│ │ ├── vpn_domain_name_servers_controller.rb
│ │ └── vpns_controller.rb
│ ├── helpers/
│ │ ├── admin_helper.rb
│ │ ├── api_resources_helper.rb
│ │ ├── application_helper.rb
│ │ ├── group_helper.rb
│ │ ├── groups_helper.rb
│ │ ├── home_helper.rb
│ │ ├── host_access_groups_helper.rb
│ │ ├── host_machine_groups_helper.rb
│ │ ├── host_machines_helper.rb
│ │ ├── nss_helper.rb
│ │ ├── omniauth_callbacks_helper.rb
│ │ ├── profile_helper.rb
│ │ └── users_helper.rb
│ ├── lib/
│ │ ├── datadog.rb
│ │ └── saml_app.rb
│ ├── mailers/
│ │ └── .keep
│ ├── models/
│ │ ├── .keep
│ │ ├── access_token.rb
│ │ ├── api_resource.rb
│ │ ├── application_record.rb
│ │ ├── concerns/
│ │ │ ├── .keep
│ │ │ └── ms_chap_auth.rb
│ │ ├── endpoint.rb
│ │ ├── group.rb
│ │ ├── group_admin.rb
│ │ ├── group_association.rb
│ │ ├── group_endpoint.rb
│ │ ├── host.rb
│ │ ├── host_access_group.rb
│ │ ├── host_machine.rb
│ │ ├── ip_address.rb
│ │ ├── organisation.rb
│ │ ├── saml_app_config.rb
│ │ ├── user.rb
│ │ ├── vpn.rb
│ │ ├── vpn_domain_name_server.rb
│ │ ├── vpn_group_association.rb
│ │ ├── vpn_group_user_association.rb
│ │ ├── vpn_search_domain.rb
│ │ └── vpn_supplemental_match_domain.rb
│ ├── validators/
│ │ └── email_validator.rb
│ └── views/
│ ├── admin/
│ │ └── index.html.slim
│ ├── api/
│ │ └── v1/
│ │ └── users/
│ │ └── show.json.jbuilder
│ ├── api_resources/
│ │ ├── _api_resource.json.jbuilder
│ │ ├── _form.html.slim
│ │ ├── edit.html.slim
│ │ ├── index.html.slim
│ │ ├── index.json.jbuilder
│ │ ├── new.html.slim
│ │ ├── show.html.slim
│ │ └── show.json.jbuilder
│ ├── application/
│ │ ├── _admin.html.slim
│ │ ├── _groups_header.html.slim
│ │ └── _host_header.html.slim
│ ├── common/
│ │ └── errors.json.jbuilder
│ ├── groups/
│ │ ├── _form.html.slim
│ │ ├── index.html.slim
│ │ ├── new.html.slim
│ │ └── show.html.slim
│ ├── home/
│ │ └── index.html.slim
│ ├── host_machines/
│ │ ├── index.html.slim
│ │ ├── new.html.slim
│ │ └── show.html.slim
│ ├── layouts/
│ │ ├── application.html.slim
│ │ ├── home.html.slim
│ │ └── profile.html.slim.disabled
│ ├── nss/
│ │ └── add_host.json.jbuilder
│ ├── organisations/
│ │ ├── _form.html.slim
│ │ ├── config_saml_app.html.slim
│ │ ├── index.html.slim
│ │ ├── new.html.slim
│ │ ├── saml_apps/
│ │ │ └── _datadog.html.erb
│ │ └── show.html.slim
│ ├── profile/
│ │ ├── _group_search.html.slim
│ │ ├── _user_search.html.slim
│ │ ├── group_admin.html.slim
│ │ ├── list.html.slim
│ │ ├── public_key.html.slim
│ │ ├── show.html.slim
│ │ ├── user.html.slim
│ │ └── user_admin.html.slim
│ ├── saml_idp/
│ │ └── idp/
│ │ └── new.html.erb
│ ├── users/
│ │ ├── _search.html.slim
│ │ ├── index.html.slim
│ │ ├── new.html.erb
│ │ └── show.html.slim
│ └── vpns/
│ ├── _form.html.slim
│ ├── edit.html.slim
│ ├── index.html.slim
│ ├── new.html.slim
│ └── show.html.slim
├── bin/
│ ├── bundle
│ ├── rails
│ ├── rake
│ ├── setup
│ └── update
├── config/
│ ├── application.rb
│ ├── boot.rb
│ ├── cable.yml
│ ├── database.yml
│ ├── environment.rb
│ ├── environments/
│ │ ├── development.rb
│ │ ├── integration.rb
│ │ ├── production.rb
│ │ └── test.rb
│ ├── initializers/
│ │ ├── application_controller_renderer.rb
│ │ ├── assets.rb
│ │ ├── backtrace_silencers.rb
│ │ ├── content_security_policy.rb
│ │ ├── cookies_serializer.rb
│ │ ├── devise.rb
│ │ ├── dotenv.rb
│ │ ├── filter_parameter_logging.rb
│ │ ├── inflections.rb
│ │ ├── mime_types.rb
│ │ ├── new_framework_defaults.rb
│ │ ├── new_framework_defaults_7_0.rb
│ │ ├── permissions_policy.rb
│ │ ├── session_store.rb
│ │ └── wrap_parameters.rb
│ ├── locales/
│ │ ├── devise.en.yml
│ │ ├── en.bootstrap.yml
│ │ └── en.yml
│ ├── newrelic.yml
│ ├── puma.rb
│ ├── redis.yml
│ ├── routes.rb
│ ├── schedule.rb
│ ├── secrets.yml
│ ├── spring.rb
│ └── storage.yml
├── config.ru
├── db/
│ ├── migrate/
│ │ ├── 20160419122430_devise_create_users.rb
│ │ ├── 20160419132647_add_provider_to_users.rb
│ │ ├── 20160419144739_add_name_to_users.rb
│ │ ├── 20160427123146_add_auth_key_to_user.rb
│ │ ├── 20160427123233_add_provisioning_uri_to_user.rb
│ │ ├── 20160519042340_add_active_to_users.rb
│ │ ├── 20160519064340_add_default_value_to_users.rb
│ │ ├── 20160615044834_create_hosts.rb
│ │ ├── 20160615045052_add_admin_to_user.rb
│ │ ├── 20160615112805_add_user_to_host.rb
│ │ ├── 20160628140022_add_deleted_at_to_host.rb
│ │ ├── 20160628140440_add_deleted_by_to_host.rb
│ │ ├── 20160629043358_add_homedir_to_user.rb
│ │ ├── 20160629043415_add_shell_to_user.rb
│ │ ├── 20160629075435_create_groups.rb
│ │ ├── 20160701090045_create_group_associations.rb
│ │ ├── 20160701112600_add_deleted_properties_to_group.rb
│ │ ├── 20160707115313_create_access_tokens.rb
│ │ ├── 20160714115228_add_public_key_to_user.rb
│ │ ├── 20160908081651_create_host_machines.rb
│ │ ├── 20161003145832_create_host_access_groups.rb
│ │ ├── 20170803140620_add_user_login_id_to_user.rb
│ │ ├── 20171013115441_create_versions.rb
│ │ ├── 20171016064705_remove_index_group_name.rb
│ │ ├── 20171016071526_add_unique_index_on_groups_name.rb
│ │ ├── 20171031060034_create_group_admin.rb
│ │ ├── 20171031060217_add_foreign_key_ref_on_group_admin.rb
│ │ ├── 20171031100758_create_vpns.rb
│ │ ├── 20171031101026_create_vpn_group_association.rb
│ │ ├── 20171031103518_add_foreign_key_ref_on_vpn_group_association.rb
│ │ ├── 20171031113123_create_vpn_group_user_association.rb
│ │ ├── 20171031121702_add_foreign_key_ref_on_vpn_group_user_association.rb
│ │ ├── 20171102071909_add_ip_address_to_vpns.rb
│ │ ├── 20171107114249_remove_url_from_vpns.rb
│ │ ├── 20171108130234_add_user_id_to_access_token.rb
│ │ ├── 20171108130353_add_foreign_key_ref_on_access_tokens.rb
│ │ ├── 20171124090240_add_uuid_to_vpns.rb
│ │ ├── 20171124114427_create_vpn_domain_name_servers.rb
│ │ ├── 20171124114830_create_vpn_search_domains.rb
│ │ ├── 20171124115925_create_vpn_supplemental_match_domains.rb
│ │ ├── 20180104081814_add_product_name_to_users.rb
│ │ ├── 20180202102206_create_saml_service_providers.rb
│ │ ├── 20180214050204_add_api_key_to_host_machines.rb
│ │ ├── 20180214052451_create_ip_addresses.rb
│ │ ├── 20180214052644_add_host_machine_to_ip_address.rb
│ │ ├── 20180219150818_add_description_to_group.rb
│ │ ├── 20180222135930_add_access_key_to_host_machine.rb
│ │ ├── 20180222140000_add_access_key_to_user.rb
│ │ ├── 20180227051732_create_api_resources.rb
│ │ ├── 20180301010021_add_user_to_api_resources.rb
│ │ ├── 20180301010035_add_group_to_api_resources.rb
│ │ ├── 20180306231200_add_deactivated_at_to_users.rb
│ │ ├── 20180311082600_rename_access_key_in_api_resources.rb
│ │ ├── 20180311161200_rename_token_in_access_tokens.rb
│ │ ├── 20180318083000_create_indexes_to_speedup_nss_controller.rb
│ │ ├── 20180613074108_create_organisations.rb
│ │ ├── 20180613165050_drop_saml_service_providers.rb
│ │ ├── 20180723175600_update_organisations_for_saml.rb
│ │ ├── 20181002023107_add_default_admins_to_host_machines.rb
│ │ ├── 20181016093315_create_saml_app_configs.rb
│ │ ├── 20181208184236_add_fields_to_user.rb
│ │ ├── 20190624024930_add_expiration_date_to_group_associations.rb
│ │ ├── 20190820070910_create_endpoints.rb
│ │ ├── 20190820075040_create_group_endpoints.rb
│ │ ├── 20190820080624_add_foreign_key_ref_on_group_endpoints.rb
│ │ ├── 20200113065717_add_sessions_table.rb
│ │ ├── 20220926001848_add_service_name_to_active_storage_blobs.active_storage.rb
│ │ ├── 20220926001849_create_active_storage_variant_records.active_storage.rb
│ │ └── 20220926001850_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb
│ ├── schema.rb
│ ├── seeds/
│ │ ├── development.rb
│ │ ├── production.rb
│ │ └── test.rb
│ └── seeds.rb
├── docker-compose.yaml
├── docs/
│ ├── additional_setup.md
│ ├── administration.md
│ ├── dredd_setup.md
│ ├── newrelic.md
│ └── oauth_setup.md
├── dredd.yml
├── lib/
│ ├── assets/
│ │ └── .keep
│ ├── tasks/
│ │ ├── .keep
│ │ ├── app.rake
│ │ ├── setup.rake
│ │ ├── users.rake
│ │ └── vpn.rake
│ └── vpn/
│ ├── mobileconfig.erb
│ ├── mobileconfig.rb
│ └── namespace.rb
├── public/
│ ├── 404.html
│ ├── 422.html
│ ├── 500.html
│ └── robots.txt
├── scripts/
│ ├── gen-client-conf
│ └── gen-client-keys
├── setup.sh
└── spec/
├── clients/
│ └── data_dog_client_spec.rb
├── controllers/
│ ├── admin_controller_spec.rb
│ ├── api/
│ │ └── v1/
│ │ ├── api_controller_spec.rb
│ │ ├── endpoints_controller_spec.rb
│ │ ├── groups_controller_spec.rb
│ │ ├── users_controller_spec.rb
│ │ └── vpns_controller_spec.rb
│ ├── api_resources_controller_spec.rb
│ ├── groups_controller_spec.rb
│ ├── home_controller_spec.rb
│ ├── host_machine_groups_controller_spec.rb
│ ├── host_machines_controller_spec.rb
│ ├── nss_controller_spec.rb
│ ├── omniauth_callbacks_controller_spec.rb
│ ├── organisations_controller_spec.rb
│ ├── profile_controller_spec.rb
│ ├── users/
│ │ └── auth_controller_spec.rb
│ ├── users_controller_spec.rb
│ └── vpns_controller_spec.rb
├── factories/
│ ├── access_tokens.rb
│ ├── api_resources.rb
│ ├── endpoints.rb
│ ├── group_associations.rb
│ ├── groups.rb
│ ├── host_access_groups.rb
│ ├── host_machine_groups.rb
│ ├── host_machines.rb
│ ├── ip_addresses.rb
│ ├── organisations.rb
│ ├── saml_app_configs.rb
│ ├── user_host_access_groups.rb
│ ├── users.rb
│ └── vpns.rb
├── features/
│ ├── layout_spec.rb
│ ├── organisations/
│ │ ├── add_user_saml_app_spec.rb
│ │ ├── config_saml_app_spec.rb
│ │ ├── create_spec.rb
│ │ ├── list_spec.rb
│ │ ├── list_user_saml_app_spec.rb
│ │ ├── remove_user_saml_app_spec.rb
│ │ ├── save_config_saml_app_spec.rb
│ │ ├── setup_saml_spec.rb
│ │ └── update_spec.rb
│ ├── saml/
│ │ └── show_spec.rb
│ └── users/
│ ├── create_user_spec.rb
│ └── regenerate_auth_spec.rb
├── helpers/
│ └── application_helper_spec.rb
├── lib/
│ ├── datadog_spec.rb
│ ├── saml_app_spec.rb
│ └── tasks/
│ └── users_rake_spec.rb
├── models/
│ ├── access_token_spec.rb
│ ├── api_resource_spec.rb
│ ├── endpoint_spec.rb
│ ├── group_association_spec.rb
│ ├── group_endpoint_spec.rb
│ ├── group_spec.rb
│ ├── host_machine_spec.rb
│ ├── host_spec.rb
│ ├── ip_address_spec.rb
│ ├── organisation_spec.rb
│ ├── user_spec.rb
│ └── vpn_spec.rb
├── rails_helper.rb
├── routing/
│ └── api_resources_routing_spec.rb
├── spec_helper.rb
├── support/
│ └── helpers/
│ └── x509_certificate_helper.rb
└── views/
├── api_resources/
│ ├── edit.html.slim_spec.rb
│ ├── index.html.slim_spec.rb
│ ├── new.html.slim_spec.rb
│ └── show.html.slim_spec.rb
├── groups/
│ └── show.html.slim_spec.rb
└── layouts/
└── home.html.slim_spec.rb
================================================
FILE CONTENTS
================================================
================================================
FILE: .deepsource.toml
================================================
version = 1
[[analyzers]]
name = "ruby"
enabled = true
[[analyzers]]
name = "javascript"
enabled = true
================================================
FILE: .dockerignore
================================================
/log/*
!/log/.keep
/tmp
.idea
.env
*.swp
config/application.yml
dump.rdb
coverage
.git
================================================
FILE: .gitignore
================================================
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
# git config --global core.excludesfile '~/.gitignore_global'
# Ignore bundler config.
/.bundle
.local
vendor/*
# Ignore the default SQLite database.
/db/*.sqlite3
/db/*.sqlite3-journal
# Ignore all logfiles and tempfiles.
/log/*
!/log/.keep
/tmp
.idea
.env
.ruby-gemset
*.swp
config/application.yml
public/assets/*
dump.rdb
coverage
data/
================================================
FILE: .rspec
================================================
--color
--format documentation
--require spec_helper
================================================
FILE: .rubocop.yml
================================================
---
require:
- rubocop-rails
- rubocop-performance
- rubocop-faker
AllCops:
NewCops: enable
Exclude:
- config/initializers/*.rb
- config/environments/*.rb
- db/*.rb
- app/workers/*.rb
- app/services/**/*.rb
- spec/services/*.rb
- bin/*
- Rakefile
- lib/tasks/*.rake
- spec/workers/*.rb
- chef-repo/**/*
Naming/AccessorMethodName:
Description: Check the naming of accessor methods for get_/set_.
Enabled: false
Style/Alias:
Description: Use alias_method instead of alias.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#alias-method
Enabled: false
Style/ArrayJoin:
Description: Use Array#join instead of Array#*.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#array-join
Enabled: false
Style/AsciiComments:
Description: Use only ascii symbols in comments.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#english-comments
Enabled: false
Naming/AsciiIdentifiers:
Description: Use only ascii symbols in identifiers.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#english-identifiers
Enabled: false
Style/Attr:
Description: Checks for uses of Module#attr.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#attr
Enabled: false
Metrics/BlockNesting:
Description: Avoid excessive block nesting
StyleGuide: https://github.com/bbatsov/ruby-style-guide#three-is-the-number-thou-shalt-count
Enabled: false
Style/CaseEquality:
Description: Avoid explicit use of the case equality operator(===).
StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-case-equality
Enabled: false
Style/CharacterLiteral:
Description: Checks for uses of character literals.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-character-literals
Enabled: false
Style/ClassAndModuleChildren:
Description: Checks style of children classes and modules.
Enabled: true
EnforcedStyle: compact
Exclude:
- config/application.rb
Metrics/ClassLength:
Description: Avoid classes longer than 100 lines of code.
Enabled: false
Metrics/ModuleLength:
Description: Avoid modules longer than 100 lines of code.
Enabled: false
Style/ClassVars:
Description: Avoid the use of class variables.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-class-vars
Enabled: false
Style/CollectionMethods:
Enabled: true
PreferredMethods:
find: detect
inject: reduce
collect: map
find_all: select
Style/ColonMethodCall:
Description: 'Do not use :: for method call.'
StyleGuide: https://github.com/bbatsov/ruby-style-guide#double-colons
Enabled: false
Style/CommentAnnotation:
Description: Checks formatting of special comments (TODO, FIXME, OPTIMIZE, HACK,
REVIEW).
StyleGuide: https://github.com/bbatsov/ruby-style-guide#annotate-keywords
Enabled: false
Metrics/AbcSize:
Description: A calculated magnitude based on number of assignments, branches, and
conditions.
Enabled: false
Metrics/BlockLength:
CountComments: true
Max: 25
AllowedMethods: []
Exclude:
- spec/**/*
- config/environments/*.rb
Metrics/CyclomaticComplexity:
Description: A complexity metric that is strongly correlated to the number of test
cases needed to validate a method.
Enabled: false
Rails/Delegate:
Description: Prefer delegate method for delegations.
Enabled: false
Style/PreferredHashMethods:
Description: Checks use of `has_key?` and `has_value?` Hash methods.
StyleGuide: "#hash-key"
Enabled: false
Style/Documentation:
Description: Document classes and non-namespace modules.
Enabled: false
Style/DoubleNegation:
Description: Checks for uses of double negation (!!).
StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-bang-bang
Enabled: false
Style/EachWithObject:
Description: Prefer `each_with_object` over `inject` or `reduce`.
Enabled: false
Style/EmptyLiteral:
Description: Prefer literals to Array.new/Hash.new/String.new.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#literal-array-hash
Enabled: false
Style/Encoding:
Enabled: false
Style/EvenOdd:
Description: Favor the use of Fixnum#even? && Fixnum#odd?
StyleGuide: https://github.com/bbatsov/ruby-style-guide#predicate-methods
Enabled: false
Naming/FileName:
Description: Use snake_case for source file names.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#snake-case-files
Enabled: false
Style/FrozenStringLiteralComment:
Description: Add the frozen_string_literal comment to the top of files to help transition
from Ruby 2.3.0 to Ruby 3.0.
Enabled: false
Style/FormatString:
Description: Enforce the use of Kernel#sprintf, Kernel#format or String#%.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#sprintf
Enabled: false
Style/GlobalVars:
Description: Do not introduce global variables.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#instance-vars
Reference: http://www.zenspider.com/Languages/Ruby/QuickRef.html
Enabled: false
Style/GuardClause:
Description: Check for conditionals that can be replaced with guard clauses
StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-nested-conditionals
Enabled: false
Style/IfUnlessModifier:
Description: Favor modifier if/unless usage when you have a single-line body.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#if-as-a-modifier
Enabled: false
Style/IfWithSemicolon:
Description: Do not use if x; .... Use the ternary operator instead.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-semicolon-ifs
Enabled: false
Style/InlineComment:
Description: Avoid inline comments.
Enabled: false
Style/Lambda:
Description: Use the new lambda literal syntax for single-line blocks.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#lambda-multi-line
Enabled: false
Style/LambdaCall:
Description: Use lambda.call(...) instead of lambda.(...).
StyleGuide: https://github.com/bbatsov/ruby-style-guide#proc-call
Enabled: false
Style/LineEndConcatenation:
Description: Use \ instead of + or << to concatenate two string literals at line
end.
Enabled: false
Metrics/MethodLength:
Description: Avoid methods longer than 10 lines of code.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#short-methods
Enabled: false
Style/ModuleFunction:
Description: Checks for usage of `extend self` in modules.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#module-function
Enabled: false
Style/MultilineBlockChain:
Description: Avoid multi-line chains of blocks.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#single-line-blocks
Enabled: false
Style/NegatedIf:
Description: Favor unless over if for negative conditions (or control flow or).
StyleGuide: https://github.com/bbatsov/ruby-style-guide#unless-for-negatives
Enabled: false
Style/NegatedWhile:
Description: Favor until over while for negative conditions.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#until-for-negatives
Enabled: false
Style/Next:
Description: Use `next` to skip iteration instead of a condition at the end.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-nested-conditionals
Enabled: false
Style/NilComparison:
Description: Prefer x.nil? to x == nil.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#predicate-methods
Enabled: false
Style/Not:
Description: Use ! instead of not.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#bang-not-not
Enabled: false
Style/NumericLiterals:
Description: Add underscores to large numeric literals to improve their readability.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#underscores-in-numerics
Enabled: false
Style/OneLineConditional:
Description: Favor the ternary operator(?:) over if/then/else/end constructs.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#ternary-operator
Enabled: false
Naming/BinaryOperatorParameterName:
Description: When defining binary operators, name the argument other.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#other-arg
Enabled: false
Metrics/ParameterLists:
Description: Avoid parameter lists longer than three or four parameters.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#too-many-params
Enabled: false
Style/PercentLiteralDelimiters:
Description: Use `%`-literal delimiters consistently
StyleGuide: https://github.com/bbatsov/ruby-style-guide#percent-literal-braces
Enabled: false
Style/PerlBackrefs:
Description: Avoid Perl-style regex back references.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-perl-regexp-last-matchers
Enabled: false
Naming/PredicateName:
Description: Check the names of predicate methods.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#bool-methods-qmark
ForbiddenPrefixes:
- is_
Exclude:
- spec/**/*
Style/Proc:
Description: Use proc instead of Proc.new.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#proc
Enabled: false
Style/RaiseArgs:
Description: Checks the arguments passed to raise/fail.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#exception-class-messages
Enabled: false
Style/RegexpLiteral:
Description: Use / or %r around regular expressions.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#percent-r
Enabled: false
Style/SelfAssignment:
Description: Checks for places where self-assignment shorthand should have been
used.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#self-assignment
Enabled: false
Style/SingleLineBlockParams:
Description: Enforces the names of some block params.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#reduce-blocks
Enabled: false
Style/SingleLineMethods:
Description: Avoid single-line methods.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-single-line-methods
Enabled: false
Style/SignalException:
Description: Checks for proper usage of fail and raise.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#fail-method
Enabled: false
Style/SpecialGlobalVars:
Description: Avoid Perl-style global variables.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-cryptic-perlisms
Enabled: false
Style/StringLiterals:
Description: Checks if uses of quotes match the configured preference.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#consistent-string-literals
EnforcedStyle: single_quotes
Enabled: true
Style/TrailingCommaInArguments:
Description: Checks for trailing comma in argument lists.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas
EnforcedStyleForMultiline: no_comma
SupportedStylesForMultiline:
- comma
- consistent_comma
- no_comma
Enabled: true
Style/TrailingCommaInArrayLiteral:
Description: Checks for trailing comma in array literals.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas
EnforcedStyleForMultiline: comma
SupportedStylesForMultiline:
- comma
- consistent_comma
- no_comma
Enabled: true
Style/TrailingCommaInHashLiteral:
Description: Checks for trailing comma in hash literals.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas
EnforcedStyleForMultiline: comma
SupportedStylesForMultiline:
- comma
- consistent_comma
- no_comma
Enabled: true
Style/TrivialAccessors:
Description: Prefer attr_* methods to trivial readers/writers.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#attr_family
Enabled: false
Style/VariableInterpolation:
Description: Don't interpolate global, instance and class variables directly in
strings.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#curlies-interpolate
Enabled: false
Style/WhenThen:
Description: Use when x then ... for one-line cases.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#one-line-cases
Enabled: false
Style/WhileUntilModifier:
Description: Favor modifier while/until usage when you have a single-line body.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#while-as-a-modifier
Enabled: false
Style/WordArray:
Description: Use %w or %W for arrays of words.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#percent-w
Enabled: false
Layout/ConditionPosition:
Description: Checks for condition placed in a confusing position relative to the
keyword.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#same-line-condition
Enabled: false
Layout/DotPosition:
Description: Checks the position of the dot in multi-line method calls.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#consistent-multi-line-chains
EnforcedStyle: trailing
Layout/ExtraSpacing:
Description: Do not use unnecessary spacing.
Enabled: true
Layout/MultilineOperationIndentation:
Description: Checks indentation of binary operations that span more than one line.
Enabled: true
EnforcedStyle: indented
Layout/MultilineMethodCallIndentation:
Description: Checks indentation of method calls with the dot operator that span
more than one line.
Enabled: true
EnforcedStyle: indented
Layout/InitialIndentation:
Description: Checks the indentation of the first non-blank non-comment line in a
file.
Enabled: false
Lint/AmbiguousOperator:
Description: Checks for ambiguous operators in the first argument of a method invocation
without parentheses.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#parens-as-args
Enabled: false
Lint/AmbiguousRegexpLiteral:
Description: Checks for ambiguous regexp literals in the first argument of a method
invocation without parenthesis.
Enabled: false
Lint/AssignmentInCondition:
Description: Don't use assignment in conditions.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#safe-assignment-in-condition
Enabled: false
Lint/CircularArgumentReference:
Description: Don't refer to the keyword argument in the default value.
Enabled: false
Lint/DeprecatedClassMethods:
Description: Check for deprecated class method calls.
Enabled: false
Lint/EachWithObjectArgument:
Description: Check for immutable argument given to each_with_object.
Enabled: false
Lint/ElseLayout:
Description: Check for odd code arrangement in an else block.
Enabled: false
Lint/FormatParameterMismatch:
Description: The number of parameters to format/sprint must match the fields.
Enabled: false
Lint/LiteralAsCondition:
Description: Checks of literals used in conditions.
Enabled: false
Lint/LiteralInInterpolation:
Description: Checks for literals used in interpolation.
Enabled: false
Lint/Loop:
Description: Use Kernel#loop with break rather than begin/end/until or begin/end/while
for post-loop tests.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#loop-with-break
Enabled: false
Lint/NestedMethodDefinition:
Description: Do not use nested method definitions.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-nested-methods
Enabled: false
Lint/NonLocalExitFromIterator:
Description: Do not use return in iterator to cause non-local exit.
Enabled: false
Lint/ParenthesesAsGroupedExpression:
Description: Checks for method calls with a space before the opening parenthesis.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#parens-no-spaces
Enabled: false
Lint/RequireParentheses:
Description: Use parentheses in the method call to avoid confusion about precedence.
Enabled: false
Lint/UnderscorePrefixedVariableName:
Description: Do not use prefix `_` for a variable that is used.
Enabled: false
Lint/Void:
Description: Possible use of operator/literal/variable in void context.
Enabled: false
Performance/CaseWhenSplat:
Description: Place `when` conditions that use splat at the end of the list of `when`
branches.
Enabled: false
Performance/Count:
Description: Use `count` instead of `select...size`, `reject...size`, `select...count`,
`reject...count`, `select...length`, and `reject...length`.
Enabled: false
Performance/Detect:
Description: Use `detect` instead of `select.first`, `find_all.first`, `select.last`,
and `find_all.last`.
Reference: https://github.com/JuanitoFatas/fast-ruby#enumerabledetect-vs-enumerableselectfirst-code
Enabled: false
Performance/FlatMap:
Description: Use `Enumerable#flat_map` instead of `Enumerable#map...Array#flatten(1)`
or `Enumberable#collect..Array#flatten(1)`
Reference: https://github.com/JuanitoFatas/fast-ruby#enumerablemaparrayflatten-vs-enumerableflat_map-code
Enabled: false
Performance/ReverseEach:
Description: Use `reverse_each` instead of `reverse.each`.
Reference: https://github.com/JuanitoFatas/fast-ruby#enumerablereverseeach-vs-enumerablereverse_each-code
Enabled: false
Performance/Size:
Description: Use `size` instead of `count` for counting the number of elements in
`Array` and `Hash`.
Reference: https://github.com/JuanitoFatas/fast-ruby#arraycount-vs-arraysize-code
Enabled: false
Performance/StringReplacement:
Description: Use `tr` instead of `gsub` when you are replacing the same number of
characters. Use `delete` instead of `gsub` when you are deleting characters.
Reference: https://github.com/JuanitoFatas/fast-ruby#stringgsub-vs-stringtr-code
Enabled: false
Rails/ActionFilter:
Description: Enforces consistent use of action filter methods.
Enabled: false
Rails/Date:
Description: Checks the correct usage of date aware methods, such as Date.today,
Date.current etc.
Enabled: false
Rails/FindBy:
Description: Prefer find_by over where.first.
Enabled: false
Rails/FindEach:
Description: Prefer all.find_each over all.find.
Enabled: false
Rails/HasAndBelongsToMany:
Description: Prefer has_many :through to has_and_belongs_to_many.
Enabled: false
Rails/Output:
Description: Checks for calls to puts, print, etc.
Enabled: false
Rails/ReadWriteAttribute:
Description: Checks for read_attribute(:attr) and write_attribute(:attr, val).
Enabled: false
Rails/ScopeArgs:
Description: Checks the arguments of ActiveRecord scopes.
Enabled: false
Rails/TimeZone:
Description: Checks the correct usage of time zone aware methods.
StyleGuide: https://github.com/bbatsov/rails-style-guide#time
Reference: http://danilenko.org/2012/7/6/rails_timezones
Enabled: false
Rails/Validation:
Description: Use validates :attribute, hash of validations.
Enabled: false
Lint/FlipFlop:
Description: Checks for flip flops
StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-flip-flops
Enabled: false
Layout/LineLength:
Description: Limit lines to 80 characters.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#80-character-limits
Max: 100
Style/Sample:
Description: Use `sample` instead of `shuffle.first`, `shuffle.last`, and `shuffle[Fixnum]`.
Reference: https://github.com/JuanitoFatas/fast-ruby#arrayshufflefirst-vs-arraysample-code
Enabled: false
Layout/ParameterAlignment:
Description: Here we check if the parameters on a multi-line method call or definition
are aligned.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-double-indent
Enabled: false
Lint/DuplicateHashKey:
Description: Check for duplicate keys in hash literals.
Enabled: false
Lint/SuppressedException:
Description: Don't suppress exception.
StyleGuide: https://github.com/bbatsov/ruby-style-guide#dont-hide-exceptions
Enabled: false
Lint/RedundantCopDisableDirective:
Description: 'Checks for rubocop:disable comments that can be removed. Note: this
cop is not disabled when disabling all cops. It must be explicitly disabled.'
Enabled: false
================================================
FILE: .ruby-version
================================================
ruby-3.1.2
================================================
FILE: .travis.yml
================================================
dist: xenial
sudo: required
language: ruby
rvm:
- ruby-2.4.4
services:
- redis-server
- mysql
env:
global:
- GATE_SERVER_URL=gate.server/url
- SIGN_IN_TYPE=
- GATE_OAUTH_CLIENT_ID=totally_secret_client_id
- GATE_OAUTH_CLIENT_SECRET=totally_secret
- GATE_HOSTED_DOMAIN=gate.domain
- GATE_HOSTED_DOMAINS=test1.com,test2.com
- GATE_DB_HOST=localhost
- GATE_DB_PORT=3306
- GATE_DB_NAME=
- GATE_DB_USER=root
- GATE_DB_PASSWORD=
- CACHE_HOST=localhost
- CACHE_PORT=6379
- SECRET_KEY_BASE=
- SECRET_API_KEY=
- GATE_CONFIG_SECRET=gate_pw_secret
- USER_ROLES=employee,consultant
- UID_BUFFER=5000
- DEFAULT_HOST_PATTERN=s*
- PRODUCT_LIST=pr1,pr2
- SAML_APPS=datadog
- secure: Q2/gUeT/Y6IUKsRzgiiE6HGxLcHAzTtVCv6+6TcQnpJL9+HEO06+ISwekNXHRe/2BNMiWzDG5ufqo2YpA1j9h8899KAJZRYDULbbV0o8nrpT2kZSac1ZejBVYb/SrhDk8wrnQxQ061o6SdKpFEEwbIiJDzaqeQkv4tkyw3dEOq6+FRGS/QXj3mPIIArPbNCOtwcvnmg0mGIuPAAxuRZmz4Tuk2F6JdR4LrZstf33mvUYqbTw02Kl7UoErFjGSx2Ti+JPYIVDJ6D8pNCjv5va3awJskcXE5bj0evR5+OiP69GK6T2/UbP+QKwN2J36Pb9RxBKGuEkBTNuduch+h+RMiYk0A8MDO3Sy47i2v8Oj1xTEYqsNm0scmD2utZ93/VqPipYTrxuos7gbC4mdiW3dcMzyrhgaULEJlvalKaSQV41Xex8h/V7NCRvpoYjnyuWVUMQFgGSnE25Xpt1LvP3epcxlEBA9LcndskbEHaWup8mCD2bp+2Zq10iWi/hNnR2IBrj61fApTWBSoNplJMsMZNb3bverQVFFG79Gfr320HWk+eJVahZNFwUYp9VYn17r38nMRdfP9B85hm2ZUEiokzOvEXEKoSa2QVlCNQHk4HGJmfykPn4L8kDnS6LhYV3Yxugxwsl//1iUOwv4+ARMGn/rs13BDOixWXc+GVZIvk=
- secure: hTSsv54GMEfKuZfk5UL3cekNK4ZgEEWwTp2cbfN39ViWBbq4xtXok1jREx4QyhwkNak47ewHuY0rifxPEYkJVJfj+tA/xiGs9BOG73gNEtQYhXXN/ZodXF0Kq3pYOfcVWDDo7oMAUoohkohHK2TA+KY3mfk5sFbxbXHOlNdSn0vXDSa8MgzALoN6+w1oWkC41perODfNS4EYD3gdhwDg4x6QHrmakrt0oOP4PPMCpOWinvkzWq7lBDdhkPSze47BwGilyUDFSJnunSKip88s6DlP4gNj6YYBiT6xGTPLuR76tgEPma9rp25zGvLxH9LsluMXTNuN0L3/6FzVyv0kJgXIwQrpgreQ+B45q3mT6iNom0alyNk3fYDKU59azpH9G0rC0zflmOhW+jssgwyJN08rJN8rFkhpQreD4dgey7+UDjf7qF3rOd0kXmqBvA/3z/aF8Mla/2+EIb1DjyHwnjAcPF2E0/97Gv2eGpZR/PPrQIVN2m8vEe3ce/39c4S/l9OU0G4Dqz9HMqIBG+0qFdS24+egbjaIoOQzO/eJwG/eew4ncvaz/ES8qCDtvFNeKR+QnfxcbJysybrxDNTqt3cBGTeotIdZxIB3rYK63+s+dvzggm09vBMafoP7zyWzD0xjSES7m+Gv9V8Jlvc7h5JSWrkmAgLmgnqt7FpI7hs=
- secure: KtmItMzRHfZEPS54hTnYXNAWsqxCZZMtmxamJPcr2SVP+pzM/25eEF3M2b0JZECFRtW3xPBGita+4BjH8IY4NljH0IDVhPPKQsMHaVKtaqEeiTCRXCqkJd0DMUDeqyRcccwPDJSy9HeZns6E+zQDCGaC/tmFwDUWy5BYpairWd7sdw436iOeTmQ2fJ8SQ9lBr9LGpk8NwDmkYqg14fnOraIhw70tiWv9Wn82mEv+OwY4iKphOv2ZXEBeJYitoT1LQmhnaVvNvax16TYIY3Mxh89Oy2gVkKCgvbR9q1NmAIiWmMTyCLWxF0bd6A6Q+dHDDaQZF0pDsQqe83rnoA0xuaJUF9dh+ahvW0bn0aVFIa8tWgiBEMXWxHEDuEyfCWFis9vf3uj1xJl0SV0ktE5oIRzaF/0cTQorAwRy0UpN1HxK1yB9aITCad/BJ9ERK8MXYnfzC65jn2zHuQMjBz9Aeig4sgLc4IgtGM2DzabsIkhYG3ygL1TYaXXSj5Mo2KDwOuaZ46C7B6qxlzcesPmSnM3KF1CBatRZQK5tjsMm5GnxXKKtqg/udGtOA2fELlNolFsojtpmO4A79TAnebRUpEsU2vP0da1x7yTD5+2NWg6dnvq7tA3c5b8qBK2cAMnCHS0gmjaN3RYeFhLYO55dHDdmx/DNyQQ1V/YEkuisy80=
- COMMIT=${TRAVIS_COMMIT::8}
- DOCKER_COMPOSE_VERSION=1.11.2
before_install:
- gem update --system
- gem install bundler
stages:
- build, test and releases
- name: build and publish docker
if: (branch = master OR tag IS present) and type != pull_request
jobs:
include:
- stage: build, test and releases
script:
- sudo mysql_upgrade -u root
- sudo service mysql restart
- mysql -e 'CREATE DATABASE IF NOT EXISTS gate_test;'
- gem install bundler
- bundle package --all
- bundle install --binstubs --local
- bundle exec rake db:migrate
- bundle exec rake spec
- bundle exec rake assets:precompile RAILS_ENV=production
before_deploy:
- "rm -rf $TRAVIS_BUILD_DIR/*.tar.gz"
- "tar zcf gate-$TRAVIS_TAG.tar.gz -C $TRAVIS_BUILD_DIR ./*"
deploy:
provider: releases
skip_cleanup: true
api_key:
secure: VWDGnrtrECoeJBATfe71HdpvnD15IKTkHWq/cQDfo9FTrm005ngTusQpW0eim76tSTMcJ1OBLoE9aAkd4Szi00TWenNPaAWHtgodcvNXxjqyZEtznRmtZW/vSk2H+iwJxJZoPDMZqStjmmSoD0dA1t2GLGltFzeJ5Y409YeroLUsVdRcTJY0mvQYbuLt1aZCu76gY5nB01yH7ib4ykZllJQbkyX57TKBYSLoQVUQ3hqo9BLUoROknHSfFGBHjSN9D3zIqKoh0XDOuTnyMHB+zMGmjjJbHMx5Z2eW1NW1HvpqDUOPl8uRnUEoCCfujA7OUlGgdadRBeUJObzpNkpQUNLEh5zIIr9NAZzjunzYkMiMZIseTNflJ6HOajld2Bcgz3PcbzM8hcIFog5loE7CBLWEzDoOIY/B75NYuHPIzRzTbgw7jf8XdfypCNMm0RLWiCXiDmuDMcNPZT9NrrheNGFz1CDmWkwpJmUTIv8J13J2Ux9ex1NY9iSRD8rgJ+bLOfp/u1nJWjACki8zq2/vffm2oUWz/R7q23Keq5Itddpe3mJUyFjokTUZPNSAlC45rF+rgK4ka7yJb+ZZAOaq/N8iIfVkgnfviWtaPQzAWRkO8J8Wzt1GrfQpNlo2BMM6Cpy0iV9ANYqAVYerImAopMWlzQmjbtt8P+xmmYA0FIw=
file_glob: true
file: $TRAVIS_BUILD_DIR/*.tar.gz
on:
tags: true
repo: gate-sso/gate
- stage: build and publish docker
install: skip
script:
- gem install bundler
- bundle install
- bundle exec rake assets:precompile RAILS_ENV=production
- echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
- docker build -t gatesso/gate:latest .
- if [ -n "$TRAVIS_TAG" ]; then
docker tag gatesso/gate:latest gatesso/gate:$TRAVIS_TAG;
fi
- docker images
- docker push gatesso/gate
================================================
FILE: CHANGELOG.md
================================================
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [1.1.8] - 2020-02-17
- Securing organisations configuration page
## [1.1.7] - 2020-02-24
### Fixed
- Fix audit trail when user removed from group
## [1.1.6] - 2020-01-14
### Changed
- Store session to db using active record instead of using cookies
## [1.1.5] - 2019-10-20
### Changed
- User API now also return `id`
## [1.1.4] - 2019-10-05
### Added
- API to add user to group (POST /api/v1/groups/:group_id/users)
## [1.1.3] - 2019-09-17
### Changed
- Update devise to version `4.7.1`.
## [1.1.2] - 2019-09-17
### Added
- Show email of group admin on group detail
- Show users join date to group on group detail
## [1.1.1] - 2019-09-02
### Changed
- Update nokogiri to version `1.10.4`.
## [1.1.0] - 2019-09-02
### Fixed
- Ensure that 'deactivated_at' on user is automatically set when we make user inactive
### Changed
- Improve access policy for actions on resources including profile, user, api resource, host machine, organisation
### Added
- Add endpoint entity to represent gate endpoint. Group will own endpoints, this mechanism will be used as an authorization for gate.
- Add api to deactivate user in gate (PATCH /api/v1/users/:id/deactivate).
## [1.0.5] - 2019-08-06
### Fixed
- Improve loading time when opening group and user show page
## [1.0.4] - 2019-07-17
### Fixed
- If a user don't have any VPNs, they should still be able to click download VPN without incurring exception
- Create missing tests for user model
- Optimize queries when fetching sysadmins
## [1.0.3] - 2019-07-16
### Fixed
- Fix nil pointer exception when group members response is nil
## [1.0.2] - 2019-07-15
### Fixed
- Optimize slow queries on vpn model
## [1.0.1] - 2019-07-15
### Added
- Add the ability to only fetch active user for `/api/v1/users/profile` API
## [1.0.0] - 2019-07-15
### Changed
- Use dotenv instead of figaro. This is a breaking change and warrant a major version release.
- All spiders are banned by default now in `robots.txt`
- When admin account become inactive, the admin status will automatically revoked.
- Admin can set expiration date on group assignment. This expiration date is optional, when not specified then it's a permanent assignment.
## [0.1.0] - 2019-05-20
### Changed
- Gate now uses semantic versioning.
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing Guidelines
## Releasing Gate
> Gate uses semantic versioning, check [this page](https://semver.org/) for more details on how to bump the version number.
Steps on releasing Gate.
1. Bump version on [VERSION](VERSION) file.
2. Add appropriate changelogs on [CHANGELOG.md](CHANGELOG.md) file. Please follow existing format.
3. Tag the commit by the new version number and push it, travis will automatically build and release Gate.
================================================
FILE: Dockerfile
================================================
FROM ruby:2.4
RUN apt-get update
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash
RUN apt-get update -qq && apt-get install -y build-essential nodejs git
RUN mkdir /app
WORKDIR /app
COPY Gemfile /app
COPY Gemfile.lock /app
RUN gem install bundler -v '>= 2.0'
RUN bundle install --without development
COPY . /app
CMD [ "bundle", "exec", "rails", "s" ]
================================================
FILE: Gemfile
================================================
source 'https://rubygems.org'
gem 'rails', '7.1.3.2'
gem 'activerecord-session_store'
gem 'ansi'
gem 'bootstrap'
gem 'countries', require: 'countries/global'
gem 'devise'
gem 'dotenv-rails'
gem 'font-awesome-rails'
gem 'httparty'
gem 'jbuilder'
gem 'mysql2'
gem 'omniauth'
gem 'omniauth-google-oauth2'
gem 'paranoia'
gem 'puma'
gem 'redis'
gem 'rotp'
gem 'rqrcode'
gem 'sassc-rails'
#Disabling SAML Feature during upgrade
# #TODO ENable this feature later
#gem 'ruby-saml', '1.8.0'
#gem 'saml_idp', git: 'https://github.com/gate-sso/saml_idp'
gem 'sdoc', group: :doc
# #TODO ENable this feature later
gem 'slim-rails'
gem 'turbolinks'
gem 'uglifier'
gem 'whenever', require: false
group :development, :test do
gem 'capybara'
gem 'coveralls'
gem 'database_cleaner'
gem 'dredd_hooks'
gem 'factory_bot_rails'
gem 'faker'
gem 'mock_redis'
gem 'pry'
gem 'rails-controller-testing'
gem 'rspec-rails'
gem 'rubocop'
gem 'rubocop-faker'
gem 'rubocop-performance'
gem 'rubocop-rails'
gem 'rubocop-rspec'
gem 'shoulda-matchers'
gem 'simplecov'
gem 'simplecov-console'
gem 'timecop'
gem 'webmock'
end
group :development do
gem 'web-console', platform: :ruby
end
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2016 gate-sso
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# Gate is now Gate-WireGuard
## DEPRECATED
#### Please use [Gate-WireGuard](https://github.com/gate-sso/gate-wireguard)
GateWireguard is based on WireGuard VPN Backend, also, it provides better security, faster speeds; it's much easier to install and run.
## *MASTER is broken* we are migrating to Rails 7.
## Ubuntu dependencies
Apart from devtools you need to install the following packages as well.
```
apt-get install libmysqlclient-dev
apt-get install libyaml-dev
```
#### Please note that we are upgrading gate RAILS version, and it will have breaking changes New RAILS 7 version will not be backward compatible and will not have many features We are removing many features, just to support API TOKENS and VPN functionality
#### Please use [RAILS 5 Branch](https://github.com/gate-sso/gate/tree/RAILS_5_RELEASE) for backward compatibilty
> Gate now uses semantic versioning to add more visibility on breaking changes. For users, you might want to check [CHANGELOG.md](CHANGELOG.md). For contributors, check [CONTRIBUTING.md](CONTRIBUTING.md).
Gate is a single sign-on (SSO) platform for centralised authentication across Linux, OpenVPN and CAS.
Gate works by automating OpenVPN profile creation for you and also providing you with google multi-factor authentication (MFA) integration. Gate provides single MFA Token authorisation across your organisation. Following scenarios can be handled by Gate:
1. Setup OpenVPN with Gate authentication.
2. Automatically create VPN profiles for each users.
3. Provide you with JaSig CAS Custom Authentication Handler to authenticate with Gate SSO and in turn enabling MFA for JaSig CAS.
4. Enable Linux authentication with [pam_gate](https://github.com/gate-sso/pam_gate), which sits like a small module with Linux and allow authentication.
5. Enable Name Service Switch (NSS) on Linux, so that Gate users can be discovered and authenticated on Linux.
6. **Access Control on Linux** Gate also allows you to control access to specific machines, like which hosts a user can login. And that can be controlled by reg-ex pattern on host name or IP addresses. (Note: pattern * matches everything).
> The entry point for self sign-in is Google mail authentication. If you don't use Google mail authentication, you can point gate to any OAuth provider and it should work.
> Gate provides you with single sign-on solution plus centralised user management across your applications and services. Not only it helps in controlling users access but it also helps in making most of it automated.
### Modules
* [pam_gate](https://github.com/gate-sso/pam_gate) - Gate module for Linux PAM
* [nss_gate](https://github.com/gate-sso/nss_gate) - Gate module for Linux Name Server Switch (NSS)
* [cas_gate](https://github.com/gate-sso/cas_gate) - CAS Customer MFA authentication handler for Gate
* open_vpn_gate - for OpenVPN setup, it is not extracted yet.
## Development Setup
> We are in the process of improving Gate setup process, please check back for updated instructions.
### Manual Setup
#### Initializing Your Application
* Ensure that ruby is installed (>= 2.4) and `bundler` gem is installed.
* Clone [Gate repository](https://github.com/gate-sso/gate)
* Run `bundle install`
* Run `rake app:init` to create environment file based on sample (we use dotenv to manage environment variables).
#### Setting up OAuth (Optional)
> If you setup Gate for development purpose and you want to avoid setting up OAuth, you can fill `SIGN_IN_TYPE` environment variable with `form`. This option will provide you with sign-in form in Gate homepage that you can fill with e-mail and name to sign-in.
> Note that you still need to update `GATE_HOSTED_DOMAINS` to serve your e-mail domain.
Check [this guide](docs/oauth_setup.md) For detailed information on how to setup OAuth.
#### Setting up Database and Cache
* Install and setup database (mysql) and update the following values (`GATE_DB_HOST`, `GATE_DB_PORT`, `GATE_DB_USER`, `GATE_DB_PASSWORD`) on `.env`.
* Install and setup cache (redis) and update the following values (`CACHE_DB`, `CACHE_HOST`).
#### Finishing Steps
To finalize your setup you just need to run `rake app:setup`. This command will setup your database and also run inital set of tests to make sure you have a successful setup.
Once Gate is setup, sign-in with your user and you should see welcome page with VPN profile download and VPN MFA Scanning.
If you want Gate to setup VPN for you then just install OpenVPN with easy rsa. Gate should just work fine with it.
> **NOTE** We will be putting more effort to automate VPN setup using Gate as well. Or you can send a pull request to help us with this.
### Docker Setup
* Build docker image using `docker build -t gate .`
* Create and update `.env` file according to `.env.example` with appropriate values
* Run the image using `docker run -p 3000:3000 --env-file=.env -it gate`
* If you want use docker-compose run using `docker-compose up`
## Additional Topics
* [API Blueprint Test](docs/dredd_setup.md)
* [Additional Setup](docs/additional_setup.md)
* [Administration](docs/administration.md)
* [Newrelic Integration](docs/newrelic.md)
### Changelog
See [CHANGELOG.md](CHANGELOG.md)
### Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md)
### License
MIT License, See [LICENSE](LICENSE).
================================================
FILE: Rakefile
================================================
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require File.expand_path('../config/application', __FILE__)
Rails.application.load_tasks
================================================
FILE: VERSION
================================================
1.1.8
================================================
FILE: api_blueprint/bin/dredd_server.sh
================================================
#!/bin/bash
# dredd_server.sh
kill -9 $(lsof -i tcp:9865 -t)
export RAILS_ENV=test
export LOG_LEVEL=info
rake db:drop
rake db:setup
bundle exec rails server --port=9865
================================================
FILE: api_blueprint/group.apib
================================================
FORMAT: 1A
# API Group
# Group [/api/v1/groups]
## Create Groups [POST]
Create new group
+ Request(application/json)
+ Body
{
"access_token": "token",
"name" : "foo"
}
+ Schema
{
"type": "object",
"properties" : {
"name" : {
"type" : "string"
},
"access_token" : {
"type" : "string"
}
}
}
+ Response 200
+ Headers
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
content-type: application/json; charset=utf-8
etag: W/"5c15461069e69109955c72671ffc465d"
cache-control: max-age=0, private, must-revalidate
x-request-id: 0613ec11-afd7-4dc0-9096-fee607d71c12
x-runtime: 0.073641
connection: close
transfer-encoding: chunked
+ Body
{
"id": 1,
"name": "foo"
}
+ Schema
{
"type": "object",
"properties" : {
"id" : {
"type" : "int"
},
"name" : {
"type" : "string"
}
}
}
+ Request(application/json)
+ Body
{
"access_token": "token",
"name" : "foo"
}
+ Schema
{
"type": "object",
"properties" : {
"name" : {
"type" : "string"
},
"access_token" : {
"type" : "string"
}
}
}
+ Response 422
+ Headers
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
content-type: application/json; charset=utf-8
cache-control: no-cache
x-request-id: 30ec7a3a-4794-435b-a5b9-8ff480cd648c
x-runtime: 0.007976
connection: close
transfer-encoding: chunked
+ Body
{
"status": "group already exist",
"id": 1,
"name": "foo"
}
+ Schema
{
"type": "object",
"properties" : {
"status" : {
"type" : "string"
},
"id" : {
"type" : "int"
},
"name" : {
"type" : "string"
}
}
}
+ Request(application/json)
+ Body
{
"access_token": "wrong token",
"name" : "foo"
}
+ Schema
{
"type": "object",
"properties" : {
"name" : {
"type" : "string"
},
"access_token" : {
"type" : "string"
}
}
}
+ Response 401
+ Headers
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
content-type: text/html
cache-control: no-cache
x-request-id: 30276bf6-0ce6-4ba6-b87d-7528b4f2c85d
x-runtime: 0.002650
connection: close
transfer-encoding: chunked
+ Body
# Group Users [/api/v1/groups/{group_id}/users]
+ Parameters
+ group_id: 1 (required, number) - ID of the Group in form of an integer
## Add user [POST]
+ user_id (required, number) - ID of the User in form of an integer
+ expiration_date (optional, date) - Membership expiration date in format (YYYY-MM-DD)
+ Request (application/json)
+ Header
Authorization: <user-token>
+ Body
{
"user_id": 7,
"expiration_date": "2019-11-20"
}
+ Response 204
================================================
FILE: api_blueprint/hooks/dredd_hooks.rb
================================================
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __dir__)
require 'dredd_hooks/methods'
include DreddHooks::Methods
before_all do |_|
user = User.create(name: 'foo', email: 'bar@test.com', admin: 1)
access_token = AccessToken.new
access_token.token = 'token'
access_token.user = user
user.access_token = access_token
access_token.save!
user.save!
inactive_user = User.create(name: 'foo', email: 'foo@test2.com', active: 0, user_login_id: 'foo')
inactive_user.save!
active_user = User.create(name: 'foo', email: 'foo@test.com', active: 1, user_login_id: 'foo')
active_user.save!
end
================================================
FILE: api_blueprint/user.apib
================================================
FORMAT: 1A
# API User
# User [/api/v1/users]
## Create Users [POST]
Create new users gate
+ Request(application/json)
+ Body
{
"access_token": "token",
"name" : "foo",
"email" : "foo@test.com"
}
+ Schema
{
"type": "object",
"properties" : {
"name" : {
"type" : "string"
},
"email" : {
"type" : "string"
},
"access_token" : {
"type" : "string"
}
}
}
+ Response 200
+ Headers
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
content-type: application/json; charset=utf-8
etag: W/"5c15461069e69109955c72671ffc465d"
cache-control: max-age=0, private, must-revalidate
x-request-id: 0613ec11-afd7-4dc0-9096-fee607d71c12
x-runtime: 0.073641
connection: close
transfer-encoding: chunked
+ Body
{
"status" : "created"
}
+ Schema
{
"type": "object",
"properties" : {
"status" : {
"type" : "string"
}
}
}
+ Request(application/json)
+ Body
{
"access_token": "wrong token",
"name" : "foo",
"email" : "foo@test.com"
}
+ Schema
{
"type": "object",
"properties" : {
"name" : {
"type" : "string"
},
"email" : {
"type" : "string"
},
"access_token" : {
"type" : "string"
}
}
}
+ Response 401
+ Headers
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
content-type: text/html
cache-control: no-cache
x-request-id: 30276bf6-0ce6-4ba6-b87d-7528b4f2c85d
x-runtime: 0.002650
connection: close
transfer-encoding: chunked
+ Body
# User [/api/v1/users/profile/{?email,uid,username,active}]
## Get Users [GET]
Get user data with email, uid or username
+ Request
+ Headers
Authorization: token
+ Parameters
+ email (string, optional)
+ Default: bar@test.com
+ uid (string, optional)
+ username (string, optional)
+ active ((string, boolean, int), optional)
+ Response 200
+ Body
{
"email": "bar@test.com",
"id": null,
"uid": null,
"name": "foo",
"active": true,
"admin": true,
"home_dir": null,
"shell": null,
"public_key": null,
"user_login_id": null,
"product_name": null,
"groups": []
}
+ Request
+ Headers
Authorization: token
+ Parameters
+ email (string, optional)
+ uid (string, optional)
+ username (string, optional)
+ Default: foo
+ active ((string, boolean, int), optional)
+ Default: 1
+ Response 200
+ Body
{
"email": "foo@test.com",
"uid": null,
"name": "foo",
"active": true,
"admin": true,
"home_dir": null,
"shell": null,
"public_key": null,
"user_login_id": "foo",
"product_name": null,
"groups": []
}
+ Request
+ Headers
Authorization: token
+ Parameters
+ email (string, optional)
+ Default: notfound@test.com
+ uid (string, optional)
+ username (string, optional)
+ active ((string, boolean, int), optional)
+ Response 404
+ Body
# User [/api/v1/users/profile]
## Update Users [POST]
Update users data with email as key
+ Request(application/json)
+ Headers
Authorization: token
+ Body
{
"name" : "foo bar",
"email" : "bar@test.com"
}
+ Schema
{
"type": "object",
"properties" : {
"name" : {
"type" : "string"
},
"email" : {
"type" : "string"
}
}
}
+ Response 200
+ Headers
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
content-type: application/json; charset=utf-8
etag: W/"c955e57777ec0d73639dca6748560d00"
cache-control: max-age=0, private, must-revalidate
x-request-id: 136874b1-39fb-4704-b548-d7670773a4bf
x-runtime: 0.014707
connection: close
transfer-encoding: chunked
+ Body
{
"success": true
}
+ Request(application/json)
+ Headers
Authorization: wrong-token
+ Body
{
"name" : "foo bar",
"email" : "bar@test.com"
}
+ Schema
{
"type": "object",
"properties" : {
"name" : {
"type" : "string"
},
"email" : {
"type" : "string"
}
}
}
+ Response 401
+ Headers
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
content-type: text/html
cache-control: no-cache
x-request-id: 85cb1679-58d4-41c4-9479-ce5f9c75ca7a
x-runtime: 0.002542
connection: close
transfer-encoding: chunked
================================================
FILE: api_blueprint/vpns.apib
================================================
FORMAT: 1A
# API VPNS
# VPNS [/api/v1/vpns]
## Create VPNS [POST]
Create new vpns
+ Request(application/json)
+ Headers
Authorization: token
+ Body
{
"id": 1,
"name": "test-vpn",
"host_name": "test-vpn.example.com",
"ip_address" : "10.10.10.10"
}
+ Schema
{
"type": "object",
"properties" : {
"id" : {
"type" : int
},
"name" : {
"type" : "string"
},
"host_name" : {
"type" : "string"
},
"ip_address" : {
"type" : "string"
}
}
}
+ Response 200
+ Body
{
"id": 1,
"name": "test-vpn",
"host_name": "test-vpn.example.com",
"ip_address": "10.10.10.10"
}
+ Request(application/json)
+ Headers
Authorization: wrong-token
+ Body
+ Response 401
+ Headers
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
content-type: text/html
cache-control: no-cache
x-request-id: 73b10aa8-6f68-400b-b723-2e992ac4d000
x-runtime: 0.002242
connection: close
transfer-encoding: chunked
================================================
FILE: app/assets/config/manifest.js
================================================
//= link application.css
//= link apple-touch-icon-144x144-precomposed.png
//= link apple-touch-icon-72x72-precomposed.png
//= link apple-touch-icon-precomposed.png
//= link favicon.ico
//= link application.js
================================================
FILE: app/assets/images/.keep
================================================
================================================
FILE: app/assets/javascripts/admin.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
================================================
FILE: app/assets/javascripts/api_resources.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
API_RESOURCE_NAME_FORMAT_ERROR_MSG = "Please enter valid name containing only alphanumeric (a-z, A-Z, 0-9), underscore (_) and dash (-)"
API_RESOURCE_NAME_UNIQUENESS_ERROR_MSG = "API name already taken"
API_RESOURCE_DESC_REQUIRED_ERROR_MSG = "Please enter description"
api_resources_ready = ->
$('#api_resource_name').on 'blur', ->
valid = validate_pattern($('#api_resource_name'), '^[a-zA-Z0-9_-]+$', API_RESOURCE_NAME_FORMAT_ERROR_MSG)
if valid
validate_uniqueness($('#api_resource_name'), '/api_resources/search', API_RESOURCE_NAME_UNIQUENESS_ERROR_MSG)
$('#api_resource_description').on 'blur', ->
validate_required($('#api_resource_description'), API_RESOURCE_DESC_REQUIRED_ERROR_MSG)
$('#new_api_resource').submit (event) ->
if $('.is-invalid').length > 0
event.preventDefault()
event.stopPropagation()
return
$(document).on('turbolinks:load', api_resources_ready)
================================================
FILE: app/assets/javascripts/application.js
================================================
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
// require jquery3
// require popper
// require bootstrap-sprockets
// require jquery_ujs
// require turbolinks
// require_tree .
================================================
FILE: app/assets/javascripts/bootstrap.js.coffee
================================================
jQuery ->
$("a[rel~=popover], .has-popover").popover()
$("a[rel~=tooltip], .has-tooltip").tooltip()
================================================
FILE: app/assets/javascripts/group.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
group_ready = ->
$('#assign_admin_include_inactive_user').prop('checked', false);
$('#assign_admin_user_id').selectize
maxItems: 1
valueField: 'id'
labelField: 'name'
searchField: 'name_email'
create: false
render: option: (item, escape) ->
'<div>' + escape(item.name) + '<br /><span class=\'small\'>' + escape(item.email) + '</span></div>'
load: (query, callback) ->
if !query.length
return callback()
# Clear the cache, because user list may change
this.clearOptions()
include_inactive = $('#assign_admin_include_inactive_user').is(':checked')
# Use remote as source
$.ajax
url: '/users/search?q=' + encodeURIComponent(query) + '&include_inactive=' + include_inactive
type: 'GET'
error: ->
callback()
return
success: (res) ->
callback res
return
return
$('#assign_admin_user_id').on 'change', ->
set_allow_submit($(this).val(), $(this))
$('#add_user_include_inactive_user').prop('checked', false);
$('#add_user_user_id').selectize
maxItems: 1
valueField: 'id'
labelField: 'name'
searchField: 'name_email'
create: false
render: option: (item, escape) ->
'<div>' + escape(item.name) + '<br /><span class=\'small\'>' + escape(item.email) + '</span></div>'
load: (query, callback) ->
if !query.length
return callback()
# Clear the cache, because user list may change
this.clearOptions()
include_inactive = $('#add_user_include_inactive_user').is(':checked')
# Use remote as source
$.ajax
url: '/users/search?q=' + encodeURIComponent(query) + '&include_inactive=' + include_inactive
type: 'GET'
error: ->
callback()
return
success: (res) ->
callback res
return
return
$('#add_user_user_id').on 'change', ->
set_allow_submit($(this).val(), $(this))
$('#add_vpn_vpn_id').selectize
maxItems: 1
valueField: 'id'
labelField: 'name'
searchField: 'name'
create: false
render: option: (item, escape) ->
'<div>' + escape(item.name) + '</div>'
load: (query, callback) ->
if !query.length
return callback()
# Use remote as source
$.ajax
url: '/vpns/search?q=' + encodeURIComponent(query)
type: 'GET'
error: ->
callback()
return
success: (res) ->
callback res
return
return
$('#add_vpn_vpn_id').on 'change', ->
set_allow_submit($(this).val(), $(this))
$('#add_machine_machine_id').selectize
maxItems: 1
valueField: 'id'
labelField: 'name'
searchField: 'name'
create: false
render: option: (item, escape) ->
'<div>' + escape(item.name) + '</div>'
load: (query, callback) ->
if !query.length
return callback()
# Use remote as source
$.ajax
url: '/host_machines/search?q=' + encodeURIComponent(query)
type: 'GET'
error: ->
callback()
return
success: (res) ->
callback res
return
return
$('#add_machine_machine_id').on 'change', ->
set_allow_submit($(this).val(), $(this))
$(document).on('turbolinks:load', group_ready)
================================================
FILE: app/assets/javascripts/groups.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
================================================
FILE: app/assets/javascripts/home.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
================================================
FILE: app/assets/javascripts/host_access_groups.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
================================================
FILE: app/assets/javascripts/host_machine_groups.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
================================================
FILE: app/assets/javascripts/host_machines.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
host_machines_ready = ->
$('#group_id').selectize
maxItems: 1
valueField: 'id'
labelField: 'name'
searchField: 'name'
create: false
render: option: (item, escape) ->
'<div>' + escape(item.name) + '</div>'
load: (query, callback) ->
if !query.length
return callback()
# Use remote as source
$.ajax
url: '/groups/search?q=' + encodeURIComponent(query)
type: 'GET'
error: ->
callback()
return
success: (res) ->
callback res
return
return
$('#group_id').on 'change', ->
set_allow_submit($(this).val(), $(this))
$(document).on('turbolinks:load', host_machines_ready)
================================================
FILE: app/assets/javascripts/nss.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
================================================
FILE: app/assets/javascripts/omniauth_callbacks.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
================================================
FILE: app/assets/javascripts/profile.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
================================================
FILE: app/assets/javascripts/users.coffee
================================================
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
users_ready = ->
$('#group_id').selectize
maxItems: 1
valueField: 'id'
labelField: 'name'
searchField: 'name'
create: false
render: option: (item, escape) ->
'<div>' + escape(item.name) + '</div>'
load: (query, callback) ->
if !query.length
return callback()
# Use remote as source
$.ajax
url: '/groups/search?q=' + encodeURIComponent(query)
type: 'GET'
error: ->
callback()
return
success: (res) ->
callback res
return
return
$('#group_id').on 'change', ->
set_allow_submit($(this).val(), $(this))
$(document).on('turbolinks:load', users_ready)
================================================
FILE: app/assets/javascripts/utilities.coffee
================================================
# Utility functions
@append_error_msg = (elem, res, msg) ->
if !res
elem.addClass('is-invalid')
elem.next('.invalid-feedback').html(msg)
else
elem.removeClass('is-invalid')
elem.next('.invalid-feedback').html('')
@validate_required = (elem, msg) ->
input = elem.val()
append_error_msg(elem, input, msg)
return !!input
@validate_pattern = (elem, pattern, msg) ->
input = elem.val()
regex = new RegExp(pattern)
validate_regex = regex.test(input)
append_error_msg(elem, validate_regex, msg)
return !!validate_regex
@validate_uniqueness = (elem, check_url, msg) ->
input = elem.val()
$.ajax
url: check_url + '?q=' + encodeURIComponent(input) + '&exact=true'
type: 'GET'
error: ->
return
success: (res) ->
append_error_msg(elem, $.isEmptyObject(res), msg)
return
@set_allow_submit = (cond, elem) ->
curSubmit = $("input[type=submit]", $(elem).parents('form'))
if !!cond
curSubmit.prop("disabled", false)
else
curSubmit.prop('disabled', true)
return
================================================
FILE: app/assets/javascripts/viewport.js
================================================
/*!
* IE10 viewport hack for Surface/desktop Windows 8 bug
* Copyright 2014-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
// See the Getting Started docs for more information:
// http://getbootstrap.com/getting-started/#support-ie10-width
(function () {
'use strict';
if (navigator.userAgent.match(/IEMobile\/10\.0/)) {
var msViewportStyle = document.createElement('style')
msViewportStyle.appendChild(
document.createTextNode(
'@-ms-viewport{width:auto!important}'
)
)
document.querySelector('head').appendChild(msViewportStyle)
}
})();
================================================
FILE: app/assets/stylesheets/application.scss
================================================
/*
* This is a manifest file that'll be compiled into application.css, which will include all the files
* listed below.
*
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
* compiled file so the styles you add here take precedence over styles defined in any styles
* defined in the other CSS/SCSS files in this directory. It is generally better to create a new
* file per style scope.
*
*= require_tree .
*= require_self
*= stub 'profile'
*= stub 'general'
*/
@import url(https://fonts.googleapis.com/css?family=Roboto:300);
@import url(https://fonts.googleapis.com/css?family=Lato:300);
@import "bootstrap";
@import "font-awesome";
/*
* https://github.com/ladjs/bootstrap-social
*/
@import "bootstrap-social";
a.btn { color: white!important; }
.form-group .field_with_errors { display: block; background: none; }
.form-group .field_with_errors label::after { content: ' *'; color: red; }
body {
font-family: 'Roboto', 'Lato', sans-serif;
}
.container-profile {
max-width: 768px;
min-width: 768px;
}
a:visited {
color: blue;
}
/* mouse over link */
a:hover {
color: blue;
background: none;
}
.table-responsive { overflow-x: inherit; }
#configAppTabsContent .tab-pane { padding-top: 20px; }
#configAppTabsContent ol li { margin-top: 10px; }
#configAppTabsContent li > ol { margin-bottom: 10px; }
================================================
FILE: app/assets/stylesheets/bootstrap-social.scss
================================================
/*
* Social Buttons for Bootstrap
*
* Copyright 2013-2016 Panayiotis Lipiridis
* Licensed under the MIT License
*
* https://github.com/lipis/bootstrap-social
*/
.btn-social, .btn-social-icon {
position: relative;
padding-left: 3.5rem;
text-align: left;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis; }
.btn-social > :first-child, .btn-social-icon > :first-child {
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 3rem;
line-height: 5rem;
font-size: 1.6em;
text-align: center;
border-right: 1px solid rgba(0, 0, 0, 0.2); }
.btn-social.btn-lg, .btn-lg.btn-social-icon {
padding-left: 4.75rem; }
.btn-social.btn-lg > :first-child, .btn-lg.btn-social-icon > :first-child {
line-height: 4rem;
width: 4rem;
font-size: 1.8em; }
.btn-social.btn-sm, .btn-sm.btn-social-icon {
padding-left: 2.25rem; }
.btn-social.btn-sm > :first-child, .btn-sm.btn-social-icon > :first-child {
line-height: 2rem;
width: 2rem;
font-size: 1.4em; }
.btn-social.btn-xs, .btn-xs.btn-social-icon {
padding-left: 2.25rem; }
.btn-social.btn-xs > :first-child, .btn-xs.btn-social-icon > :first-child {
line-height: 2rem;
width: 2rem;
font-size: 1.2em; }
.btn-social > :first-child, .btn-social-icon > :first-child {
line-height: 1.25 !important;
padding-top: 0.5rem !important;
padding-bottom: 0.5rem !important;
font-size: inherit !important; }
.btn-social.btn-lg > :first-child, .btn-lg.btn-social-icon > :first-child {
line-height: 1.25 !important;
padding-top: 0.75rem !important;
padding-bottom: 0.75rem !important;
font-size: inherit !important; }
.btn-social-icon {
height: 3rem;
width: 3rem;
padding: 0; }
.btn-social-icon > :first-child {
border: none;
text-align: center;
width: 100% !important; }
.btn-social-icon.btn-lg {
height: 4rem;
width: 4rem;
padding-left: 0;
padding-right: 0; }
.btn-social-icon.btn-sm {
height: 2rem;
width: 2rem;
padding-left: 0;
padding-right: 0; }
.btn-social-icon.btn-xs {
height: 2rem;
width: 2rem;
padding-left: 0;
padding-right: 0; }
.btn-adn {
color: #fff;
background-color: #d87a68;
border-color: #d87a68; }
.btn-adn:hover {
color: #fff;
background-color: #d05f4a;
border-color: #ce563f; }
.btn-adn:focus, .btn-adn.focus {
box-shadow: 0 0 0 3px rgba(216, 122, 104, 0.5); }
.btn-adn.disabled, .btn-adn:disabled {
background-color: #d87a68;
border-color: #d87a68; }
.btn-adn:active, .btn-adn.active, .show > .btn-adn.dropdown-toggle {
background-color: #d05f4a;
background-image: none;
border-color: #ce563f; }
.btn-bitbucket {
color: #fff;
background-color: #205081;
border-color: #205081; }
.btn-bitbucket:hover {
color: #fff;
background-color: #183d62;
border-color: #163758; }
.btn-bitbucket:focus, .btn-bitbucket.focus {
box-shadow: 0 0 0 3px rgba(32, 80, 129, 0.5); }
.btn-bitbucket.disabled, .btn-bitbucket:disabled {
background-color: #205081;
border-color: #205081; }
.btn-bitbucket:active, .btn-bitbucket.active, .show > .btn-bitbucket.dropdown-toggle {
background-color: #183d62;
background-image: none;
border-color: #163758; }
.btn-dropbox {
color: #fff;
background-color: #1087dd;
border-color: #1087dd; }
.btn-dropbox:hover {
color: #fff;
background-color: #0d71b9;
border-color: #0d6aad; }
.btn-dropbox:focus, .btn-dropbox.focus {
box-shadow: 0 0 0 3px rgba(16, 135, 221, 0.5); }
.btn-dropbox.disabled, .btn-dropbox:disabled {
background-color: #1087dd;
border-color: #1087dd; }
.btn-dropbox:active, .btn-dropbox.active, .show > .btn-dropbox.dropdown-toggle {
background-color: #0d71b9;
background-image: none;
border-color: #0d6aad; }
.btn-facebook {
color: #fff;
background-color: #3b5998;
border-color: #3b5998; }
.btn-facebook:hover {
color: #fff;
background-color: #30497c;
border-color: #2d4373; }
.btn-facebook:focus, .btn-facebook.focus {
box-shadow: 0 0 0 3px rgba(59, 89, 152, 0.5); }
.btn-facebook.disabled, .btn-facebook:disabled {
background-color: #3b5998;
border-color: #3b5998; }
.btn-facebook:active, .btn-facebook.active, .show > .btn-facebook.dropdown-toggle {
background-color: #30497c;
background-image: none;
border-color: #2d4373; }
.btn-flickr {
color: #fff;
background-color: #ff0084;
border-color: #ff0084; }
.btn-flickr:hover {
color: #fff;
background-color: #d90070;
border-color: #cc006a; }
.btn-flickr:focus, .btn-flickr.focus {
box-shadow: 0 0 0 3px rgba(255, 0, 132, 0.5); }
.btn-flickr.disabled, .btn-flickr:disabled {
background-color: #ff0084;
border-color: #ff0084; }
.btn-flickr:active, .btn-flickr.active, .show > .btn-flickr.dropdown-toggle {
background-color: #d90070;
background-image: none;
border-color: #cc006a; }
.btn-foursquare {
color: #fff;
background-color: #f94877;
border-color: #f94877; }
.btn-foursquare:hover {
color: #fff;
background-color: #f8235b;
border-color: #f71752; }
.btn-foursquare:focus, .btn-foursquare.focus {
box-shadow: 0 0 0 3px rgba(249, 72, 119, 0.5); }
.btn-foursquare.disabled, .btn-foursquare:disabled {
background-color: #f94877;
border-color: #f94877; }
.btn-foursquare:active, .btn-foursquare.active, .show > .btn-foursquare.dropdown-toggle {
background-color: #f8235b;
background-image: none;
border-color: #f71752; }
.btn-github {
color: #fff;
background-color: #444444;
border-color: #444444; }
.btn-github:hover {
color: #fff;
background-color: #313131;
border-color: #2b2b2b; }
.btn-github:focus, .btn-github.focus {
box-shadow: 0 0 0 3px rgba(68, 68, 68, 0.5); }
.btn-github.disabled, .btn-github:disabled {
background-color: #444444;
border-color: #444444; }
.btn-github:active, .btn-github.active, .show > .btn-github.dropdown-toggle {
background-color: #313131;
background-image: none;
border-color: #2b2b2b; }
.btn-google {
color: #fff;
background-color: #dd4b39;
border-color: #dd4b39; }
.btn-google:hover {
color: #fff;
background-color: #cd3623;
border-color: #c23321; }
.btn-google:focus, .btn-google.focus {
box-shadow: 0 0 0 3px rgba(221, 75, 57, 0.5); }
.btn-google.disabled, .btn-google:disabled {
background-color: #dd4b39;
border-color: #dd4b39; }
.btn-google:active, .btn-google.active, .show > .btn-google.dropdown-toggle {
background-color: #cd3623;
background-image: none;
border-color: #c23321; }
.btn-instagram {
color: #fff;
background-color: #3f729b;
border-color: #3f729b; }
.btn-instagram:hover {
color: #fff;
background-color: #345e80;
border-color: #305777; }
.btn-instagram:focus, .btn-instagram.focus {
box-shadow: 0 0 0 3px rgba(63, 114, 155, 0.5); }
.btn-instagram.disabled, .btn-instagram:disabled {
background-color: #3f729b;
border-color: #3f729b; }
.btn-instagram:active, .btn-instagram.active, .show > .btn-instagram.dropdown-toggle {
background-color: #345e80;
background-image: none;
border-color: #305777; }
.btn-linkedin {
color: #fff;
background-color: #007bb6;
border-color: #007bb6; }
.btn-linkedin:hover {
color: #fff;
background-color: #006190;
border-color: #005983; }
.btn-linkedin:focus, .btn-linkedin.focus {
box-shadow: 0 0 0 3px rgba(0, 123, 182, 0.5); }
.btn-linkedin.disabled, .btn-linkedin:disabled {
background-color: #007bb6;
border-color: #007bb6; }
.btn-linkedin:active, .btn-linkedin.active, .show > .btn-linkedin.dropdown-toggle {
background-color: #006190;
background-image: none;
border-color: #005983; }
.btn-microsoft {
color: #fff;
background-color: #2672ec;
border-color: #2672ec; }
.btn-microsoft:hover {
color: #fff;
background-color: #135fd9;
border-color: #125acd; }
.btn-microsoft:focus, .btn-microsoft.focus {
box-shadow: 0 0 0 3px rgba(38, 114, 236, 0.5); }
.btn-microsoft.disabled, .btn-microsoft:disabled {
background-color: #2672ec;
border-color: #2672ec; }
.btn-microsoft:active, .btn-microsoft.active, .show > .btn-microsoft.dropdown-toggle {
background-color: #135fd9;
background-image: none;
border-color: #125acd; }
.btn-odnoklassniki {
color: #fff;
background-color: #f4731c;
border-color: #f4731c; }
.btn-odnoklassniki:hover {
color: #fff;
background-color: #df600b;
border-color: #d35b0a; }
.btn-odnoklassniki:focus, .btn-odnoklassniki.focus {
box-shadow: 0 0 0 3px rgba(244, 115, 28, 0.5); }
.btn-odnoklassniki.disabled, .btn-odnoklassniki:disabled {
background-color: #f4731c;
border-color: #f4731c; }
.btn-odnoklassniki:active, .btn-odnoklassniki.active, .show > .btn-odnoklassniki.dropdown-toggle {
background-color: #df600b;
background-image: none;
border-color: #d35b0a; }
.btn-openid {
color: #111;
background-color: #f7931e;
border-color: #f7931e; }
.btn-openid:hover {
color: #111;
background-color: #e78008;
border-color: #da7908; }
.btn-openid:focus, .btn-openid.focus {
box-shadow: 0 0 0 3px rgba(247, 147, 30, 0.5); }
.btn-openid.disabled, .btn-openid:disabled {
background-color: #f7931e;
border-color: #f7931e; }
.btn-openid:active, .btn-openid.active, .show > .btn-openid.dropdown-toggle {
background-color: #e78008;
background-image: none;
border-color: #da7908; }
.btn-pinterest {
color: #fff;
background-color: #cb2027;
border-color: #cb2027; }
.btn-pinterest:hover {
color: #fff;
background-color: #aa1b21;
border-color: #9f191f; }
.btn-pinterest:focus, .btn-pinterest.focus {
box-shadow: 0 0 0 3px rgba(203, 32, 39, 0.5); }
.btn-pinterest.disabled, .btn-pinterest:disabled {
background-color: #cb2027;
border-color: #cb2027; }
.btn-pinterest:active, .btn-pinterest.active, .show > .btn-pinterest.dropdown-toggle {
background-color: #aa1b21;
background-image: none;
border-color: #9f191f; }
.btn-reddit {
color: #111;
background-color: #eff7ff;
border-color: #eff7ff; }
.btn-reddit:hover {
color: #111;
background-color: #c9e4ff;
border-color: #bcdeff; }
.btn-reddit:focus, .btn-reddit.focus {
box-shadow: 0 0 0 3px rgba(239, 247, 255, 0.5); }
.btn-reddit.disabled, .btn-reddit:disabled {
background-color: #eff7ff;
border-color: #eff7ff; }
.btn-reddit:active, .btn-reddit.active, .show > .btn-reddit.dropdown-toggle {
background-color: #c9e4ff;
background-image: none;
border-color: #bcdeff; }
.btn-soundcloud {
color: #fff;
background-color: #ff5500;
border-color: #ff5500; }
.btn-soundcloud:hover {
color: #fff;
background-color: #d94800;
border-color: #cc4400; }
.btn-soundcloud:focus, .btn-soundcloud.focus {
box-shadow: 0 0 0 3px rgba(255, 85, 0, 0.5); }
.btn-soundcloud.disabled, .btn-soundcloud:disabled {
background-color: #ff5500;
border-color: #ff5500; }
.btn-soundcloud:active, .btn-soundcloud.active, .show > .btn-soundcloud.dropdown-toggle {
background-color: #d94800;
background-image: none;
border-color: #cc4400; }
.btn-tumblr {
color: #fff;
background-color: #2c4762;
border-color: #2c4762; }
.btn-tumblr:hover {
color: #fff;
background-color: #203448;
border-color: #1c2e3f; }
.btn-tumblr:focus, .btn-tumblr.focus {
box-shadow: 0 0 0 3px rgba(44, 71, 98, 0.5); }
.btn-tumblr.disabled, .btn-tumblr:disabled {
background-color: #2c4762;
border-color: #2c4762; }
.btn-tumblr:active, .btn-tumblr.active, .show > .btn-tumblr.dropdown-toggle {
background-color: #203448;
background-image: none;
border-color: #1c2e3f; }
.btn-twitter {
color: #fff;
color: #fff;
background-color: #1DA1F2;
border-color: #1DA1F2; }
.btn-twitter:hover {
color: #fff;
background-color: #0d8ddc;
border-color: #0c85d0; }
.btn-twitter:focus, .btn-twitter.focus {
box-shadow: 0 0 0 3px rgba(29, 161, 242, 0.5); }
.btn-twitter.disabled, .btn-twitter:disabled {
background-color: #1DA1F2;
border-color: #1DA1F2; }
.btn-twitter:active, .btn-twitter.active, .show > .btn-twitter.dropdown-toggle {
background-color: #0d8ddc;
background-image: none;
border-color: #0c85d0; }
.btn-vimeo {
color: #fff;
background-color: #1ab7ea;
border-color: #1ab7ea; }
.btn-vimeo:hover {
color: #fff;
background-color: #139ecb;
border-color: #1295bf; }
.btn-vimeo:focus, .btn-vimeo.focus {
box-shadow: 0 0 0 3px rgba(26, 183, 234, 0.5); }
.btn-vimeo.disabled, .btn-vimeo:disabled {
background-color: #1ab7ea;
border-color: #1ab7ea; }
.btn-vimeo:active, .btn-vimeo.active, .show > .btn-vimeo.dropdown-toggle {
background-color: #139ecb;
background-image: none;
border-color: #1295bf; }
.btn-vk {
color: #fff;
background-color: #587ea3;
border-color: #587ea3; }
.btn-vk:hover {
color: #fff;
background-color: #4b6b8a;
border-color: #466482; }
.btn-vk:focus, .btn-vk.focus {
box-shadow: 0 0 0 3px rgba(88, 126, 163, 0.5); }
.btn-vk.disabled, .btn-vk:disabled {
background-color: #587ea3;
border-color: #587ea3; }
.btn-vk:active, .btn-vk.active, .show > .btn-vk.dropdown-toggle {
background-color: #4b6b8a;
background-image: none;
border-color: #466482; }
.btn-yahoo {
color: #fff;
background-color: #720e9e;
border-color: #720e9e; }
.btn-yahoo:hover {
color: #fff;
background-color: #590b7b;
border-color: #500a6f; }
.btn-yahoo:focus, .btn-yahoo.focus {
box-shadow: 0 0 0 3px rgba(114, 14, 158, 0.5); }
.btn-yahoo.disabled, .btn-yahoo:disabled {
background-color: #720e9e;
border-color: #720e9e; }
.btn-yahoo:active, .btn-yahoo.active, .show > .btn-yahoo.dropdown-toggle {
background-color: #590b7b;
background-image: none;
border-color: #500a6f; }
.btn-stripe {
color: #fff;
background-color: #1275FF;
border-color: #1275FF; }
.btn-stripe:hover {
color: #fff;
background-color: #0062eb;
border-color: #005dde; }
.btn-stripe:focus, .btn-stripe.focus {
box-shadow: 0 0 0 3px rgba(18, 117, 255, 0.5); }
.btn-stripe.disabled, .btn-stripe:disabled {
background-color: #1275FF;
border-color: #1275FF; }
.btn-stripe:active, .btn-stripe.active, .show > .btn-stripe.dropdown-toggle {
background-color: #0062eb;
background-image: none;
border-color: #005dde; }
.btn-amazon {
color: #232F3E;
color: #111;
background-color: #FF9900;
border-color: #FF9900; }
.btn-amazon:hover {
color: #111;
background-color: #d98200;
border-color: #cc7a00; }
.btn-amazon:focus, .btn-amazon.focus {
box-shadow: 0 0 0 3px rgba(255, 153, 0, 0.5); }
.btn-amazon.disabled, .btn-amazon:disabled {
background-color: #FF9900;
border-color: #FF9900; }
.btn-amazon:active, .btn-amazon.active, .show > .btn-amazon.dropdown-toggle {
background-color: #d98200;
background-image: none;
border-color: #cc7a00; }
.btn-patreon {
color: #052D49;
color: #fff;
background-color: #F96854;
border-color: #F96854; }
.btn-patreon:hover {
color: #fff;
background-color: #f8472f;
border-color: #f73c23; }
.btn-patreon:focus, .btn-patreon.focus {
box-shadow: 0 0 0 3px rgba(249, 104, 84, 0.5); }
.btn-patreon.disabled, .btn-patreon:disabled {
background-color: #F96854;
border-color: #F96854; }
.btn-patreon:active, .btn-patreon.active, .show > .btn-patreon.dropdown-toggle {
background-color: #f8472f;
background-image: none;
border-color: #f73c23; }
.btn-untappd {
color: #111;
background-color: #ffc000;
border-color: #ffc000; }
.btn-untappd:hover {
color: #111;
background-color: #d9a300;
border-color: #cc9a00; }
.btn-untappd:focus, .btn-untappd.focus {
box-shadow: 0 0 0 3px rgba(255, 192, 0, 0.5); }
.btn-untappd.disabled, .btn-untappd:disabled {
background-color: #ffc000;
border-color: #ffc000; }
.btn-untappd:active, .btn-untappd.active, .show > .btn-untappd.dropdown-toggle {
background-color: #d9a300;
background-image: none;
border-color: #cc9a00; }
.btn-gitlab {
color: #fff;
background-color: #de7e00;
border-color: #de7e00; }
.btn-gitlab:hover {
color: #fff;
background-color: #b86800;
border-color: #ab6100; }
.btn-gitlab:focus, .btn-gitlab.focus {
box-shadow: 0 0 0 3px rgba(222, 126, 0, 0.5); }
.btn-gitlab.disabled, .btn-gitlab:disabled {
background-color: #de7e00;
border-color: #de7e00; }
.btn-gitlab:active, .btn-gitlab.active, .show > .btn-gitlab.dropdown-toggle {
background-color: #b86800;
background-image: none;
border-color: #ab6100; }
.btn-whatsapp {
color: #fff;
color: #fff;
background-color: #25D366;
border-color: #25D366; }
.btn-whatsapp:hover {
color: #fff;
background-color: #1fb256;
border-color: #1da851; }
.btn-whatsapp:focus, .btn-whatsapp.focus {
box-shadow: 0 0 0 3px rgba(37, 211, 102, 0.5); }
.btn-whatsapp.disabled, .btn-whatsapp:disabled {
background-color: #25D366;
border-color: #25D366; }
.btn-whatsapp:active, .btn-whatsapp.active, .show > .btn-whatsapp.dropdown-toggle {
background-color: #1fb256;
background-image: none;
border-color: #1da851; }
/*# sourceMappingURL=bootstrap-social.css.map */
================================================
FILE: app/assets/stylesheets/general.css
================================================
body {
padding-top: 70px;
}
================================================
FILE: app/assets/stylesheets/home.scss.erb
================================================
// Place all the styles related to the Home controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
:root {
--input-padding-x: .75rem;
--input-padding-y: .75rem;
}
html,
body {
height: 100%;
}
@import url(https://fonts.googleapis.com/css?family=Roboto:300);
@import url(https://fonts.googleapis.com/css?family=Lato:300);
.home {
display: -ms-flexbox;
display: -webkit-box;
display: flex;
-ms-flex-align: center;
-ms-flex-pack: center;
-webkit-box-align: center;
align-items: center;
-webkit-box-pack: center;
justify-content: center;
padding-top: 40px;
padding-bottom: 40px;
font-family: 'Roboto', sans-serif;
font-size: 16px;
font-weight: 300;
color: white;
line-height: 30px;
text-align: center;
background-image: image-url('bg.jpeg');
background-size: cover;
background-repeat: no-repeat;
background-color: #444444;
background-position: 50%;
}
.form-signin {
width: 100%;
max-width: 420px;
padding: 15px;
margin: 0 auto;
}
.token-qr table {
border-width: 0;
border-style: none;
border-color: #0000ff;
border-collapse: collapse;
}
.token-qr td {
border-left: solid 5px #000;
padding: 0;
margin: 0;
width: 0px;
height: 5px;
}
.token-qr td.black { border-color: #000; }
.token-qr td.white { border-color: #fff; }
================================================
FILE: app/assets/stylesheets/profile.css
================================================
/* Everything but the jumbotron gets side spacing for mobile first views */
.container-profile {
max-width: 730px;
min-width: 768px;
}
================================================
FILE: app/assets/stylesheets/scaffolds.scss
================================================
body {
background-color: #fff;
color: #333;
font-family: verdana, arial, helvetica, sans-serif;
font-size: 13px;
line-height: 18px;
}
p, ol, ul, td {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 13px;
line-height: 18px;
}
pre {
background-color: #eee;
padding: 10px;
font-size: 11px;
}
a {
color: #000;
&:visited {
color: #666;
}
&:hover {
color: #fff;
background-color: #000;
}
}
div {
&.field, &.actions {
margin-bottom: 10px;
}
}
#notice {
color: green;
}
.field_with_errors {
padding: 2px;
background-color: red;
display: table;
}
#error_explanation {
width: 450px;
border: 2px solid red;
padding: 7px;
padding-bottom: 0;
margin-bottom: 20px;
background-color: #f0f0f0;
h2 {
text-align: left;
font-weight: bold;
padding: 5px 5px 5px 15px;
font-size: 12px;
margin: -7px;
margin-bottom: 0px;
background-color: #c00;
color: #fff;
}
ul li {
font-size: 12px;
list-style: square;
}
}
================================================
FILE: app/clients/data_dog_client.rb
================================================
class DataDogClient
include HTTParty
base_uri 'https://api.datadoghq.com/api/v1'
def initialize(app_key, api_key)
@base_path = 'https://api.datadoghq.com/api/v1'
@app_key = app_key
@api_key = api_key
@headers = {
'Content-Type' => 'application/json',
'Accept' => 'application/json',
}
end
def get_user(email)
url = append_auth("/user/#{email}")
response = self.class.get(url, headers: @headers)
if response.success?
JSON.parse(response.body)['user']
else
{}
end
end
def new_user(email)
url = append_auth('/user')
response = self.class.post(url, body: { handle: email }.to_json, headers: @headers)
if response.success?
JSON.parse(response.body)['user']
else
{}
end
end
def activate_user(email)
url = append_auth("/user/#{email}")
response = self.class.put(url, body: { email: email, disabled: false }.to_json, headers: @headers)
if response.success?
JSON.parse(response.body)['user']
else
{}
end
end
def deactivate_user(email)
url = append_auth("/user/#{email}")
response = self.class.put(url, body: { email: email, disabled: true }.to_json, headers: @headers)
if response.success?
JSON.parse(response.body)['user']
else
{}
end
end
private
def append_auth(str)
auth_str = "api_key=#{@api_key}&application_key=#{@app_key}"
str += str.include?('?') ? "&#{auth_str}" : "?#{auth_str}"
str
end
end
================================================
FILE: app/controllers/admin_controller.rb
================================================
class AdminController < ApplicationController
def index; end
end
================================================
FILE: app/controllers/api/v1/base_controller.rb
================================================
class ::Api::V1::BaseController < ActionController::Base
protect_from_forgery with: :null_session
before_action :authenticate_user_from_token!
def authenticate_user_from_token!
if get_token.nil? || !AccessToken.valid_token(get_token)
raise_unauthorized
end
end
protected
def current_user
access_token = AccessToken.find_token(get_token)
access_token.user
end
private
def get_token
if params.key?(:access_token)
params[:access_token]
elsif params.key?(:token)
params[:token]
elsif request.headers.key?(:Authorization)
request.headers[:Authorization].split(' ').last
end
end
def raise_unauthorized
head :unauthorized
end
end
================================================
FILE: app/controllers/api/v1/endpoints_controller.rb
================================================
class ::Api::V1::EndpointsController < ::Api::V1::BaseController
before_action :authorize_user
def create
endpoint = Endpoint.new(endpoint_param)
if endpoint.save
render json: {
id: endpoint.id,
path: endpoint.path,
method: endpoint.method,
}
else
render json: { status: endpoint.errors }, status: :unprocessable_entity
end
end
def add_group
endpoint = Endpoint.find_by(id: params[:id])
if endpoint.nil?
return head :not_found
end
group = Group.find_by(group_param)
group_endpoint = GroupEndpoint.new(group: group, endpoint: endpoint)
if group_endpoint.save
render json: {}
else
head :unprocessable_entity
end
end
private
def authorize_user
unless current_user.admin?
head :forbidden
end
end
def group_param
params.require(:group).permit(:id)
end
def endpoint_param
params.require(:endpoint).permit(:path, :method)
end
end
================================================
FILE: app/controllers/api/v1/groups_controller.rb
================================================
class ::Api::V1::GroupsController < ::Api::V1::BaseController
def create
if current_user.admin?
@group = Group.new(group_params)
if @group.save
render json: {
id: @group.id,
name: @group.name,
}, status: :ok
else
is_taken = @group.errors.details[:name].select { |x| x[:error] == :taken }
if !is_taken.blank?
existing_group = Group.find_by(name: @group.name)
render json: {
status: 'group already exist',
id: existing_group.id,
name: existing_group.name,
}, status: :unprocessable_entity
else
render json: {
status: 'error',
}, status: :unprocessable_entity
end
end
end
end
def add_user
@group = Group.find_by(id: params[:id])
return head :not_found unless @group.present?
return raise_unauthorized unless current_user.admin? || @group.admin?(current_user)
user = User.find_by(id: params[:user_id])
return head :unprocessable_entity unless user.present?
expiration_date = params[:expiration_date]
@group.add_user_with_expiration(params[:user_id], expiration_date)
head :no_content
end
private
def group_params
params.require(:group).permit(:name)
end
end
================================================
FILE: app/controllers/api/v1/users_controller.rb
================================================
class ::Api::V1::UsersController < ::Api::V1::BaseController
before_action :set_user, only: %i[show update]
def create
return head :forbidden unless current_user.admin?
user = user_params
if User.add_temp_user user[:name], user[:email]
render json: { status: 'created' }, status: :ok
else
render json: { status: 'error' }, status: :unprocessable_entity
end
end
def show
if @user.present?
user_attrs = %w(
email id uid name active admin home_dir shell public_key user_login_id
product_name
)
data = @user.attributes.select { |k, _v| user_attrs.include?(k) }
data['groups'] = @user.groups.map { |g| { 'id' => g.gid, 'name' => g.name } }
render json: data
else
head :not_found
end
end
def deactivate
endpoint = Endpoint.find_by(path: api_v1_deactivate_user_path(':id'), method: 'PATCH')
if !current_user.admin? && !current_user.permitted_endpoint?(endpoint)
return head :forbidden
end
user = User.find_by(id: params[:id])
return head :not_found if user.nil?
user.active = false
if user.save
head :no_content
else
head :unprocessable_entity
end
end
def update
return raise_unauthorized unless current_user.admin? || current_user == @user
render json: { success: @user.update_profile(user_params) }
end
private
def set_user
@user = if params.key?('email')
User.find_by_email(params['email'])
elsif params.key?('uid')
User.find_by_uid(params['uid'])
elsif params.key?('username')
if params.key?('active')
is_active = [1, true, '1', 'true'].include?(params['active'])
User.where(user_login_id: params['username'], active: is_active).take
else
User.find_by_user_login_id(params['username'])
end
end
end
def user_params
if params.key?(:user)
params.require(:user).permit(:name, :email, :public_key, :product_name)
else
params.permit(:name, :email, :public_key, :product_name)
end
end
end
================================================
FILE: app/controllers/api/v1/vpns_controller.rb
================================================
class ::Api::V1::VpnsController < ::Api::V1::BaseController
before_action :set_vpn, only: [:assign_group]
def create
if current_user.admin?
@vpn = Vpn.new(vpn_params)
@vpn.uuid = SecureRandom.uuid
if @vpn.save
render json: {
id: @vpn.id,
name: @vpn.name,
host_name: @vpn.host_name,
ip_address: @vpn.ip_address,
}, status: :ok
else
render json: { status: 'error' }, status: :unprocessable_entity
end
end
end
def assign_group
if current_user.admin?
@vpn.groups.delete_all
@vpn.groups << Group.where(id: params[:group_id]).first
render json: { status: 'group assigned' }, status: :ok
end
end
private
def set_vpn
@vpn = Vpn.find(params[:id])
end
def vpn_params
params.require(:vpn).permit(:name, :host_name, :ip_address)
end
end
================================================
FILE: app/controllers/api_resources_controller.rb
================================================
class ApiResourcesController < ApplicationController
before_action :set_api_resource, only: %i[show edit update destroy regenerate_access_key]
before_action :authenticate_user!, except: [:authenticate]
before_action :authorize_user, only: %i[regenerate_access_key destroy update]
# GET /api_resources
# GET /api_resources.json
def index
@api_resources = ApiResource.where(user: current_user) if !current_user.admin
@api_resources = ApiResource.all if current_user.admin
end
# GET /api_resources/1
# GET /api_resources/1.json
def show; end
def authenticate
# this authenticates and tells whether users is able to access this api or not
if ApiResource.authenticate(params[:access_key], params[:access_token])
render json: { result: 0 }, status: :ok
else
render json: { result: 1 }, status: 401
end
end
# GET /api_resources/new
def new
@api_resource = ApiResource.new
end
# GET /api_resources/1/edit
def edit; end
# POST /api_resources
# POST /api_resources.json
def create
@api_resource = ApiResource.new(api_resource_params)
@api_resource.access_key = ROTP::Base32.random_base32
@api_resource.user = current_user
group = Group.create name: "#{@api_resource.name}_api_group"
@api_resource.group = group
group.add_admin current_user
group.save!
respond_to do |format|
if @api_resource.save
format.html { redirect_to api_resource_path(@api_resource.id), notice: 'Api resource was successfully created.', flash: { access_key: @api_resource.access_key } }
format.json { render :show, status: :created, location: @api_resource }
else
format.html { render :new }
format.json { render json: @api_resource.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /api_resources/1
# PATCH/PUT /api_resources/1.json
def update
respond_to do |format|
if @api_resource.update(api_resource_params)
format.html { redirect_to api_resources_path, notice: 'Api resource was successfully updated.' }
format.json { render :show, status: :ok, location: @api_resource }
else
format.html { render :edit }
format.json { render json: @api_resource.errors, status: :unprocessable_entity }
end
end
end
# DELETE /api_resources/1
# DELETE /api_resources/1.json
def destroy
@api_resource.group.destroy if @api_resource.group.present?
@api_resource.destroy
respond_to do |format|
format.html { redirect_to api_resources_url, notice: 'Api resource was successfully destroyed.' }
format.json { head :no_content }
end
end
# GET /api_resources/q=.json
def search
if params[:exact]
@api_resources = ApiResource.where('name LIKE ?', params[:q].to_s)
else
@api_resources = ApiResource.where('name LIKE ?', "%#{params[:q]}%")
end
@api_resources = @api_resources.order('name ASC').limit(20)
data = @api_resources.map { |group| { id: group.id, name: group.name } }
render json: data
end
# GET /api_resources/:id/regenerate_access_key
def regenerate_access_key
@api_resource.access_key = ROTP::Base32.random_base32
respond_to do |format|
if @api_resource.save
format.html { redirect_to api_resource_path(@api_resource.id), notice: 'Access key regenerated.', flash: { access_key: @api_resource.access_key } }
format.json { render :show, status: :ok, location: @api_resource }
else
format.html { redirect_to api_resource_path(@api_resource.id), notice: 'Access key failed to regenerate.' }
format.json { render json: @api_resource.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_api_resource
@api_resource = ApiResource.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def api_resource_params
params.require(:api_resource).permit(:name, :access_key, :description, :user_id, :group_id)
end
def authorize_user
unless current_user.admin? || current_user == @api_resource.user
respond_to do |format|
format.html { redirect_to api_resources_url, notice: 'Unauthorized access' }
format.json { render json: {}, status: :unauthorized }
end
end
end
end
================================================
FILE: app/controllers/application_controller.rb
================================================
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
def render_404
respond_to do |format|
format.html { render file: "#{Rails.root}/public/404", layout: false, status: :not_found }
format.xml { head :not_found }
format.any { head :not_found }
end
end
def authenticate_access_token!
unless AccessToken.valid_token(params[:token])
render_error(['Unauthorized'], :unauthorized)
end
end
def render_error(errors, status = 400)
render 'common/errors', locals: { errors: errors }, status: status
end
end
================================================
FILE: app/controllers/concerns/.keep
================================================
================================================
FILE: app/controllers/groups_controller.rb
================================================
class GroupsController < ApplicationController
before_action :set_group, only: %i[show edit update destroy
add_user add_machine add_vpn add_admin
remove_admin delete_user delete_vpn delete_machine]
before_action :authenticate_user!
def index
@groups = []
@group_search = params[:group_search]
if current_user.admin && @group_search.present?
@groups = Group.where('name LIKE ?', "%#{@group_search}%")
elsif current_user.group_admin? && !current_user.admin
@groups = GroupAdmin.where(user_id: current_user.id).map(&:group)
end
end
def create
if current_user.admin?
@group = Group.new(group_params)
respond_to do |format|
if @group.save
format.html { redirect_to group_path(@group), notice: 'Group was successfully created.' }
format.json { render status: :created, json: "#{@group.name}host created" }
else
format.html { redirect_to groups_path, notice: "Can't save '#{group_params[:name]}'" }
format.json { render status: :error, json: "#{@group.name} not created" }
end
end
else
format.html { redirect_to groups_path, notice: "Can't save '#{group_params[:name]}'" }
format.json { render status: :error, json: "#{@group.name} not created" }
end
end
def new
@group = Group.new
end
def show
@group_users = User.
select(%Q{
users.id AS id,
name,
email,
active,
group_associations.created_at AS join_date,
group_associations.expiration_date AS group_expiration_date
}).
joins('LEFT OUTER JOIN group_associations ON users.id = group_associations.user_id').
where('group_associations.group_id = ?', @group.id)
end
def delete_machine
@machine = HostMachine.find(params[:host_machine_id])
if current_user.admin?
@machine.groups.delete(@group)
end
redirect_to group_path @group
end
def delete_user
if current_user.admin? || @group.admin?(current_user)
@user = User.find(params[:user_id])
if @user.email.split('@').first != @group.name
@group.remove_user @user
end
end
redirect_to group_path(@group, anchor: 'group_members')
end
def add_user
if current_user.admin? || @group.admin?(current_user)
user = User.find(params[:user_id])
begin
expiration_date = expiration_date_param
rescue ArgumentError
return respond_to do |format|
format.html { redirect_to group_path(@group), notice: 'Expiration date is wrong' }
end
end
@group.add_user_with_expiration(user.id, expiration_date) if user.present?
end
respond_to do |format|
format.html do
redirect_to group_path(@group, anchor: 'group_members')
end
end
end
def add_machine
if current_user.admin?
machine = HostMachine.find(params[:machine_id])
machine.groups << @group if machine.present? && machine.groups.find_by_id(@group.id).blank?
machine.save!
end
respond_to do |format|
format.html do
redirect_to group_path @group
end
end
end
def add_admin
if current_user.admin?
GroupAdmin.find_or_create_by(group_id: @group.id, user_id: params[:user_id])
end
respond_to do |format|
format.html do
redirect_to group_path @group
end
end
end
def remove_admin
if current_user.admin?
GroupAdmin.delete(params[:group_admin_id])
end
respond_to do |format|
format.html do
redirect_to group_path @group
end
end
end
def add_vpn
if current_user.admin?
VpnGroupAssociation.find_or_create_by(group_id: @group.id, vpn_id: params[:vpn_id])
end
respond_to do |format|
format.html do
redirect_to group_path @group
end
end
end
def delete_vpn
return unless current_user.admin? || @group.group_admin.user == current_user
VpnGroupAssociation.where(group_id: @group.id, vpn_id: params[:vpn_id]).destroy_all
VpnGroupUserAssociation.where(group_id: @group.id, vpn_id: params[:vpn_id]).destroy_all
respond_to do |format|
format.html do
redirect_to group_path @group
end
end
end
def add_group
user_id = params[:id]
if current_user.admin?
begin
expiration_date = expiration_date_param
rescue ArgumentError
response_message = 'Expiration date is wrong'
return redirect_to user_path, notice: response_message
end
group = Group.find(params[:group_id])
group.add_user_with_expiration(user_id, expiration_date)
end
redirect_to user_path
end
def delete_group
@user = User.find(params[:user_id])
if current_user.admin?
group = Group.find(params[:id])
if @user.email.split('@').first != group.name
@user.groups.delete(group)
end
end
redirect_to user_path(@user)
end
def list
@groups = []
@group_search = params[:group_search]
return unless @group_search.present?
if current_user.admin?
@groups = Group.where('name LIKE ?', "%#{@group_search}%")
elsif current_user.group_admin?
@groups = GroupAdmin.where(user_id: current_user.id).map(&:group)
end
end
def search
@groups = Group.
where('name LIKE ?', "%#{params[:q]}%").
order('name ASC').
limit(20)
data = @groups.map { |group| { id: group.id, name: group.name } }
render json: data
end
private
# Use callbacks to share common setup or constraints between actions.
def set_group
@group = Group.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def group_params
params.require(:group).permit(:name)
end
def expiration_date_param
expiration_date = params[:expiration_date]
return nil if expiration_date.nil? || expiration_date.empty?
Date.parse(expiration_date, '%Y-%m-%d')
end
end
================================================
FILE: app/controllers/home_controller.rb
================================================
class HomeController < ApplicationController
before_action :check_signed_in
def check_signed_in
redirect_to profile_path if signed_in?
end
def index; end
end
================================================
FILE: app/controllers/host_controller.rb
================================================
class HostController < ApplicationController
before_action :authenticate_user!
def add_host
@user = User.find(params[:id])
if current_user.admin?
host = Host.new
host.user = @user
host.host_pattern = params[:host_pattern]
host.save!
end
redirect_to user_path
end
def delete_host
@user = User.find(params[:user_id])
if current_user.admin?
@host = Host.find(params[:id])
@host.deleted_by = current_user.id
@host.save!
@host.destroy
end
redirect_to user_path(@user)
end
end
================================================
FILE: app/controllers/host_machine_groups_controller.rb
================================================
class HostMachineGroupsController < ApplicationController
def show
@host_machines = HostMachine.all
end
def create
@host_machine = HostMachine.new(host_machine_params)
respond_to do |format|
@host_machine.save
format.html { redirect_to :show, notice: 'host_machine was successfully created.' }
format.json { render status: :created, json: "#{@host_machine.name}host created" }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_host_machine
@host_machine = host_machine.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def host_machine_params
params.require(:host_machine).permit(:name)
end
end
================================================
FILE: app/controllers/host_machines_controller.rb
================================================
class HostMachinesController < ApplicationController
before_action :set_host_machine, only: %i[add_group show edit update destroy delete_group]
before_action :authenticate_user!
before_action :authorize_user, only: %i[delete_group update]
def index
@title = 'Host'
@host_machines = HostMachine.all
@host_machines = []
@host_machine_search = params[:host_machine_search]
if @host_machine_search.present?
if current_user.admin?
@host_machines = HostMachine.where('name LIKE ?', "%#{@host_machine_search}%")
end
end
end
def create
@host_machine = HostMachine.new(host_machine_params)
respond_to do |format|
if @host_machine.save
format.html { redirect_to host_machines_path, notice: 'Host was successfully created.' }
format.json { render status: :created, json: "#{@host_machine.name}host created" }
else
format.html { redirect_to host_machines_path, notice: "Can't save '#{host_machine_params[:name]}'" }
format.json { render status: :error, json: "#{@host_machine.name} not created" }
end
end
end
def show
@machine = @host_machine
@groups = Group.all
end
def update
@host_machine.update(default_admins: params[:host_machine][:default_admins])
redirect_to host_machine_path @host_machine
end
def add_group
@machine = @host_machine
if current_user.admin?
group = Group.find(params[:group_id])
@machine.groups << group if @machine.present? && @machine.groups.find_by_id(group.id).blank?
@machine.save!
end
respond_to do |format|
format.html do
redirect_to host_machine_path @host_machine
end
end
end
def delete_group
group = Group.find(params[:group_id])
@host_machine.groups.delete(group)
@host_machine.save!
redirect_to host_machine_path @host_machine
end
def search
@host_machines = HostMachine.
where('name LIKE ?', "%#{params[:q]}%").
order('name ASC').
limit(20)
data = @host_machines.map { |host_machine| { id: host_machine.id, name: host_machine.name } }
render json: data
end
private
# Use callbacks to share common setup or constraints between actions.
def set_host_machine
@host_machine = HostMachine.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def host_machine_params
params.require(:host_machine).permit(:name)
end
def authorize_user
unless current_user.admin?
redirect_to host_machines_path, notice: 'Unauthorized access'
end
end
end
================================================
FILE: app/controllers/nss_controller.rb
================================================
class NssController < ApplicationController
skip_before_action :verify_authenticity_token, only: %i[add_host add_user_to_group]
before_action :authenticate_access_token!, only: %i[add_host]
def host
token = AccessToken.valid_token params[:token]
@response = nil
if token
@response = HostMachine.get_group_response(params[:name]) if params[:name].present?
render json: @response
return
end
host_machine = HostMachine.find_by(access_key: params[:token])
sysadmins = host_machine.sysadmins if host_machine.present?
if sysadmins.present? && sysadmins.count.positive?
@response = Group.get_sysadmins_and_groups sysadmins, host_machine.default_admins
end
render json: @response
nil
end
def add_host
if params[:name].present?
host = HostMachine.find_or_create_by(name: params[:name])
host.default_admins = params[:default_admins]
host.save
host.add_host_group(params[:name])
host.add_group(params[:group_name])
render 'add_host', locals: { host: host }, format: :json
else
errors = ['Name can\'t be blank']
if params.key?(:group_name) && params[:group_name].blank?
errors << 'Group Name can\'t be blank'
end
render_error(errors)
end
end
def group
@response = REDIS_CACHE.get("#{GROUP_RESPONSE}:#{params[:token]}")
@response = JSON.parse(@response) if @response.present?
if @response.blank?
host_machine = HostMachine.find_by(access_key: params[:token])
sysadmins = host_machine.sysadmins if host_machine.present?
if sysadmins.present? && sysadmins.count.positive?
@response = Group.get_sysadmins_and_groups sysadmins, host_machine.default_admins
REDIS_CACHE.set("#{GROUP_RESPONSE}:#{params[:token]}", @response.to_json)
REDIS_CACHE.expire("#{GROUP_RESPONSE}:#{params[:token]}", REDIS_KEY_EXPIRY)
end
end
render json: @response
end
def passwd
@response = REDIS_CACHE.get("#{PASSWD_RESPONSE}:#{params[:token]}")
@response = JSON.parse(@response) if @response.present?
if @response.blank?
host_machine = HostMachine.find_by(access_key: params[:token])
sysadmins = host_machine.sysadmins if host_machine.present?
if sysadmins.present? && sysadmins.count.positive?
@response = User.get_sysadmins sysadmins
REDIS_CACHE.set("#{PASSWD_RESPONSE}:#{params[:token]}", @response.to_json)
REDIS_CACHE.expire("#{PASSWD_RESPONSE}:#{params[:token]}", REDIS_KEY_EXPIRY)
end
end
render json: @response
end
def shadow
token = AccessToken.valid_token params[:token]
@response = nil
if token
name = params[:name]
if name.present?
@response = REDIS_CACHE.get(SHADOW_NAME_RESPONSE + name)
if @response.blank?
@response = User.get_shadow_name_response(name).to_json
REDIS_CACHE.set(SHADOW_NAME_RESPONSE + name, @response)
REDIS_CACHE.expire(SHADOW_NAME_RESPONSE + name, REDIS_KEY_EXPIRY)
end
else
@response = REDIS_CACHE.get(SHADOW_ALL_RESPONSE)
if @response.blank?
@response = User.get_all_shadow_response.to_json
REDIS_CACHE.set(SHADOW_ALL_RESPONSE, @response)
REDIS_CACHE.expire(SHADOW_ALL_RESPONSE, REDIS_KEY_EXPIRY)
end
end
end
render json: @response
end
def groups_list
token = AccessToken.valid_token params[:token]
if token
user = User.get_user(params[:email].split('@').first)
if user.blank?
render json: { success: false }
else
groups = user.blank? ? [] : user.group_names_list
render json: { success: true, groups: groups }
end
else
render json: { success: false }
end
end
end
================================================
FILE: app/controllers/organisations_controller.rb
================================================
class OrganisationsController < ApplicationController
before_action :authorize_user, except: [:index]
before_action :load_org, only: %i(
config_saml_app update show setup_saml save_config_saml_app
remove_user_saml_app add_user_saml_app
)
before_action :validate_app_name, only: %i(
config_saml_app save_config_saml_app
remove_user_saml_app add_user_saml_app
)
def index
render :index, locals: { org_list: Organisation.all }
end
def new
render :new, locals: { org: Organisation.new }
end
def config_saml_app
app_name = params[:app_name]
saml_app = app_name.titleize.constantize.new(@org.id)
config = saml_app.config
users = config.persisted? ? config.group.users : []
render :config_saml_app, locals: {
org: @org,
saml_config: config,
app_name: app_name,
users: users,
}
end
def save_config_saml_app
app_name = params[:app_name]
saml_app_config = params[:saml_app_config]
saml_app = app_name.titleize.constantize.new(@org.id)
saml_app.save_config(saml_app_config[:sso_url], params[:config])
flash[:success] = 'Configuration saved successfully'
redirect_to organisation_config_saml_app_path(
app_name: app_name,
organisation_id: @org.id
)
end
def remove_user_saml_app
app_name = params[:app_name]
saml_app = app_name.titleize.constantize.new(@org.id)
if saml_app.remove_user(params[:email])
flash[:success] = 'User removed successfullly'
else
flash[:error] = 'Issue removing the user'
end
redirect_to organisation_config_saml_app_path
end
def add_user_saml_app
app_name = params[:app_name]
saml_app = app_name.titleize.constantize.new(@org.id)
if saml_app.add_user(params[:email])
flash[:success] = 'User added successfullly'
else
flash[:error] = 'Issue adding the user'
end
redirect_to organisation_config_saml_app_path
end
def create
org = Organisation.setup(organisation_params.to_h || {})
if org.errors.blank?
flash[:success] = 'Successfully created organisation'
redirect_to organisations_path
else
flash[:errors] = org.errors.full_messages
render :new, locals: { org: org }
end
end
def update
@org.update_profile(organisation_params.to_h || {})
if @org.errors.blank?
flash[:success] = 'Successfully updated organisation'
redirect_to organisations_path
else
flash[:errors] = @org.errors.full_messages
render :show, locals: { org: @org }
end
end
def show
render :show, locals: { org: @org }
end
def setup_saml
if @org.saml_setup?
flash[:errors] = 'SAML Certificates Already Setup'
else
@org.setup_saml_certs
flash[:success] = 'Successfully setup SAML Certificates'
end
redirect_to organisations_path
end
private
def authorize_user
unless current_user.admin?
respond_to do |format|
format.html { redirect_to organisations_path, notice: 'Unauthorized access' }
format.json { render json: {}, status: :unauthorized }
end
end
end
def load_org
id = params[:id] || params[:organisation_id]
@org = Organisation.where(id: id).first
if @org.blank?
redirect_to organisations_path
end
end
def validate_app_name
saml_apps = ENV['SAML_APPS'].split(',').map(&:downcase)
unless saml_apps.include?(params[:app_name].downcase)
redirect_to organisation_path(id: params[:organisation_id])
end
end
def organisation_params
params.require(:organisation).permit(
:name, :website, :domain, :country, :state, :address, :admin_email_address,
:slug, :unit_name
)
end
end
================================================
FILE: app/controllers/pings_controller.rb
================================================
class PingsController < ApplicationController
def show
render plain: 'pong'
end
end
================================================
FILE: app/controllers/profile_controller.rb
================================================
class ProfileController < ApplicationController
require 'vpn/mobileconfig'
skip_before_action :verify_authenticity_token, if: Proc.new { |c| c.request.format == 'application/json' }
before_action :authenticate_user!, except: %i[user_id verify authenticate authenticate_cas authenticate_ms_chap authenticate_pam public_key]
def regen_auth
current_user.generate_two_factor_auth(true)
redirect_to profile_path
end
def show
@token_qr = nil
unless current_user.provisioning_uri.blank?
@token_qr = RQRCode::QRCode.new(current_user.provisioning_uri, size: 10, level: :h)
end
end
def user_admin
@users = []
@groups = []
if !current_user.admin?
redirect_to profile_path
end
@user_search = params[:user_search]
if @user_search.present?
@users = User.where('name LIKE ? OR email LIKE ?', "%#{@user_search}%", "%#{@user_search}%").
take(5)
redirect_to profile_list_path(user_search: params[:user_search]) if @users.count.positive?
end
@group_search = params[:group_search]
if @group_search.present?
@groups = Group.where('name LIKE ?', "%#{@group_search}%").take(5)
redirect_to group_list_path(group_search: params[:group_search]) if @groups.count.positive?
end
end
def group_admin
@users = []
@groups = []
if !current_user.admin? && !current_user.group_admin?
redirect_to profile_path
end
@user_search = params[:user_search]
if @user_search.present?
@users = User.where('name LIKE ? OR email LIKE ?', "%#{@user_search}%", "%#{@user_search}%").
take(5)
redirect_to profile_list_path(user_search: params[:user_search]) if @users.count.positive?
end
@group_search = params[:group_search]
if @group_search.present?
@groups = Group.where('name LIKE ?', "%#{@group_search}%").take(5)
redirect_to group_list_path(group_search: params[:group_search]) if @groups.count >= 0
end
end
def user_id
token = AccessToken.valid_token params[:token]
response = 0
if token
user = User.get_user(params[:name])
response = user.uid if user.present?
end
render plain: response
end
def download_vpn
if !Pathname.new("/opt/vpnkeys/#{current_user.email}.tar.gz").exist?
`cd /etc/openvpn/easy-rsa/ && bash /etc/openvpn/easy-rsa/gen-client-keys #{current_user.email}`
else
`cd /etc/openvpn/easy-rsa/ && bash /etc/openvpn/easy-rsa/gen-client-conf #{current_user.email}`
end
send_file(
"/opt/vpnkeys/#{current_user.email}.tar.gz",
type: 'application/zip',
disposition: "attachment; filename=#{current_user.email}.tar.gz"
)
end
def download_vpn_for_ios_and_mac
mobileconfig = Mobileconfig.new
vpns = Vpn.user_vpns current_user
return render plain: "you don't have access to any vpns" unless vpns.present?
mobileconfig_data = mobileconfig.generate(vpns, current_user)
send_data(
mobileconfig_data,
filename: "#{current_user.email}.mobileconfig",
type: 'application/x-apple-aspen-config'
)
end
def download_vpn_for_user
render plain: 'Please download vpn config from your homepage'
end
def authenticate
response = User.authenticate params
if response
render plain: 0
else
render plain: 1
end
end
def authenticate_ms_chap
response = User.ms_chap_auth params
render plain: response
end
def authenticate_cas
username = User.authenticate_cas request.env['HTTP_AUTHORIZATION']
## cas-5.2.x expects {"@c":".SimplePrincipal","id":"casuser","attributes":{}}
response_map = {
'@class': 'org.apereo.cas.authentication.principal.SimplePrincipal',
'id': username,
'attributes': { 'backend': 'gate-sso' },
}
if username.present?
render json: response_map, status: :ok
else
response_map['attributes'] = nil
render json: response_map, status: 401
end
end
def authenticate_pam
response = User.authenticate_pam params
if response
render plain: 0
else
render plain: 1
end
end
def verify
token = AccessToken.valid_token params[:token]
if token
response = User.verify params
if response
render plain: 0
else
render plain: 1
end
else
render plain: 1
end
end
def list
@users = []
@user_search = params[:user_search]
if @user_search.present?
@users = User.where('name LIKE ? OR email LIKE ?', "%#{@user_search}%", "%#{@user_search}%").
take(5)
end
end
def admin
@users = []
@groups = []
if !current_user.admin?
redirect_to profile_path
end
@user_search = params[:user_search]
if @user_search.present?
@users = User.where('name LIKE ? OR email LIKE ?', "%#{@user_search}%", "%#{@user_search}%").
take(5)
redirect_to profile_list_path(user_search: params[:user_search]) if @users.count.positive?
end
@group_search = params[:group_search]
if @group_search.present?
@groups = Group.where('name LIKE ?', "%#{@group_search}%").take(5)
redirect_to group_list_path(group_search: params[:group_search]) if @groups.count.positive?
end
end
def update
if current_user.admin?
@user = User.find(params[:id])
@user.update(admin_active)
end
redirect_to user_path
end
def user_edit; end
def public_key_update
@user = User.where(id: params[:id]).first
if current_user.admin? || current_user.id == @user.id
@user.public_key = params[:public_key]
@user.save!
end
redirect_to user_path
end
def public_key
public_key = ''
@user = User.get_user(params[:name])
public_key = @user.public_key if @user.present?
render plain: public_key
end
def user
@group = Group.all
@user = User.where(id: params[:id]).first
if !current_user.admin? && current_user.id != @user.id
redirect_to profile_path
end
render_404 if @user.blank?
if @user.present?
# hack add blank text to public_key
@user.public_key = 'Add public key' if @user.public_key.blank?
respond_to do |format|
format.html
end
end
end
protected
def admin_active
params.require(:user).permit(:active, :admin)
end
end
================================================
FILE: app/controllers/saml_idp_controller.rb
================================================
#TODO rename back to SAMLController
#class SamlIdpController < SamlIdp::IdpController
class SamlIdpController < ApplicationController
layout false
before_action :setup_saml_configuration
def show
xml_content = SamlIdp.metadata.signed
if params.key?(:download)
send_data xml_content,
type: 'text/xml',
filename: 'metadata.xml'
else
render xml: xml_content
end
end
private
def idp_authenticate(email, password)
user = User.find_and_validate_saml_user(email, password, params[:app])
user.present? ? user : nil
end
def idp_make_saml_response(found_user)
encode_response found_user
end
def idp_logout
# user = User.by_email(saml_request.name_id)
# user.logout
end
def setup_saml_configuration
slug = params[:slug]
app = params[:app]
org = Organisation.find_by_slug(slug)
saml_url = "#{ENV['GATE_SERVER_URL']}/#{slug}/#{app}/saml"
SamlIdp.configure do |config|
config.x509_certificate = org.cert_key
config.secret_key = org.cert_private_key
config.organization_name = org.name
config.organization_url = org.website
config.base_saml_location = saml_url
config.session_expiry = 86400
config.name_id.formats = {
email_address: ->(principal) { principal.email },
transient: ->(principal) { principal.user_login_id },
persistent: ->(principal) { principal.user_login_id },
name: ->(principal) { principal.name },
}
config.attributes = {
'eduPersonPrincipalName' => {
'name' => 'urn:oid:1.3.6.1.4.1.5923.1.1.1.6',
'name_format' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
'getter' => ->(principal) { principal.email },
},
}
config.attribute_service_location = "#{saml_url}/attributes"
config.single_service_post_location = "#{saml_url}/auth"
config.single_logout_service_post_location = "#{saml_url}/logout"
config.single_logout_service_redirect_location = "#{saml_url}/logout"
end
end
end
================================================
FILE: app/controllers/users/auth_controller.rb
================================================
class Users::AuthController < ApplicationController
def log_in
unless ENV['SIGN_IN_TYPE'] == 'form'
return redirect_to root_path
end
email = params.require(:email)
name = params.require(:name)
unless User.valid_domain? email.split('@').last
return render plain: 'Your domain is unauthorized', status: :unauthorized
end
user = User.create_user(name, email)
user.generate_two_factor_auth
sign_in_and_redirect user, event: :authentication
end
end
================================================
FILE: app/controllers/users/omniauth_callbacks_controller.rb
================================================
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def google_oauth2
# You need to implement the method below in your model (e.g. app/models/user.rb)
#
data = request.env['omniauth.auth']
domain = data['info']['email'].split('@').last
unless User.valid_domain? domain
return render plain: 'Your domain is unauthorized', status: :unauthorized
end
@user = User.create_user(data.info['name'], data.info['email'])
if @user.persisted?
@user.generate_two_factor_auth
sign_in_and_redirect @user, event: :authentication
else
session['devise.google_data'] = request.env['omniauth.auth']
redirect_to new_user_registration_url
end
end
end
================================================
FILE: app/controllers/users_controller.rb
================================================
class UsersController < ApplicationController
before_action :authenticate_user!, except: %i[user_id verify authenticate authenticate_cas authenticate_ms_chap authenticate_pam public_key]
before_action :authorize_user, only: %i[create update]
def index
@user_search = params[:user_search]
@users = []
@users = User.where('name like ?', "%#{@user_search}%").take(20) if @user_search.present?
end
def show
@user = User.where(id: params[:id]).first
return render_404 if @user.blank?
@user_groups = Group.
select(%{
groups.id AS id,
gid,
name,
deleted_at,
group_associations.expiration_date AS group_expiration_date
}).
joins('INNER JOIN group_associations ON groups.id = group_associations.group_id').
where('group_associations.user_id = ?', @user.id)
if @user.access_token.blank?
access_token = AccessToken.new
access_token.token = ROTP::Base32.random_base32
access_token.user = @user
access_token.save!
end
@vpns = Vpn.user_vpns @user
return unless current_user.admin? || current_user == @user
return unless @user.present? && (current_user.admin? || current_user.id == @user.id)
respond_to do |format|
format.html { render :show, flash: { token: access_token.try(:token) } }
end
end
def new
return redirect_to profile_path unless current_user.admin?
render :new, locals: {
roles: ENV['USER_ROLES'].split(','),
domains: ENV['GATE_HOSTED_DOMAINS'].split(','),
}
end
def create
user = User.add_user(
user_params[:first_name],
user_params[:last_name],
user_params[:user_role],
params[:user_domain]
)
if user.errors.present?
flash[:errors] = user.errors.full_messages
redirect_to(new_user_path)
else
flash[:success] = 'Successfully Created User'
redirect_to user_path(id: user.id)
end
end
def update
@user = User.find(params[:id])
begin
@user.update(product_name: product_name)
response_message = 'product name updated successfully!!'
rescue ActionController::ParameterMissing
response_message = 'Params are missing'
end
form_response(response_message)
end
def search
@users = User.
where('name LIKE :q OR email LIKE :q', q: "%#{params[:q]}%").
order('name ASC').
limit(20)
unless params[:include_inactive] == 'true'
@users = @users.where(active: true)
end
data = @users.map do |user|
{
id: user.id,
name: user.name,
email: user.email,
name_email: "#{user.name} - #{user.email}",
}
end
render json: data
end
# GET /users/:id/regenerate_token
def regenerate_token
@user = User.find(params[:id])
unless current_user.admin? || (current_user.id == @user.id)
return respond_to do |format|
format.html { redirect_to user_path(@user.id), notice: 'You cannot regenerate this token.' }
format.json { render json: @user.errors, status: :unauthorized }
end
end
@access_token = @user.access_token
@access_token.token = ROTP::Base32.random_base32
respond_to do |format|
if @access_token.save
format.html { redirect_to user_path(@user.id), notice: 'Token regenerated.', flash: { token: @access_token.token } }
format.json { render :show, status: :ok, location: @user }
else
format.html { redirect_to user_path(@user.id), notice: 'Token failed to regenerate.' }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
private
def user_params
params.require(:user).permit(
:first_name, :last_name, :user_role
)
end
def form_response(message)
respond_to do |format|
format.html { redirect_to user_path, notice: message }
end
end
def product_name
params.require(:product_name)
end
def authorize_user
unless current_user.admin?
flash[:errors] = 'unauthorized access'
redirect_to profile_path
end
end
end
================================================
FILE: app/controllers/vpn_domain_name_servers_controller.rb
================================================
class VpnsController < ApplicationController
before_action :authorize_user
before_action :set_vpn, only: %i[show edit update destroy user_associated_groups]
def destroy; end
end
#TODO fix this in future. This is something not great.
class VpnDomainNameServersController < ApplicationController
end
================================================
FILE: app/controllers/vpns_controller.rb
================================================
class VpnsController < ApplicationController
before_action :authorize_user, except: %i[create_group_associated_users show index
user_associated_groups group_associated_users search]
before_action :set_vpn, only: %i[show edit update destroy
user_associated_groups add_dns_server remove_dns_server
add_search_domain remove_search_domain
add_supplemental_match_domain remove_supplemental_match_domain
migrate_to_new_group assign_group]
before_action :authenticate_user!
require 'securerandom'
def index
@vpns = Vpn.order(:name)
end
def update
if current_user.admin?
@vpn = Vpn.find(params[:id])
if @vpn.update(vpn_params)
redirect_to vpn_path(@vpn), notice: 'Vpn was successfully updated.'
end
else
redirect_to vpn_path(@vpn), notice: 'You can not update, not sufficient privileges.'
end
end
def create
@vpn = Vpn.new(vpn_params)
@vpn.uuid = SecureRandom.uuid
respond_to do |format|
if @vpn.save
format.html { redirect_to vpns_path, notice: 'Vpn was successfully added.' }
format.json { render status: :created, json: "#{@vpn.name}host created" }
else
format.html { redirect_to vpns_path, notice: "Can't save '#{vpn_params[:name]}'" }
format.json { render status: :error, json: "#{@vpn.name} not created" }
end
end
end
def new
@vpn = Vpn.new
end
def add_dns_server
if current_user.admin? && params[:server_address].present?
VpnDomainNameServer.find_or_create_by(server_address: params[:server_address], vpn: @vpn)
end
redirect_to vpn_path(@vpn, anchor: 'dns_hosts')
end
def add_search_domain
if current_user.admin? && params[:search_domain].present?
VpnSearchDomain.find_or_create_by(search_domain: params[:search_domain], vpn: @vpn)
end
redirect_to vpn_path(@vpn, anchor: 'search_domains')
end
def add_supplemental_match_domain
if current_user.admin? && params[:supplemental_match_domain].present?
VpnSupplementalMatchDomain.find_or_create_by(
supplemental_match_domain: params[:supplemental_match_domain],
vpn: @vpn
)
end
redirect_to vpn_path(@vpn, anchor: 'match_domains')
end
def remove_dns_server
if current_user.admin?
VpnDomainNameServer.delete(params[:vpn_domain_name_server_id])
end
redirect_to vpn_path(@vpn, anchor: 'dns_hosts')
end
def remove_search_domain
if current_user.admin?
VpnSearchDomain.delete(params[:vpn_search_domain_id])
end
redirect_to vpn_path(@vpn, anchor: 'search_domains')
end
def remove_supplemental_match_domain
if current_user.admin?
VpnSupplementalMatchDomain.delete(params[:vpn_supplemental_match_domain_id])
end
redirect_to vpn_path(@vpn, anchor: 'match_domains')
end
def assign_group
if current_user.admin?
@vpn.groups.delete_all
@vpn.groups << Group.where(id: params[:group_id]).first
end
redirect_to vpn_path(@vpn, anchor: 'match_domains')
end
def show
@vpn = Vpn.find(params[:id])
@groups = Group.order(:name)
end
def user_associated_groups
@groups_under_current_user = []
@group_id = params[:group_id]
@vpn_id = params[:id]
if current_user.admin?
@groups_under_current_user = Group.all
else
@vpn.groups.each do |vpn_group|
if vpn_group.group_admin.try(:user) == current_user
@groups_under_current_user << vpn_group
end
end
end
render 'show'
end
def group_associated_users
@group = Group.find(params[:group_id])
if current_user.admin? || @group.group_admin.try(:user) == current_user
@users = @group.users
@vpn_group_user_associations = VpnGroupUserAssociation.where(
vpn_id: params[:vpn_id],
group_id: params[:group_id]
)
@vpn_enabled_users = @vpn_group_user_associations.map(&:user)
@vpn_disabled_users = @users - @vpn_enabled_users
@vpn_enabled_users = @vpn_enabled_users.sort_by(&:email)
@vpn_disabled_users = @vpn_disabled_users.sort_by(&:email)
end
respond_to do |format|
format.json { render status: :ok, json: { enabled: @vpn_enabled_users, disabled: @vpn_disabled_users } }
end
end
def create_group_associated_users
if current_user.admin? ||
VpnGroupAssociation.find_by_vpn_id_and_group_id(
params[:vpn_id].to_i,
params[:group_id]
).group.group_admin.user == current_user
@users_selected = params[:users] || []
@associations_made = []
VpnGroupUserAssociation.where(
vpn_id: params[:vpn_id].to_i,
group_id: params[:group_id].to_i
).each do |vpn_association|
unless @users_selected.include? vpn_association.user.id
vpn_association.destroy
end
end
@users_selected.each do |user|
@associations_made << VpnGroupUserAssociation.find_or_create_by(
vpn_id: params[:vpn_id],
group_id: params[:group_id],
user_id: user.to_i
)
end
respond_to do |format|
format.json { render status: :ok, json: @associations_made }
end
else
respond_to do |format|
format.json { render status: :unauthorized, json: 'not gonna happen' }
end
end
end
def destroy
VpnGroupUserAssociation.where(vpn_id: params[:id]).destroy_all
VpnGroupAssociation.where(vpn_id: params[:id]).destroy_all
Vpn.destroy(params[:id])
respond_to do |format|
format.html { redirect_to vpns_path, notice: 'Vpn was successfully destroyed.' }
format.json { render status: :ok, json: 'vpn destroyed' }
end
end
def search
@vpns = Vpn.
where('name LIKE ?', "%#{params[:q]}%").
order('name ASC').
limit(20)
data = @vpns.map { |vpn| { id: vpn.id, name: vpn.name } }
render json: data
end
private
def set_vpn
@vpn = Vpn.find(params[:id])
end
def vpn_params
params.require(:vpn).permit(:name, :host_name, :ip_address)
end
def authorize_user
unless current_user.admin?
redirect_to profile_path
end
end
end
================================================
FILE: app/helpers/admin_helper.rb
================================================
module AdminHelper
end
================================================
FILE: app/helpers/api_resources_helper.rb
================================================
module ApiResourcesHelper
end
================================================
FILE: app/helpers/application_helper.rb
================================================
module ApplicationHelper
def add_placeholder_to_list(list, placeholder, string_convert: 'titleize')
(list.map do |row|
name = string_convert.present? ? row.send(string_convert.to_sym) : row
[name, row]
end).insert(0, [placeholder, ''])
end
end
================================================
FILE: app/helpers/group_helper.rb
================================================
module GroupHelper
end
================================================
FILE: app/helpers/groups_helper.rb
================================================
module GroupsHelper
end
================================================
FILE: app/helpers/home_helper.rb
================================================
module HomeHelper
end
================================================
FILE: app/helpers/host_access_groups_helper.rb
================================================
module HostAccessGroupsHelper
end
================================================
FILE: app/helpers/host_machine_groups_helper.rb
================================================
module HostMachineGroupsHelper
end
================================================
FILE: app/helpers/host_machines_helper.rb
================================================
module HostMachinesHelper
end
================================================
FILE: app/helpers/nss_helper.rb
================================================
module NssHelper
end
================================================
FILE: app/helpers/omniauth_callbacks_helper.rb
================================================
module OmniauthCallbacksHelper
end
================================================
FILE: app/helpers/profile_helper.rb
================================================
module ProfileHelper
end
================================================
FILE: app/helpers/users_helper.rb
================================================
module UsersHelper
end
================================================
FILE: app/lib/datadog.rb
================================================
class Datadog < SamlApp
def initialize(org_id)
@app_name = 'datadog'
super(org_id)
if @config.persisted?
@client = DataDogClient.new(
@config.config['app_key'],
@config.config['api_key']
)
else
@config.config = { app_key: '', api_key: '' }
end
end
def save_config(sso_url, config = {})
@config.config = @config.config.merge(config)
super(sso_url, config)
end
def add_user(email)
user_detail_response = @client.get_user(email)
response = if user_detail_response.eql?({})
@client.new_user(email)
else
@client.activate_user(email)
end
super(email) unless response.eql?({})
end
def remove_user(email)
response = @client.deactivate_user(email)
super(email) unless response.eql?({})
end
end
================================================
FILE: app/lib/saml_app.rb
================================================
class SamlApp
attr_accessor :config, :app_name
def initialize(org_id)
@config = SamlAppConfig.find_or_initialize_by(
app_name: @app_name, organisation_id: org_id
)
end
def save_config(sso_url, config = {})
unless @config.persisted?
group_name = "#{@config.organisation.slug}_saml_#{app_name}_users"
@config.group = Group.find_or_create_by(name: group_name)
end
@config.sso_url = sso_url
@config.save
end
def add_user(email)
user = User.where(email: email).first
unless user.blank?
@config.group.add_user(user.id)
return true
end
false
end
def remove_user(email)
user = User.where(email: email).first
unless user.blank?
@config.group.remove_user(user.id)
return true
end
false
end
end
================================================
FILE: app/mailers/.keep
================================================
================================================
FILE: app/models/.keep
================================================
================================================
FILE: app/models/access_token.rb
================================================
class AccessToken < ApplicationRecord
attr_accessor :token
belongs_to :user
before_save :hash_token!
def self.find_token challenge_token
AccessToken.where(hashed_token: Digest::SHA512.hexdigest(challenge_token)).first
end
def self.valid_token challenge_token
find_token(challenge_token).present?
end
private
def hash_token!
self.hashed_token = Digest::SHA512.hexdigest self.token unless self.token.blank?
end
end
================================================
FILE: app/models/api_resource.rb
================================================
class ApiResource < ApplicationRecord
attr_accessor :access_key
validates :name, format: { with: /\A[a-zA-Z0-9_-]+\Z/ }, uniqueness: true, presence: true
validates :access_key, presence: true, on: :create
belongs_to :user
belongs_to :group
before_save :hash_access_key!
def self.authenticate access_key, access_token
api_resource = ApiResource.find_by(hashed_access_key: Digest::SHA512.hexdigest(access_key))
user = AccessToken.find_by(hashed_token: Digest::SHA512.hexdigest(access_token)).user
api_resource.group.member? user
end
private
def hash_access_key!
self.hashed_access_key = Digest::SHA512.hexdigest self.access_key unless self.access_key.blank?
end
end
================================================
FILE: app/models/application_record.rb
================================================
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
================================================
FILE: app/models/concerns/.keep
================================================
================================================
FILE: app/models/concerns/ms_chap_auth.rb
================================================
module MsChapAuth
def hexlify(msg)
msg.unpack('H*').first
end
def unhexlify(msg)
msg.scan(/../).collect { |c| c.to_i(16).chr }.join
end
def test_key key, challenge
des = OpenSSL::Cipher::DES.new('ECB')
des.encrypt
des.key = key
des.update challenge
#need to do it twice, don't know why!!! :-(
des.update challenge
end
def ntlm_challenge_response word, challenge
uword = word.encode('iso-8859-1').encode('utf-16le')
ntlmhash = md4_hash uword
response = []
response.push(test_key(key56_to_key64(ntlmhash[0...14]), challenge))
response.push(test_key(key56_to_key64(ntlmhash[14...28]), challenge))
response.push(test_key(key56_to_key64(ntlmhash[28...ntlmhash.length] + '0000000000'), challenge))
hexlify(response[0]) + hexlify(response[1]) + hexlify(response[2])
end
def md4_hash word
md4 = OpenSSL::Digest::MD4.new
return md4.hexdigest(word)
end
def set_key_odd_parity key
for pos in 0..key.length - 1
for k in 0..6
bit = 0
t = key[pos] >> k
bit = (t ^ bit) & 0x1
end
key[pos] = (key[pos] & 0xFE) | bit
end
return key
end
def key56_to_key64 key_raw
key_raw = unhexlify(key_raw)
key_56 = []
key_raw.split("").each {|c| key_56.push(c.ord)}
key = []
(0..7).to_a.each {|i| key.push(0)}
key[0] = key_56[0]
key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
key[7] = (key_56[6] << 1) & 0xFF;
key = set_key_odd_parity(key)
keyout = ''
key.each {|k| keyout += k.chr}
return keyout
end
def nt_password_hash password
md4 = OpenSSL::Digest::MD4.new
md4.digest(password)
end
def get_nt_key password
unicode_pwd = password.encode('iso-8859-1').encode('utf-16le')
pwd_hash = nt_password_hash(unicode_pwd)
nt_key = nt_password_hash(pwd_hash)
return hexlify(nt_key)
end
def authenticate_ms_chap password, challenge, response
if ntlm_challenge_response(password, unhexlify(challenge)) == response
return "NT_KEY: " + get_nt_key(password).upcase
end
return ("NT_STATUS_UNSUCCESSFUL: Failure (0xC0000001)")
end
def authenticate_ms_chap_with_drift passwords, challenge, response
passwords.each do |password|
if ntlm_challenge_response(password, unhexlify(challenge)) == response
return "NT_KEY: " + get_nt_key(password).upcase
end
end
return ("NT_STATUS_UNSUCCESSFUL: Failure (0xC0000001)")
end
end
================================================
FILE: app/models/endpoint.rb
================================================
class Endpoint < ApplicationRecord
has_many :group_endpoints
has_many :groups, through: :group_endpoints
validates_presence_of :path
validates_presence_of :method
validates :method, inclusion: { in: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'] }
validates_format_of :path, with: /\A((\/(([0-9, a-z,\-,_]+)|(:[a-z]+))+)+|\/)\Z/i
end
================================================
FILE: app/models/group.rb
================================================
class Group < ApplicationRecord
has_many :group_admins, dependent: :destroy
has_many :group_associations
has_many :users, through: :group_associations
has_many :vpn_group_associations
has_many :vpns, through: :vpn_group_associations
has_many :host_access_groups
has_many :host_machines, through: :host_access_groups
belongs_to :vpn
has_many :group_endpoints
has_many :endpoints, through: :group_endpoints
validates_uniqueness_of :name, case_sensitive: false
validates :name, presence: true
before_create :set_lower_case_name
acts_as_paranoid
after_create :add_gid
GID_CONSTANT = 9000
def burst_host_cache
if host_machines.count.positive?
host_machines.each do |host|
if host.access_key.present?
REDIS_CACHE.del "#{GROUP_RESPONSE}:#{host.access_key}"
REDIS_CACHE.del "#{PASSWD_RESPONSE}:#{host.access_key}"
Rails.logger.info "hello #{host.name} #{host.access_key}"
end
end
end
end
def add_admin(user)
GroupAdmin.find_or_create_by(group_id: id, user: user)
end
def set_lower_case_name
self.name = name.downcase
end
def add_gid
self.gid = id + GID_CONSTANT
save!
end
def self.get_name_response(name)
response = REDIS_CACHE.get(GROUP_NSS_RESPONSE + name)
if response.blank?
group = Group.where(name: name).first
group = [] if group.blank?
response = group.group_response.to_json
REDIS_CACHE.set(GROUP_NSS_RESPONSE + name, response)
REDIS_CACHE.expire(GROUP_NSS_RESPONSE + name, REDIS_KEY_EXPIRY)
end
JSON.parse(response, symbolize_names: true)
end
def self.get_all_response
response = REDIS_CACHE.get(GROUP_ALL_RESPONSE)
if response.blank?
response_array = []
Group.all.includes(:users).each do |group|
response_array << group.group_response
end
response = response_array.to_json
REDIS_CACHE.set(GROUP_ALL_RESPONSE, response)
REDIS_CACHE.expire(GROUP_ALL_RESPONSE, REDIS_KEY_EXPIRY)
end
response
end
def self.get_gid_response(gid)
group = Group.where(gid: gid).first
return [] if group.blank?
group.group_response
end
def admin?(user)
GroupAdmin.where(group_id: self, user_id: user).first.present?
end
def member?(user)
users.exists? user.id
end
def self.generate_group_response(name, gid, members)
{
gr_name: name,
gr_passwd: 'x',
gr_gid: gid,
gr_mem: members,
}
end
def group_response
Group.group_nss_response name
end
def self.group_nss_response(name)
group_response = REDIS_CACHE.get("#{GROUP_NSS_RESPONSE}:#{name}")
group_response = JSON.parse(group_response) if group_response.present?
if group_response.blank?
group = Group.find_by(name: name)
if group.present?
members = group.users.map(&:user_login_id)
response_hash = Group.generate_group_response(group.name, group.gid, members)
REDIS_CACHE.set("#{GROUP_NSS_RESPONSE}:#{group.name}", response_hash.to_json)
REDIS_CACHE.expire("#{GROUP_NSS_RESPONSE}:#{group.name}", REDIS_KEY_EXPIRY)
group_response = response_hash
end
end
group_response
end
def self.get_sysadmins_and_groups(sysadmins, default_admins = true)
sysadmins_login_ids = User.
select(:user_login_id).
where('id IN (?)', sysadmins).
map(&:user_login_id)
# TODO: extract to query object
groups = Group.
select(%(
id,
name,
gid,
(
SELECT GROUP_CONCAT(user_login_id)
FROM users
INNER JOIN group_associations
ON users.id = group_associations.user_id
WHERE group_associations.group_id = groups.id
) AS members
)).
where('name IN (?)', sysadmins_login_ids).
map do |group|
members = (group.members || '').split(',')
Group.generate_group_response(group.name, group.gid, members)
end
groups << Group.get_default_sysadmin_group_for_host(sysadmins_login_ids, default_admins)
groups.to_json
end
def get_user_ids
user_ids = REDIS_CACHE.get("#{GROUP_UID_RESPONSE}:#{name}")
user_ids = JSON.parse(user_ids) if user_ids.present?
if user_ids.blank?
user_ids = users.map(&:user_login_id)
REDIS_CACHE.set("#{GROUP_UID_RESPONSE}:#{name}", user_ids.to_json)
REDIS_CACHE.expire("#{GROUP_UID_RESPONSE}:#{name}", REDIS_KEY_EXPIRY)
end
user_ids
end
def self.get_default_sysadmin_group_for_host(sysadmins_login_ids, default_admins = true)
sysadmins = sysadmins_login_ids
if default_admins
group = Group.find_by(name: 'sysadmins')
if group.present?
sysadmins = sysadmins + group.get_user_ids
end
end
group_id = group.blank? ? 8999 : group.id
sysadmin_group = Group.generate_group_response('sysadmins', group_id, sysadmins.uniq)
sysadmin_group
end
def add_user(user_id)
add_user_with_expiration(user_id, nil)
end
def add_user_with_expiration(user_id, expiration_date)
remove_user user_id
group_associations.create(user_id: user_id, expiration_date: expiration_date)
end
def remove_user(user_id)
group_associations.where(user_id: user_id).destroy_all
burst_host_cache
end
end
================================================
FILE: app/models/group_admin.rb
================================================
class GroupAdmin < ApplicationRecord
belongs_to :user
belongs_to :group
end
================================================
FILE: app/models/group_association.rb
================================================
class GroupAssociation < ApplicationRecord
belongs_to :user
belongs_to :group
def self.revoke_expired(date = Date.today)
where('expiration_date < ?', date).destroy_all
end
end
================================================
FILE: app/models/group_endpoint.rb
================================================
class GroupEndpoint < ApplicationRecord
belongs_to :group
belongs_to :endpoint
validates :group, uniqueness: { scope: :endpoint }
validates_presence_of :group
validates_presence_of :endpoint
end
================================================
FILE: app/models/host.rb
================================================
class Host < ApplicationRecord
belongs_to :user
acts_as_paranoid
end
================================================
FILE: app/models/host_access_group.rb
================================================
class HostAccessGroup < ApplicationRecord
belongs_to :host_machine
belongs_to :group
end
================================================
FILE: app/models/host_machine.rb
================================================
class HostMachine < ApplicationRecord
has_many :host_access_groups
has_many :groups, through: :host_access_groups
validates_uniqueness_of :name, case_sensitive: false
validates :name, presence: true
before_create :set_lower_case_name
before_create :set_host_access_key
def set_host_access_key
self.access_key = ROTP::Base32.random_base32
end
def set_lower_case_name
self.name = self.name.downcase
end
def self.get_group_response name
host_machine = HostMachine.find_by_name(name)
response = {}
return response if host_machine.blank?
response[:host_name] = name
response[:groups] = host_machine.groups.collect { |g| g.name }
response
end
def sysadmins
users = GroupAssociation.
select(:user_id).
distinct.
joins(:user).
where("group_id IN (?)", groups.collect(&:id)).
collect(&:user_id)
end
def add_host_group(name)
name = name.squish
if name.present?
name = "#{name}_host_group"
self.add_group(name.downcase)
end
end
def add_group(name)
name = name.squish
if name.present?
group = Group.find_or_initialize_by(name: name.downcase)
self.groups << group unless self.groups.include? group
self.save
end
end
end
================================================
FILE: app/models/ip_address.rb
================================================
class IpAddress < ApplicationRecord
end
================================================
FILE: app/models/organisation.rb
================================================
class Organisation < ApplicationRecord
validates :name, :website, :domain, :country, :state, :address,
:admin_email_address, :slug, presence: true
validates :address, format: {
with: /\A[a-zA-Z0-9\s]+\z/,
message: 'Invalid - Only Alphabets, Space and Numbers Allowed',
}
validates :admin_email_address, email: true
validates :slug, uniqueness: true
attr_accessor :cert, :rsa_key
UPDATE_KEYS = %w(
name website domain country state address admin_email_address slug unit_name
).freeze
def self.find_by_slug(slug)
Organisation.where(slug: slug).first
end
def self.setup(attrs = {})
attrs = attrs.stringify_keys
attrs = attrs.select { |k, _v| UPDATE_KEYS.include?(k) }
org = Organisation.new(attrs)
org.save if org.valid?
org
end
def update_profile(attrs = {})
attrs = attrs.stringify_keys
attrs = attrs.select { |k, _v| UPDATE_KEYS.include?(k) }
assign_attributes(attrs)
save if valid?
end
def saml_setup?
cert_fingerprint.present? && cert_key.present? && cert_private_key.present?
end
def setup_saml_certs
return false unless persisted?
require 'openssl'
self.rsa_key = OpenSSL::PKey::RSA.new(2048)
private_key = rsa_key.to_pem
public_key = rsa_key.public_key
subject = "/C=#{country}/ST=#{state}/L=#{address}/O=#{name}/OU=#{unit_name}/CN=#{domain}"
self.cert = OpenSSL::X509::Certificate.new
cert.subject = cert.issuer = OpenSSL::X509::Name.parse(subject)
cert.not_before = Time.now
cert.not_after = Time.now + 365 * 24 * 60 * 60
cert.public_key = public_key
cert.serial = SecureRandom.random_number(10)
cert.version = 2
ef = OpenSSL::X509::ExtensionFactory.new
ef.subject_certificate = cert
ef.issuer_certificate = cert
cert.extensions = [
ef.create_extension('basicConstraints', 'CA:TRUE', true),
ef.create_extension('subjectKeyIdentifier', 'hash'),
]
cert.add_extension ef.create_extension(
'authorityKeyIdentifier', 'keyid:always,issuer:always'
)
cert.sign rsa_key, OpenSSL::Digest::SHA1.new
update_attributes(
cert_fingerprint: OpenSSL::Digest::SHA256.hexdigest(cert.to_der).scan(/../).join(':'),
cert_key: cert.to_pem,
cert_private_key: private_key
)
end
end
================================================
FILE: app/models/saml_app_config.rb
================================================
class SamlAppConfig < ApplicationRecord
belongs_to :group
belongs_to :organisation
serialize :config, JSON
def self.get_config(app_name, org_id)
SamlAppConfig.find_or_initialize_by(
app_name: app_name, organisation_id: org_id
)
end
end
================================================
FILE: app/models/user.rb
================================================
class User < ApplicationRecord
include MsChapAuth
devise :timeoutable, :omniauthable, omniauth_providers: [:google_oauth2]
has_many :hosts
has_many :group_associations
has_many :groups, through: :group_associations
has_many :group_admin, dependent: :destroy
has_one :access_token
# TODO: Need to add the validations for the user model, right now a lot of tests fail due to enabling this
# validates :first_name, :last_name, :mobile, :user_role, presence: true
# validates :first_name, :last_name, format: { with: /[a-zA-Z]/}, allow_blank: true
# validates :user_role, inclusion: { in: ENV['USER_ROLES'].split(',') }
# validate :validate_email_domain
validates :email, uniqueness: true
# TODO: Need to enable these again after rails 7 update
# validate :remove_default_admin, on: :update
# before_save :revoke_admin_when_inactive, on: :update
# before_save :set_deactivated_at_when_inactive, on: :update
HOME_DIR = '/home'.freeze
USER_SHELL = '/bin/bash'.freeze
def self.add_user(first_name, last_name, user_role, domain)
user = User.new(first_name: first_name, last_name: last_name, user_role: user_role)
user.assign_attributes(
user_login_id: "#{first_name.downcase}.#{last_name.downcase}",
uid: user.generate_uid,
email: "#{first_name.downcase}.#{last_name.downcase}@#{domain}",
name: "#{first_name} #{last_name}"
)
user.save
user.initialise_host_and_group if user.persisted?
user
end
def generate_login_id
email.split('@').first
end
def generate_uid(uid_buffer = 5000)
uid_buffer = ENV['UID_BUFFER'].present? ? ENV['UID_BUFFER'].to_i : uid_buffer
User.last.blank? ? uid_buffer : User.last.id.to_i + uid_buffer
end
def initialise_host_and_group
host = Host.find_or_initialize_by(user: self)
unless ENV['DEFAULT_HOST_PATTERN'].blank?
host.host_pattern = ENV['DEFAULT_HOST_PATTERN']
end
hosts << host
groups << Group.find_or_initialize_by(name: user_login_id)
end
def generate_two_factor_auth(force_create = false)
if persisted? && (force_create || (!force_create && auth_key.blank?))
self.auth_key = ROTP::Base32.random_base32
totp = ROTP::TOTP.new(auth_key)
self.provisioning_uri = totp.provisioning_uri "GoJek-C #{email}"
save!
end
end
def self.create_user(name, email)
user = User.find_or_initialize_by(email: email)
unless user.persisted?
user.assign_attributes(
name: name, user_login_id: user.generate_login_id, uid: user.generate_uid
)
user.admin = User.first.blank?
user.initialise_host_and_group
user.save! if user.valid?
end
user
end
def self.add_temp_user(name, email)
email += "@#{ENV['GATE_HOSTED_DOMAIN']}"
user = User.create_user(name, email)
user.generate_two_factor_auth
user.auth_key
end
def update_profile(attrs = {})
allowed_keys = %w(public_key name product_name admin active)
attrs = attrs.stringify_keys
attrs = attrs.select { |k, v| allowed_keys.include?(k) && (v.present? || v.eql?(false)) }
assign_attributes(attrs)
if active.eql?(false) && deactivated_at.blank?
self.deactivated_at = Time.current
end
save! if valid?
end
def name_email
"#{name} (#{email})"
end
def self.get_sysadmins user_ids
users = User.
select(%Q(
id,
name,
uid,
user_login_id,
(
SELECT gid
FROM groups
INNER JOIN group_associations
ON groups.id = group_associations.group_id
WHERE group_associations.user_id = users.id
AND groups.name = users.user_login_id
LIMIT 1
) AS gid,
(
SELECT COUNT(gid)
FROM groups
INNER JOIN group_associations
ON groups.id = group_associations.group_id
WHERE group_associations.user_id = users.id
AND groups.name = users.user_login_id
LIMIT 1
) AS gid_count
)).
where(id: user_ids)
users.map(&:user_passwd_response)
end
def purge!
if !self.active
self.group_associations.each{ |g| g.destroy }
end
end
def self.includes_restricted_characters? input_string
return false if input_string.include?('@') == false
restricted_characters = [ ' ', '-', '*']
status = false
restricted_characters.each do |char|
break if status
status = input_string.include?(char)
end
status
end
def self.check_email_address email_address
!includes_restricted_characters?(email_address) && email_address.split("@").count == 2 ? true : false
end
def self.valid_domain? domain
hosted_domains = ENV['GATE_HOSTED_DOMAINS'].split(',')
hosted_domains.include?(domain)
end
def self.verify params
addresses = params[:addresses]
return false if addresses.empty?
address_array = addresses.split
user = User.get_user params[:user]
return false if user.blank?
return user.permitted_hosts? address_array
end
def self.authenticate_pam params
addresses = params[:addresses]
return false if addresses.empty?
address_array = addresses.split
email, token = get_user_pass_attributes params
return false if email.blank? || token.blank?
user_auth = find_and_check_user email, token
return check_user_host(email, address_array) if user_auth
return user_auth
end
def self.check_user_host email, address_array
user = User.get_user email
return user.permitted_hosts? address_array
end
def permitted_vpns? address_array
address_array.each do |host_address|
Vpn.user_vpns(self).each do |vpn|
return true if vpn.ip_address == host_address
end
end
return false
end
def permitted_hosts? address_array
address_array.each do |host_address|
host_name = nil
begin
host_name = Resolv.getname(host_address)
rescue
Rails.logger.info "Can't resolve name"
end
host_name = host_address if host_name.blank?
hosts.each do |host|
return true if /^#{host.host_pattern}/.match(host_name).to_s.present?
end
end
return false
end
def self.authenticate_cas encoded_string
username_password = Base64.decode64 encoded_string.split(" ")[1]
username = username_password.split(':').first
password = username_password.split(':').last
if User.find_and_check_user username, password
return username
else
return nil
end
end
def self.authenticate params
email, token = User.get_user_pass_attributes params
return false if email.blank? || token.blank?
return User.find_and_check_user email, token
end
def self.get_user user_login_id
return User.where(user_login_id: user_login_id, active: true).first
end
def self.find_and_validate_saml_user(email, password, app_name)
query = 'users.email = ? and users.active = ? and groups.name = ?'
users = User.joins(:groups).where(query, email, true, app_name)
if users.present?
users.first.valid_otp?(password) ? users.first : false
else
false
end
end
def valid_otp?(password)
user_key = "#{id}:#{Time.now.hour}"
request_count = REDIS_CACHE.incrby user_key, 1
REDIS_CACHE.expire user_key, 3600
return false if request_count > RATE_LIMIT
password.eql?(ROTP::TOTP.new(self.auth_key).now)
end
def self.find_and_check_user email, token
user = User.get_user email
return false if user.blank?
return false if !user.active
user_key = "#{user.id}:#{Time.now.hour}"
request_count = REDIS_CACHE.incrby user_key, 1
REDIS_CACHE.expire user_key, 3600
return false if request_count > RATE_LIMIT
token == ROTP::TOTP.new(user.auth_key).now
end
def self.get_user_pass_attributes params
token = params[:token].present? ? params[:token] : params[:password]
email = params[:email].present? ? params[:email] : params[:user]
return [nil, nil] if email.blank? || token.blank?
[email, token]
end
def self.get_shadow_name_response name
user = User.where(name: name).first
return nil if user.blank?
user.get_shadow_hash
end
def get_shadow_hash
shadow_hash = {}
shadow_hash[:sp_namp] = user_login_id
shadow_hash[:sp_pwdp] = "X"
shadow_hash[:sp_lstchg] = updated_at.to_i
shadow_hash[:sp_min] = 0
shadow_hash[:sp_max] = 99999
shadow_hash[:sp_warn] = 7
shadow_hash[:sp_inact]= nil
shadow_hash[:sp_expire] = nil
shadow_hash[:sp_flag] = nil
shadow_hash
end
def self.get_all_shadow_response
user_array = []
User.all.each do |user|
user_array << user.get_shadow_hash
end
user_array
end
def self.get_all_passwd_response
user_array = []
User.all.each do |user|
user_array << user.user_passwd_response
end
user_array
end
def self.get_passwd_name_response name
user = User.where("email like ?", "#{name}@%").first
return [] if user.blank?
user.user_passwd_response
end
def self.response_array response
user_response = []
user_response << response
user_response
end
def self.find_active_user_by_email(email)
User.where(email: email, active: true).first
end
def group_names_list
self.groups.map(&:name)
end
def reset_login_limit
user_key = "#{self.id}:#{Time.now.hour}"
REDIS_CACHE.set user_key, 0
end
def within_limits?
user_key = "#{self.id}:#{Time.now.hour}"
request_count = REDIS_CACHE.incrby user_key, 1
REDIS_CACHE.expire user_key, 3600
request_count < RATE_LIMIT
end
def self.ms_chap_auth params
auth_failed_message = "NT_STATUS_UNSUCCESSFUL: Failure (0xC0000001)"
addresses = params[:addresses]
user_name = params[:user]
challenge_string = params[:challenge]
response_string = params[:response]
return auth_failed_message if user_name.blank? || challenge_string.blank? || response_string.blank? || addresses.blank?
address_array = addresses.split
user = User.get_user user_name
if user.present? && user.permitted_vpns?(address_array)
drift_interval = 30
t = Time.now
otps = []
otps.push(user.get_user_otp_at(t))
otps.push(user.get_user_otp_at(t - drift_interval))
otps.push(user.get_user_otp_at(t + drift_interval))
return user.authenticate_ms_chap_with_drift otps, challenge_string, response_string
else
return auth_failed_message
end
end
#this method is here because we need to mock/stub for testing
def get_user_otp
return ROTP::TOTP.new(self.auth_key).now
end
def get_user_otp_at time
return ROTP::TOTP.new(self.auth_key).at time
end
def user_passwd_response
user_hash = {}
user_hash[:pw_name] = user_login_id
user_hash[:pw_passwd] = 'x'
user_hash[:pw_uid] = uid.to_i
# If gid is supplied (avoid N+1)
if respond_to?(:gid) && gid
user_hash[:pw_gid] = gid.to_i
elsif respond_to?(:gid_count)
if gid_count.positive?
user_hash[:pw_gid] = groups.where(name: user_login_id).first.gid
end
elsif groups.where(name: user_login_id).count.positive?
user_hash[:pw_gid] = groups.where(name: user_login_id).first.gid
end
user_hash[:pw_gecos] = name.to_s
user_hash[:pw_dir] = "#{HOME_DIR}/#{user_login_id}"
user_hash[:pw_shell] = '/bin/bash'
user_hash
end
def group_admin?
GroupAdmin.find_by_user_id(self.id).present?
end
def permitted_endpoint?(endpoint)
return false if endpoint.nil?
user_groups_id = group_associations.select(:group_id)
endpoint.
group_endpoints.
where('group_id IN (?)', user_groups_id).
select(:endpoint_id).present?
end
private
def remove_default_admin
admin_users = User.where('active = ? and admin = ? and id <> ?', true, true, id)
if (!admin || !active) && admin_users.blank?
errors.add(:admin, 'You cannot remove or make inactive the default admin account')
end
end
def validate_email_domain
domain_list = ENV['GATE_HOSTED_DOMAINS'].split(',')
domain = email.split('@').last
errors.add(:email, "Invalid Domain for Email Address") unless domain_list.include?(domain)
end
def revoke_admin_when_inactive
self.admin = false unless active
end
def set_deactivated_at_when_inactive
if active.eql?(false) && deactivated_at.blank?
self.deactivated_at = Time.current
end
end
end
================================================
FILE: app/models/vpn.rb
================================================
class Vpn < ApplicationRecord
belongs_to :user
belongs_to :group
has_many :vpn_group_associations
has_many :groups, through: :vpn_group_associations
has_many :vpn_group_user_associations
has_many :users, through: :vpn_group_user_associations
has_many :vpn_domain_name_servers
has_many :vpn_search_domains
has_many :vpn_supplemental_match_domains
def self.administrator?(user)
vpn_group_ids = VpnGroupAssociation.select(:group_id).collect(&:group_id)
managed_group_vpns = user.group_admin.where(group_id: vpn_group_ids)
!managed_group_vpns.empty?
end
def self.managed_vpns(user)
vpn_group_ids = VpnGroupAssociation.select(:group_id).collect(&:group_id)
managed_group_vpn_ids = user.
group_admin.
select(:group_id).
where(group_id: vpn_group_ids).
collect(&:group_id)
VpnGroupAssociation.where(group_id: managed_group_vpn_ids).collect(&:vpn).uniq
end
def self.user_vpns user
vpn_group_ids = VpnGroupAssociation.select(:group_id).collect(&:group_id)
user_group_vpn_ids = user.
group_associations.
select(:group_id).
where(group_id: vpn_group_ids).
collect(&:group_id)
VpnGroupAssociation.where(group_id: user_group_vpn_ids).collect(&:vpn).uniq
end
def migrate_to_new_group
group_name = "#{name}_vpn_group".downcase.squish.gsub(' ', '_')
group = Group.where(name: group_name).first
if group.blank?
# create a new group for VPN
group = Group.create(name: group_name, description: "#{name} VPN Access group")
# Assign VPN to group
# get all vpn administrators
admins = []
groups.each do |admin_group|
admin_group.group_admins.each do |group_admin|
group.add_admin group_admin.user
end
end
# get all vpn users
# add all vpn users to new group
users.each do |user|
user.groups << group
end
group.save!
group.vpns << self
end
end
end
================================================
FILE: app/models/vpn_domain_name_server.rb
================================================
class VpnDomainNameServer < ApplicationRecord
belongs_to :vpn
end
================================================
FILE: app/models/vpn_group_association.rb
================================================
class VpnGroupAssociation < ApplicationRecord
belongs_to :vpn
belongs_to :group
end
================================================
FILE: app/models/vpn_group_user_association.rb
================================================
class VpnGroupUserAssociation < ApplicationRecord
belongs_to :vpn
belongs_to :user
end
================================================
FILE: app/models/vpn_search_domain.rb
================================================
class VpnSearchDomain < ApplicationRecord
belongs_to :vpn
end
================================================
FILE: app/models/vpn_supplemental_match_domain.rb
================================================
class VpnSupplementalMatchDomain < ApplicationRecord
belongs_to :vpn
end
================================================
FILE: app/validators/email_validator.rb
================================================
class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value.to_s.match?(/\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i)
record.errors[attribute] << (options[:message] || 'is not an email')
end
end
end
================================================
FILE: app/views/admin/index.html.slim
================================================
h1 hello
================================================
FILE: app/views/api/v1/users/show.json.jbuilder
================================================
json.(@user, :email, :uid, :name, :active, :admin, :home_dir, :shell, :public_key, :user_login_id, :product_name)
json.groups @user.groups, :gid, :name
================================================
FILE: app/views/api_resources/_api_resource.json.jbuilder
================================================
json.extract! api_resource, :id, :name, :description, :access_key, :created_at, :updated_at
json.url api_resource_url(api_resource, format: :json)
================================================
FILE: app/views/api_resources/_form.html.slim
================================================
= form_for @api_resource, :class => 'form-horizontal', html: {novalidate: 'true'} do |f|
- if @api_resource.errors.any?
#error_explanation
h2 = "#{pluralize(@api_resource.errors.count, "error")} prohibited this api_resource from being saved:"
ul
- @api_resource.errors.full_messages.each do |message|
li = message
hr
.mb-3
label for="name"
| API Name
= f.text_field :name, required: true, class: "form-control", placeholder: "API Name"
.invalid-feedback
.mb-3
label for="description"
| Description
= f.text_field :description, required: true, class: "form-control", placeholder: "Description"
.invalid-feedback
.mb-4
= f.submit "Save", class: "btn btn-primary pull-right"
================================================
FILE: app/views/api_resources/edit.html.slim
================================================
h1 Editing api_resource
== render 'form'
=> link_to 'Show', @api_resource
'|
=< link_to 'Back', api_resources_path
================================================
FILE: app/views/api_resources/index.html.slim
================================================
.container-fluid.col-md-8
- if notice.present?
.alert.alert-primary role="alert"
#notice
= notice
h4 API Keys
table.table.responsive
thead
tr
th Name
th Description
th Access key
th Owner
th Access Group
th
tbody
- @api_resources.each do |api_resource|
tr
td = api_resource.name
td = api_resource.description
td = link_to 'Regenerate', regenerate_access_key_api_resource_path(api_resource), data: { confirm: 'Are you sure?' }
td = link_to api_resource.user.name, api_resource.user if api_resource.user.present?
td = link_to api_resource.group.name, api_resource.group if api_resource.group.present?
td = link_to 'Destroy', api_resource, data: { confirm: 'Are you sure?' }, method: :delete
br
javascript:
$("#apiresource-index").addClass("active");
================================================
FILE: app/views/api_resources/index.json.jbuilder
================================================
json.array! @api_resources, partial: 'api_resources/api_resource', as: :api_resource
================================================
FILE: app/views/api_resources/new.html.slim
================================================
.container-fluid.col-md-4.col-md-offset-4
- if notice.present?
.alert.alert-primary role="alert"
#notice
= notice
br
h5 Create new API
== render 'form'
= link_to 'Back', api_resources_path
javascript:
$("#apiresource-index").addClass("active");
================================================
FILE: app/views/api_resources/show.html.slim
================================================
.container-fluid.col-md-4.col-md-offset-4
- if notice.present?
.alert.alert-primary role="alert"
#notice
= notice
br
h5 Show API
hr
.mb-3
label for="name"
| API Name
p.form-control-static
= @api_resource.name
.mb-3
label for="description"
| Description
p.form-control-static
= @api_resource.description
- if flash[:access_key]
.mb-3
label for="access_key"
| Access Key
.alert.alert-warning role="alert"
| Important! please make note of this access key, you will see it only this once.
= text_field_tag :access_key, flash[:access_key], class: 'form-control', readonly: ""
.mb-4
=> link_to 'Edit', edit_api_resource_path(@api_resource)
'|
=> link_to 'Regenerate Access Key', regenerate_access_key_api_resource_path(@api_resource), :data => {:confirm => 'Are you sure?'}
'|
=< link_to 'Back', api_resources_path
================================================
FILE: app/views/api_resources/show.json.jbuilder
================================================
json.partial! "api_resources/api_resource", api_resource: @api_resource
================================================
FILE: app/views/application/_admin.html.slim
================================================
div
ul.navbar-nav
li.nav-item.active
a.nav-link href="#" Users
li.nav-item
a.nav-link href="#" Groups
================================================
FILE: app/views/application/_groups_header.html.slim
================================================
#notice
= notice
- if current_user.admin?
= form_tag groups_path, method: 'post' do
.row
.col-md-8
= text_field_tag "group[name]", "", class: "form-control", autofocus: true
.col-md-4
= submit_tag "Add Group", class: "form-control btn btn-sm btn-primary", name: nil
br
= form_tag groups_path, method: 'get' do
.row
.col-md-8
= text_field_tag :group_search, params[:group_search], class: "form-control" , autofocus: true
.col-md-4
= submit_tag "Search groups", class: "form-control btn btn-sm btn-primary", name: nil
hr
================================================
FILE: app/views/application/_host_header.html.slim
================================================
ul.nav.nav-tabs
li#host_machine role="presentation"
= link_to "MyHosts", host_machines_path
li#group role="presentation"
= link_to "Groups", groups_path
li#host_machine_search role="presentation"
a href="#" Search Host
li#host_machine_group_search role="presentation"
a href="#" Search Host Groups
p
br
================================================
FILE: app/views/common/errors.json.jbuilder
================================================
json.success false
json.errors errors
================================================
FILE: app/views/groups/_form.html.slim
================================================
================================================
FILE: app/views/groups/index.html.slim
================================================
.container-fluid.col.container-profile
- if current_user.admin?
= form_tag groups_path, method: 'get', class: "p-2" do
.input-group
= text_field_tag :group_search, params[:group_search], class: "form-control" , autofocus: true, placeholder: "Search group name..."
.input-group-append
= submit_tag "Search", class: "button btn btn-secondary", name: nil
- if @groups.count > 0
h5 Your managed groups
.table-responsive
table.table.table-striped
thead
tr
th Name
th Gid
th Group Admin
tbody
- @groups.each do |group|
tr
td
= link_to "#{group.name}", group_path(group)
td
= "#{group.gid}"
td
- if group.group_admins.present?
- group.group_admins.each do |admin|
.row
= "#{admin.user.try(:name)}"
javascript:
$("#group-index").addClass("active");
================================================
FILE: app/views/groups/new.html.slim
================================================
.container-fluid.col-md-4.col-md-offset-4
h5 Add new group
= form_for @group, :class => 'form-horizontal' do |f|
- if @group.errors.any?
#error_explanation
h2 = "#{pluralize(@group.errors.count, "error")} prohibited this vpn from being saved:"
ul
- @group.errors.full_messages.each do |message|
li = message
hr
.mb-3
label for="name"
| Name
= f.text_field :name, required: true, class: "form-control", placeholder: "Group Name"
.invalid-feedback
| Please enter a name
.mb-4
= f.submit "Add Group", class: "btn btn-primary pull-right"
================================================
FILE: app/views/groups/show.html.slim
================================================
.container.col-md-8
h5.mb-3 Group Details
hr
.row
.col
= "Group Name: #{@group.name}"
.col
= "Group ID: #{@group.gid}"
br
- if current_user.admin? or @group.admin?(current_user)
= form_tag add_admin_to_group_path(@group.id), method: :post do
.row
.col
| Group Administrator
.col
- if @group.group_admins.present?
- @group.group_admins.each do |admin|
.row
.col
= "#{admin.user.try(:name)}"
.col
= "#{admin.user.try(:email)}"
.col
- if (current_user.admin?)
= link_to "Remove?", [@group, admin], method: :delete, data: {confirm: "Are you sure to remove #{admin.user.try(:name)} ?"}
- if (current_user.admin?)
.row
.col-8
= text_field_tag "user_id", "", id: "assign_admin_user_id", class: "form-control"
.col
= submit_tag "Assign admin", class: "form-control btn btn-md btn-primary", disabled: true
.row
.col-8
= check_box_tag "assign_admin_include_inactive_user", "true", false
= " Include Inactive User"
.col
a name="group_members"
br
.card
.card-body
h6.card-title Groups Members (#{@group_users.length})
.table-responsive
table.table.table-striped
thead
tr
th User Details
th Email Address
th Join Date
th Expiration Date
th
tbody
- @group_users.sort_by{ |user| user.email}.each do |user|
tr
td
- if user.active?
= link_to "#{user.name}", user_path(user)
- else
= link_to "#{user.name} (inactive)", user_path(user)
td
= "#{user.email}"
td
= "#{user.join_date.strftime("%v")}"
td
= "#{user.group_expiration_date}"
td
= link_to "Delete", [@group, user], method: :delete, data: {confirm: 'Are you sure to remove this user from the group?'} if current_user.admin or @group.admin?(current_user)
br
= "*This group does not have any group members" if @group_users.length == 0
br
- if current_user.admin or @group.admin?(current_user)
.h7 Assign members
= form_tag add_user_to_group_path(@group.id), method: :post do
.row
.col
.form_group
label
| User
= text_field_tag "user_id", "", id: "add_user_user_id", class: "form-control"
= check_box_tag "add_user_include_inactive_user", "true", false
= " Include Inactive User"
.col
.form_group
label
| Assignment Expiration date
= date_field_tag "expiration_date", "", id: "expiration_date", class: "form-control"
| * expiration date is optional (unspecified means permanent)
.col
br
= submit_tag "Add User", class: "form-control btn-md btn-primary", disabled: true
br
.card
.card-body
h6.card-title VPN Access
.table-responsive
table.table.table-striped
thead
tr
th Vpn Details
th Vpn name
th Vpn Host name
th
tbody
- @group.vpns.sort_by{ |vpn| vpn.name}.uniq{|vpn| vpn.id}.each do |vpn|
tr
td
= link_to "#{vpn.name}", vpn_path(vpn)
td
= "#{vpn.name}"
td
= "#{vpn.host_name}"
td
- if current_user.admin?
= link_to "Delete", [@group, vpn], method: :delete, data: {confirm: 'Are you sure to remove this vpn from the group?'}
br
= "*This group does not have any VPNs associated with it" if @group.vpns.count == 0
br
- if current_user.admin?
= form_tag add_vpn_to_group_path(@group.id), method: :post do
.row
.col
| Assign VPNs
.col
.col
= text_field_tag "vpn_id", "", id: "add_vpn_vpn_id", class: "form-control"
.col
= submit_tag "Add Vpn", class: "form-control btn-md btn-primary", disabled: true
br
.card
.card-body
h6.card-title Group access hosts
.table-responsive
table.table.table-striped
thead
tr
th Host Name
th
tbody
- @group.host_machines.each do |machine|
tr
td
= link_to "#{machine.name}", host_machine_path(machine)
td
= link_to "Delete", [@group, machine], method: :delete, data: {confirm: 'Are you sure to remove this machine from the group??'} if current_user.admin?
br
= "*This group does not have any host access" if @group.host_machines.count == 0
br
hr
- if current_user.admin?
= form_tag add_machine_to_group_path(@group.id), method: :post do
.row
.col
| Assign Hosts
.col
.col
= text_field_tag "machine_id", "", id: "add_machine_machine_id", class: "form-control"
.col
= submit_tag "Add Host", class: "form-control btn-md btn-primary", disabled: true
javascript:
$("#group-index").addClass("active");
================================================
FILE: app/views/home/index.html.slim
================================================
.form-signin
.row
.col
h1 Gate-SSO
br
.row
.col
h3 Single Sign-On
br
br
br
br
- case ENV['SIGN_IN_TYPE']
- when 'form'
= form_tag user_sign_in_path, method: :post do
.row
.col-sm-10.offset-sm-1
= text_field_tag :name, '', class: 'form-control', placeholder: 'Name', required: true
= text_field_tag :email, '', class: 'form-control', placeholder: 'Email', required: true, type: 'email'
= submit_tag 'Sign in', class: 'form-control btn-md btn-primary'
- else
.row
.col
.col
a.btn.btn-block.btn-social.btn-google href="#{url_for user_google_oauth2_omniauth_authorize_path}"
span.fa.fa-google
| Sign in with Google
.col
================================================
FILE: app/views/host_machines/index.html.slim
================================================
.container-fluid.col-md-6.col-md-offset-2
= form_tag host_machines_path, method: 'get', class: "p-2" do
.input-group
= text_field_tag :host_machine_search, params[:host_machine_search], class: "form-control" , autofocus: true, placeholder: "Search host..."
.input-group-append
= submit_tag "Search", class: "button btn btn-secondary", name: nil
.container-fluid.col-md-6.col-md-offset-2
- if @host_machines.count > 0
.table-responsive
table.table.table-striped
thead
tr
th Name
tbody
- @host_machines.each do |host_machine|
tr
td
= link_to "#{host_machine.name}", host_machine
br
javascript:
$("#hostmachine-index").addClass("active");
================================================
FILE: app/views/host_machines/new.html.slim
================================================
.container-fluid.col-md-4.col-md-offset-4
= form_tag host_machines_path, method: 'post' do
.input-group
= text_field_tag "host_machine[name]", "", class: "form-control", autofocus: true
.input-group
= submit_tag "Add Host machine", class: "form-control btn btn-sm btn-primary", name: nil
================================================
FILE: app/views/host_machines/show.html.slim
================================================
.container.col-md-8
h5.mb-3 Host Details
hr
.row
.col
= @host_machine.name
- if current_user.admin?
.card
.card-body
h6.card-title Configurations
hr
= form_tag "/host_machines/#{@host_machine.id}", method: 'put' do
.row
.col
.custom-control.custom-checkbox
= check_box "host_machine", "default_admins", class: "custom-control-input", id: "admin-checkbox"
label.custom-control-label for="admin-checkbox" Default Admins?
.col
= submit_tag "Update", class: "form-control btn-md btn-primary"
br
.card
.card-body
.table-responsive
table.table.table-striped
thead
tr
th Group Name
th
tbody
- @host_machine.groups.each do |group|
tr
td
= link_to "#{group.name}", group_path(group)
td
= link_to "Delete", [@machine, group], method: :delete, data: {confirm: 'Are you sure to remove this machine from the group??'} if current_user.admin?
br
= "*This host does not have any group" if @host_machine.groups.count == 0
br
hr
- if current_user.admin?
= form_tag add_group_to_machine_path, method: :post do
.row
.col
| Assign group
.col
.col
= text_field_tag "group_id", "", class: "form-control"
.col
= submit_tag "Add group", class: "form-control btn-md btn-primary", disabled: true
================================================
FILE: app/views/layouts/application.html.slim
================================================
doctype html
html lang="en"
head
meta charset="utf-8"
meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"
meta name="viewport" content="width=device-width, initial-scale=1.0"
title= content_for?(:title) ? yield(:title) : "Gate"
= csrf_meta_tags
= stylesheet_link_tag "application", :media => "all"
= stylesheet_link_tag "general", :media => "all"
= stylesheet_link_tag "//cdnjs.cloudflare.com/ajax/libs/selectize.js/0.12.4/css/selectize.bootstrap3.min.css"
= javascript_include_tag "application"
= javascript_include_tag "//cdnjs.cloudflare.com/ajax/libs/selectize.js/0.12.4/js/standalone/selectize.min.js"
/! Le HTML5 sh
gitextract_ouflf_22/
├── .deepsource.toml
├── .dockerignore
├── .gitignore
├── .rspec
├── .rubocop.yml
├── .ruby-version
├── .travis.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Dockerfile
├── Gemfile
├── LICENSE
├── README.md
├── Rakefile
├── VERSION
├── api_blueprint/
│ ├── bin/
│ │ └── dredd_server.sh
│ ├── group.apib
│ ├── hooks/
│ │ └── dredd_hooks.rb
│ ├── user.apib
│ └── vpns.apib
├── app/
│ ├── assets/
│ │ ├── config/
│ │ │ └── manifest.js
│ │ ├── images/
│ │ │ └── .keep
│ │ ├── javascripts/
│ │ │ ├── admin.coffee
│ │ │ ├── api_resources.coffee
│ │ │ ├── application.js
│ │ │ ├── bootstrap.js.coffee
│ │ │ ├── group.coffee
│ │ │ ├── groups.coffee
│ │ │ ├── home.coffee
│ │ │ ├── host_access_groups.coffee
│ │ │ ├── host_machine_groups.coffee
│ │ │ ├── host_machines.coffee
│ │ │ ├── nss.coffee
│ │ │ ├── omniauth_callbacks.coffee
│ │ │ ├── profile.coffee
│ │ │ ├── users.coffee
│ │ │ ├── utilities.coffee
│ │ │ └── viewport.js
│ │ └── stylesheets/
│ │ ├── application.scss
│ │ ├── bootstrap-social.scss
│ │ ├── general.css
│ │ ├── home.scss.erb
│ │ ├── profile.css
│ │ └── scaffolds.scss
│ ├── clients/
│ │ └── data_dog_client.rb
│ ├── controllers/
│ │ ├── admin_controller.rb
│ │ ├── api/
│ │ │ └── v1/
│ │ │ ├── base_controller.rb
│ │ │ ├── endpoints_controller.rb
│ │ │ ├── groups_controller.rb
│ │ │ ├── users_controller.rb
│ │ │ └── vpns_controller.rb
│ │ ├── api_resources_controller.rb
│ │ ├── application_controller.rb
│ │ ├── concerns/
│ │ │ └── .keep
│ │ ├── groups_controller.rb
│ │ ├── home_controller.rb
│ │ ├── host_controller.rb
│ │ ├── host_machine_groups_controller.rb
│ │ ├── host_machines_controller.rb
│ │ ├── nss_controller.rb
│ │ ├── organisations_controller.rb
│ │ ├── pings_controller.rb
│ │ ├── profile_controller.rb
│ │ ├── saml_idp_controller.rb
│ │ ├── users/
│ │ │ ├── auth_controller.rb
│ │ │ └── omniauth_callbacks_controller.rb
│ │ ├── users_controller.rb
│ │ ├── vpn_domain_name_servers_controller.rb
│ │ └── vpns_controller.rb
│ ├── helpers/
│ │ ├── admin_helper.rb
│ │ ├── api_resources_helper.rb
│ │ ├── application_helper.rb
│ │ ├── group_helper.rb
│ │ ├── groups_helper.rb
│ │ ├── home_helper.rb
│ │ ├── host_access_groups_helper.rb
│ │ ├── host_machine_groups_helper.rb
│ │ ├── host_machines_helper.rb
│ │ ├── nss_helper.rb
│ │ ├── omniauth_callbacks_helper.rb
│ │ ├── profile_helper.rb
│ │ └── users_helper.rb
│ ├── lib/
│ │ ├── datadog.rb
│ │ └── saml_app.rb
│ ├── mailers/
│ │ └── .keep
│ ├── models/
│ │ ├── .keep
│ │ ├── access_token.rb
│ │ ├── api_resource.rb
│ │ ├── application_record.rb
│ │ ├── concerns/
│ │ │ ├── .keep
│ │ │ └── ms_chap_auth.rb
│ │ ├── endpoint.rb
│ │ ├── group.rb
│ │ ├── group_admin.rb
│ │ ├── group_association.rb
│ │ ├── group_endpoint.rb
│ │ ├── host.rb
│ │ ├── host_access_group.rb
│ │ ├── host_machine.rb
│ │ ├── ip_address.rb
│ │ ├── organisation.rb
│ │ ├── saml_app_config.rb
│ │ ├── user.rb
│ │ ├── vpn.rb
│ │ ├── vpn_domain_name_server.rb
│ │ ├── vpn_group_association.rb
│ │ ├── vpn_group_user_association.rb
│ │ ├── vpn_search_domain.rb
│ │ └── vpn_supplemental_match_domain.rb
│ ├── validators/
│ │ └── email_validator.rb
│ └── views/
│ ├── admin/
│ │ └── index.html.slim
│ ├── api/
│ │ └── v1/
│ │ └── users/
│ │ └── show.json.jbuilder
│ ├── api_resources/
│ │ ├── _api_resource.json.jbuilder
│ │ ├── _form.html.slim
│ │ ├── edit.html.slim
│ │ ├── index.html.slim
│ │ ├── index.json.jbuilder
│ │ ├── new.html.slim
│ │ ├── show.html.slim
│ │ └── show.json.jbuilder
│ ├── application/
│ │ ├── _admin.html.slim
│ │ ├── _groups_header.html.slim
│ │ └── _host_header.html.slim
│ ├── common/
│ │ └── errors.json.jbuilder
│ ├── groups/
│ │ ├── _form.html.slim
│ │ ├── index.html.slim
│ │ ├── new.html.slim
│ │ └── show.html.slim
│ ├── home/
│ │ └── index.html.slim
│ ├── host_machines/
│ │ ├── index.html.slim
│ │ ├── new.html.slim
│ │ └── show.html.slim
│ ├── layouts/
│ │ ├── application.html.slim
│ │ ├── home.html.slim
│ │ └── profile.html.slim.disabled
│ ├── nss/
│ │ └── add_host.json.jbuilder
│ ├── organisations/
│ │ ├── _form.html.slim
│ │ ├── config_saml_app.html.slim
│ │ ├── index.html.slim
│ │ ├── new.html.slim
│ │ ├── saml_apps/
│ │ │ └── _datadog.html.erb
│ │ └── show.html.slim
│ ├── profile/
│ │ ├── _group_search.html.slim
│ │ ├── _user_search.html.slim
│ │ ├── group_admin.html.slim
│ │ ├── list.html.slim
│ │ ├── public_key.html.slim
│ │ ├── show.html.slim
│ │ ├── user.html.slim
│ │ └── user_admin.html.slim
│ ├── saml_idp/
│ │ └── idp/
│ │ └── new.html.erb
│ ├── users/
│ │ ├── _search.html.slim
│ │ ├── index.html.slim
│ │ ├── new.html.erb
│ │ └── show.html.slim
│ └── vpns/
│ ├── _form.html.slim
│ ├── edit.html.slim
│ ├── index.html.slim
│ ├── new.html.slim
│ └── show.html.slim
├── bin/
│ ├── bundle
│ ├── rails
│ ├── rake
│ ├── setup
│ └── update
├── config/
│ ├── application.rb
│ ├── boot.rb
│ ├── cable.yml
│ ├── database.yml
│ ├── environment.rb
│ ├── environments/
│ │ ├── development.rb
│ │ ├── integration.rb
│ │ ├── production.rb
│ │ └── test.rb
│ ├── initializers/
│ │ ├── application_controller_renderer.rb
│ │ ├── assets.rb
│ │ ├── backtrace_silencers.rb
│ │ ├── content_security_policy.rb
│ │ ├── cookies_serializer.rb
│ │ ├── devise.rb
│ │ ├── dotenv.rb
│ │ ├── filter_parameter_logging.rb
│ │ ├── inflections.rb
│ │ ├── mime_types.rb
│ │ ├── new_framework_defaults.rb
│ │ ├── new_framework_defaults_7_0.rb
│ │ ├── permissions_policy.rb
│ │ ├── session_store.rb
│ │ └── wrap_parameters.rb
│ ├── locales/
│ │ ├── devise.en.yml
│ │ ├── en.bootstrap.yml
│ │ └── en.yml
│ ├── newrelic.yml
│ ├── puma.rb
│ ├── redis.yml
│ ├── routes.rb
│ ├── schedule.rb
│ ├── secrets.yml
│ ├── spring.rb
│ └── storage.yml
├── config.ru
├── db/
│ ├── migrate/
│ │ ├── 20160419122430_devise_create_users.rb
│ │ ├── 20160419132647_add_provider_to_users.rb
│ │ ├── 20160419144739_add_name_to_users.rb
│ │ ├── 20160427123146_add_auth_key_to_user.rb
│ │ ├── 20160427123233_add_provisioning_uri_to_user.rb
│ │ ├── 20160519042340_add_active_to_users.rb
│ │ ├── 20160519064340_add_default_value_to_users.rb
│ │ ├── 20160615044834_create_hosts.rb
│ │ ├── 20160615045052_add_admin_to_user.rb
│ │ ├── 20160615112805_add_user_to_host.rb
│ │ ├── 20160628140022_add_deleted_at_to_host.rb
│ │ ├── 20160628140440_add_deleted_by_to_host.rb
│ │ ├── 20160629043358_add_homedir_to_user.rb
│ │ ├── 20160629043415_add_shell_to_user.rb
│ │ ├── 20160629075435_create_groups.rb
│ │ ├── 20160701090045_create_group_associations.rb
│ │ ├── 20160701112600_add_deleted_properties_to_group.rb
│ │ ├── 20160707115313_create_access_tokens.rb
│ │ ├── 20160714115228_add_public_key_to_user.rb
│ │ ├── 20160908081651_create_host_machines.rb
│ │ ├── 20161003145832_create_host_access_groups.rb
│ │ ├── 20170803140620_add_user_login_id_to_user.rb
│ │ ├── 20171013115441_create_versions.rb
│ │ ├── 20171016064705_remove_index_group_name.rb
│ │ ├── 20171016071526_add_unique_index_on_groups_name.rb
│ │ ├── 20171031060034_create_group_admin.rb
│ │ ├── 20171031060217_add_foreign_key_ref_on_group_admin.rb
│ │ ├── 20171031100758_create_vpns.rb
│ │ ├── 20171031101026_create_vpn_group_association.rb
│ │ ├── 20171031103518_add_foreign_key_ref_on_vpn_group_association.rb
│ │ ├── 20171031113123_create_vpn_group_user_association.rb
│ │ ├── 20171031121702_add_foreign_key_ref_on_vpn_group_user_association.rb
│ │ ├── 20171102071909_add_ip_address_to_vpns.rb
│ │ ├── 20171107114249_remove_url_from_vpns.rb
│ │ ├── 20171108130234_add_user_id_to_access_token.rb
│ │ ├── 20171108130353_add_foreign_key_ref_on_access_tokens.rb
│ │ ├── 20171124090240_add_uuid_to_vpns.rb
│ │ ├── 20171124114427_create_vpn_domain_name_servers.rb
│ │ ├── 20171124114830_create_vpn_search_domains.rb
│ │ ├── 20171124115925_create_vpn_supplemental_match_domains.rb
│ │ ├── 20180104081814_add_product_name_to_users.rb
│ │ ├── 20180202102206_create_saml_service_providers.rb
│ │ ├── 20180214050204_add_api_key_to_host_machines.rb
│ │ ├── 20180214052451_create_ip_addresses.rb
│ │ ├── 20180214052644_add_host_machine_to_ip_address.rb
│ │ ├── 20180219150818_add_description_to_group.rb
│ │ ├── 20180222135930_add_access_key_to_host_machine.rb
│ │ ├── 20180222140000_add_access_key_to_user.rb
│ │ ├── 20180227051732_create_api_resources.rb
│ │ ├── 20180301010021_add_user_to_api_resources.rb
│ │ ├── 20180301010035_add_group_to_api_resources.rb
│ │ ├── 20180306231200_add_deactivated_at_to_users.rb
│ │ ├── 20180311082600_rename_access_key_in_api_resources.rb
│ │ ├── 20180311161200_rename_token_in_access_tokens.rb
│ │ ├── 20180318083000_create_indexes_to_speedup_nss_controller.rb
│ │ ├── 20180613074108_create_organisations.rb
│ │ ├── 20180613165050_drop_saml_service_providers.rb
│ │ ├── 20180723175600_update_organisations_for_saml.rb
│ │ ├── 20181002023107_add_default_admins_to_host_machines.rb
│ │ ├── 20181016093315_create_saml_app_configs.rb
│ │ ├── 20181208184236_add_fields_to_user.rb
│ │ ├── 20190624024930_add_expiration_date_to_group_associations.rb
│ │ ├── 20190820070910_create_endpoints.rb
│ │ ├── 20190820075040_create_group_endpoints.rb
│ │ ├── 20190820080624_add_foreign_key_ref_on_group_endpoints.rb
│ │ ├── 20200113065717_add_sessions_table.rb
│ │ ├── 20220926001848_add_service_name_to_active_storage_blobs.active_storage.rb
│ │ ├── 20220926001849_create_active_storage_variant_records.active_storage.rb
│ │ └── 20220926001850_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb
│ ├── schema.rb
│ ├── seeds/
│ │ ├── development.rb
│ │ ├── production.rb
│ │ └── test.rb
│ └── seeds.rb
├── docker-compose.yaml
├── docs/
│ ├── additional_setup.md
│ ├── administration.md
│ ├── dredd_setup.md
│ ├── newrelic.md
│ └── oauth_setup.md
├── dredd.yml
├── lib/
│ ├── assets/
│ │ └── .keep
│ ├── tasks/
│ │ ├── .keep
│ │ ├── app.rake
│ │ ├── setup.rake
│ │ ├── users.rake
│ │ └── vpn.rake
│ └── vpn/
│ ├── mobileconfig.erb
│ ├── mobileconfig.rb
│ └── namespace.rb
├── public/
│ ├── 404.html
│ ├── 422.html
│ ├── 500.html
│ └── robots.txt
├── scripts/
│ ├── gen-client-conf
│ └── gen-client-keys
├── setup.sh
└── spec/
├── clients/
│ └── data_dog_client_spec.rb
├── controllers/
│ ├── admin_controller_spec.rb
│ ├── api/
│ │ └── v1/
│ │ ├── api_controller_spec.rb
│ │ ├── endpoints_controller_spec.rb
│ │ ├── groups_controller_spec.rb
│ │ ├── users_controller_spec.rb
│ │ └── vpns_controller_spec.rb
│ ├── api_resources_controller_spec.rb
│ ├── groups_controller_spec.rb
│ ├── home_controller_spec.rb
│ ├── host_machine_groups_controller_spec.rb
│ ├── host_machines_controller_spec.rb
│ ├── nss_controller_spec.rb
│ ├── omniauth_callbacks_controller_spec.rb
│ ├── organisations_controller_spec.rb
│ ├── profile_controller_spec.rb
│ ├── users/
│ │ └── auth_controller_spec.rb
│ ├── users_controller_spec.rb
│ └── vpns_controller_spec.rb
├── factories/
│ ├── access_tokens.rb
│ ├── api_resources.rb
│ ├── endpoints.rb
│ ├── group_associations.rb
│ ├── groups.rb
│ ├── host_access_groups.rb
│ ├── host_machine_groups.rb
│ ├── host_machines.rb
│ ├── ip_addresses.rb
│ ├── organisations.rb
│ ├── saml_app_configs.rb
│ ├── user_host_access_groups.rb
│ ├── users.rb
│ └── vpns.rb
├── features/
│ ├── layout_spec.rb
│ ├── organisations/
│ │ ├── add_user_saml_app_spec.rb
│ │ ├── config_saml_app_spec.rb
│ │ ├── create_spec.rb
│ │ ├── list_spec.rb
│ │ ├── list_user_saml_app_spec.rb
│ │ ├── remove_user_saml_app_spec.rb
│ │ ├── save_config_saml_app_spec.rb
│ │ ├── setup_saml_spec.rb
│ │ └── update_spec.rb
│ ├── saml/
│ │ └── show_spec.rb
│ └── users/
│ ├── create_user_spec.rb
│ └── regenerate_auth_spec.rb
├── helpers/
│ └── application_helper_spec.rb
├── lib/
│ ├── datadog_spec.rb
│ ├── saml_app_spec.rb
│ └── tasks/
│ └── users_rake_spec.rb
├── models/
│ ├── access_token_spec.rb
│ ├── api_resource_spec.rb
│ ├── endpoint_spec.rb
│ ├── group_association_spec.rb
│ ├── group_endpoint_spec.rb
│ ├── group_spec.rb
│ ├── host_machine_spec.rb
│ ├── host_spec.rb
│ ├── ip_address_spec.rb
│ ├── organisation_spec.rb
│ ├── user_spec.rb
│ └── vpn_spec.rb
├── rails_helper.rb
├── routing/
│ └── api_resources_routing_spec.rb
├── spec_helper.rb
├── support/
│ └── helpers/
│ └── x509_certificate_helper.rb
└── views/
├── api_resources/
│ ├── edit.html.slim_spec.rb
│ ├── index.html.slim_spec.rb
│ ├── new.html.slim_spec.rb
│ └── show.html.slim_spec.rb
├── groups/
│ └── show.html.slim_spec.rb
└── layouts/
└── home.html.slim_spec.rb
SYMBOL INDEX (488 symbols across 136 files)
FILE: app/clients/data_dog_client.rb
class DataDogClient (line 1) | class DataDogClient
method initialize (line 5) | def initialize(app_key, api_key)
method get_user (line 15) | def get_user(email)
method new_user (line 25) | def new_user(email)
method activate_user (line 35) | def activate_user(email)
method deactivate_user (line 45) | def deactivate_user(email)
method append_auth (line 57) | def append_auth(str)
FILE: app/controllers/admin_controller.rb
class AdminController (line 1) | class AdminController < ApplicationController
method index (line 2) | def index; end
FILE: app/controllers/api/v1/base_controller.rb
class ::Api::V1::BaseController (line 1) | class ::Api::V1::BaseController < ActionController::Base
method authenticate_user_from_token! (line 5) | def authenticate_user_from_token!
method current_user (line 13) | def current_user
method get_token (line 20) | def get_token
method raise_unauthorized (line 30) | def raise_unauthorized
FILE: app/controllers/api/v1/endpoints_controller.rb
class ::Api::V1::EndpointsController (line 1) | class ::Api::V1::EndpointsController < ::Api::V1::BaseController
method create (line 4) | def create
method add_group (line 17) | def add_group
method authorize_user (line 35) | def authorize_user
method group_param (line 41) | def group_param
method endpoint_param (line 45) | def endpoint_param
FILE: app/controllers/api/v1/groups_controller.rb
class ::Api::V1::GroupsController (line 1) | class ::Api::V1::GroupsController < ::Api::V1::BaseController
method create (line 2) | def create
method add_user (line 29) | def add_user
method group_params (line 45) | def group_params
FILE: app/controllers/api/v1/users_controller.rb
class ::Api::V1::UsersController (line 1) | class ::Api::V1::UsersController < ::Api::V1::BaseController
method create (line 4) | def create
method show (line 15) | def show
method deactivate (line 29) | def deactivate
method update (line 46) | def update
method set_user (line 54) | def set_user
method user_params (line 69) | def user_params
FILE: app/controllers/api/v1/vpns_controller.rb
class ::Api::V1::VpnsController (line 1) | class ::Api::V1::VpnsController < ::Api::V1::BaseController
method create (line 4) | def create
method assign_group (line 21) | def assign_group
method set_vpn (line 31) | def set_vpn
method vpn_params (line 35) | def vpn_params
FILE: app/controllers/api_resources_controller.rb
class ApiResourcesController (line 1) | class ApiResourcesController < ApplicationController
method index (line 8) | def index
method show (line 15) | def show; end
method authenticate (line 17) | def authenticate
method new (line 27) | def new
method edit (line 32) | def edit; end
method create (line 36) | def create
method update (line 57) | def update
method destroy (line 71) | def destroy
method search (line 81) | def search
method regenerate_access_key (line 93) | def regenerate_access_key
method set_api_resource (line 109) | def set_api_resource
method api_resource_params (line 114) | def api_resource_params
method authorize_user (line 118) | def authorize_user
FILE: app/controllers/application_controller.rb
class ApplicationController (line 1) | class ApplicationController < ActionController::Base
method render_404 (line 6) | def render_404
method authenticate_access_token! (line 14) | def authenticate_access_token!
method render_error (line 20) | def render_error(errors, status = 400)
FILE: app/controllers/groups_controller.rb
class GroupsController (line 1) | class GroupsController < ApplicationController
method index (line 7) | def index
method create (line 17) | def create
method new (line 35) | def new
method show (line 39) | def show
method delete_machine (line 53) | def delete_machine
method delete_user (line 62) | def delete_user
method add_user (line 74) | def add_user
method add_machine (line 94) | def add_machine
method add_admin (line 108) | def add_admin
method remove_admin (line 120) | def remove_admin
method add_vpn (line 132) | def add_vpn
method delete_vpn (line 144) | def delete_vpn
method add_group (line 157) | def add_group
method delete_group (line 172) | def delete_group
method list (line 186) | def list
method search (line 198) | def search
method set_group (line 210) | def set_group
method group_params (line 215) | def group_params
method expiration_date_param (line 219) | def expiration_date_param
FILE: app/controllers/home_controller.rb
class HomeController (line 1) | class HomeController < ApplicationController
method check_signed_in (line 5) | def check_signed_in
method index (line 9) | def index; end
FILE: app/controllers/host_controller.rb
class HostController (line 1) | class HostController < ApplicationController
method add_host (line 3) | def add_host
method delete_host (line 15) | def delete_host
FILE: app/controllers/host_machine_groups_controller.rb
class HostMachineGroupsController (line 1) | class HostMachineGroupsController < ApplicationController
method show (line 2) | def show
method create (line 6) | def create
method set_host_machine (line 18) | def set_host_machine
method host_machine_params (line 23) | def host_machine_params
FILE: app/controllers/host_machines_controller.rb
class HostMachinesController (line 1) | class HostMachinesController < ApplicationController
method index (line 6) | def index
method create (line 18) | def create
method show (line 31) | def show
method update (line 36) | def update
method add_group (line 41) | def add_group
method delete_group (line 56) | def delete_group
method search (line 63) | def search
method set_host_machine (line 75) | def set_host_machine
method host_machine_params (line 80) | def host_machine_params
method authorize_user (line 84) | def authorize_user
FILE: app/controllers/nss_controller.rb
class NssController (line 1) | class NssController < ApplicationController
method host (line 5) | def host
method add_host (line 23) | def add_host
method group (line 40) | def group
method passwd (line 56) | def passwd
method shadow (line 71) | def shadow
method groups_list (line 97) | def groups_list
FILE: app/controllers/organisations_controller.rb
class OrganisationsController (line 1) | class OrganisationsController < ApplicationController
method index (line 12) | def index
method new (line 16) | def new
method config_saml_app (line 20) | def config_saml_app
method save_config_saml_app (line 33) | def save_config_saml_app
method remove_user_saml_app (line 45) | def remove_user_saml_app
method add_user_saml_app (line 56) | def add_user_saml_app
method create (line 67) | def create
method update (line 78) | def update
method show (line 89) | def show
method setup_saml (line 93) | def setup_saml
method authorize_user (line 105) | def authorize_user
method load_org (line 114) | def load_org
method validate_app_name (line 122) | def validate_app_name
method organisation_params (line 129) | def organisation_params
FILE: app/controllers/pings_controller.rb
class PingsController (line 1) | class PingsController < ApplicationController
method show (line 2) | def show
FILE: app/controllers/profile_controller.rb
class ProfileController (line 1) | class ProfileController < ApplicationController
method regen_auth (line 7) | def regen_auth
method show (line 12) | def show
method user_admin (line 19) | def user_admin
method group_admin (line 40) | def group_admin
method user_id (line 61) | def user_id
method download_vpn (line 71) | def download_vpn
method download_vpn_for_ios_and_mac (line 84) | def download_vpn_for_ios_and_mac
method download_vpn_for_user (line 99) | def download_vpn_for_user
method authenticate (line 103) | def authenticate
method authenticate_ms_chap (line 112) | def authenticate_ms_chap
method authenticate_cas (line 117) | def authenticate_cas
method authenticate_pam (line 135) | def authenticate_pam
method verify (line 144) | def verify
method list (line 158) | def list
method admin (line 167) | def admin
method update (line 188) | def update
method user_edit (line 196) | def user_edit; end
method public_key_update (line 198) | def public_key_update
method public_key (line 207) | def public_key
method user (line 214) | def user
method admin_active (line 233) | def admin_active
FILE: app/controllers/saml_idp_controller.rb
class SamlIdpController (line 4) | class SamlIdpController < ApplicationController
method show (line 8) | def show
method idp_authenticate (line 21) | def idp_authenticate(email, password)
method idp_make_saml_response (line 26) | def idp_make_saml_response(found_user)
method idp_logout (line 30) | def idp_logout
method setup_saml_configuration (line 35) | def setup_saml_configuration
FILE: app/controllers/users/auth_controller.rb
class Users::AuthController (line 1) | class Users::AuthController < ApplicationController
method log_in (line 3) | def log_in
FILE: app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController (line 1) | class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksCont...
method google_oauth2 (line 2) | def google_oauth2
FILE: app/controllers/users_controller.rb
class UsersController (line 1) | class UsersController < ApplicationController
method index (line 5) | def index
method show (line 11) | def show
method new (line 44) | def new
method create (line 53) | def create
method update (line 69) | def update
method search (line 81) | def search
method regenerate_token (line 101) | def regenerate_token
method user_params (line 125) | def user_params
method form_response (line 131) | def form_response(message)
method product_name (line 137) | def product_name
method authorize_user (line 141) | def authorize_user
FILE: app/controllers/vpn_domain_name_servers_controller.rb
class VpnsController (line 1) | class VpnsController < ApplicationController
method destroy (line 5) | def destroy; end
class VpnDomainNameServersController (line 9) | class VpnDomainNameServersController < ApplicationController
FILE: app/controllers/vpns_controller.rb
class VpnsController (line 1) | class VpnsController < ApplicationController
method index (line 14) | def index
method update (line 18) | def update
method create (line 29) | def create
method new (line 43) | def new
method add_dns_server (line 47) | def add_dns_server
method add_search_domain (line 54) | def add_search_domain
method add_supplemental_match_domain (line 61) | def add_supplemental_match_domain
method remove_dns_server (line 71) | def remove_dns_server
method remove_search_domain (line 78) | def remove_search_domain
method remove_supplemental_match_domain (line 85) | def remove_supplemental_match_domain
method assign_group (line 92) | def assign_group
method show (line 100) | def show
method user_associated_groups (line 105) | def user_associated_groups
method group_associated_users (line 122) | def group_associated_users
method create_group_associated_users (line 142) | def create_group_associated_users
method destroy (line 176) | def destroy
method search (line 187) | def search
method set_vpn (line 198) | def set_vpn
method vpn_params (line 202) | def vpn_params
method authorize_user (line 206) | def authorize_user
FILE: app/helpers/admin_helper.rb
type AdminHelper (line 1) | module AdminHelper
FILE: app/helpers/api_resources_helper.rb
type ApiResourcesHelper (line 1) | module ApiResourcesHelper
FILE: app/helpers/application_helper.rb
type ApplicationHelper (line 1) | module ApplicationHelper
function add_placeholder_to_list (line 2) | def add_placeholder_to_list(list, placeholder, string_convert: 'titlei...
FILE: app/helpers/group_helper.rb
type GroupHelper (line 1) | module GroupHelper
FILE: app/helpers/groups_helper.rb
type GroupsHelper (line 1) | module GroupsHelper
FILE: app/helpers/home_helper.rb
type HomeHelper (line 1) | module HomeHelper
FILE: app/helpers/host_access_groups_helper.rb
type HostAccessGroupsHelper (line 1) | module HostAccessGroupsHelper
FILE: app/helpers/host_machine_groups_helper.rb
type HostMachineGroupsHelper (line 1) | module HostMachineGroupsHelper
FILE: app/helpers/host_machines_helper.rb
type HostMachinesHelper (line 1) | module HostMachinesHelper
FILE: app/helpers/nss_helper.rb
type NssHelper (line 1) | module NssHelper
FILE: app/helpers/omniauth_callbacks_helper.rb
type OmniauthCallbacksHelper (line 1) | module OmniauthCallbacksHelper
FILE: app/helpers/profile_helper.rb
type ProfileHelper (line 1) | module ProfileHelper
FILE: app/helpers/users_helper.rb
type UsersHelper (line 1) | module UsersHelper
FILE: app/lib/datadog.rb
class Datadog (line 1) | class Datadog < SamlApp
method initialize (line 3) | def initialize(org_id)
method save_config (line 16) | def save_config(sso_url, config = {})
method add_user (line 21) | def add_user(email)
method remove_user (line 31) | def remove_user(email)
FILE: app/lib/saml_app.rb
class SamlApp (line 1) | class SamlApp
method initialize (line 5) | def initialize(org_id)
method save_config (line 11) | def save_config(sso_url, config = {})
method add_user (line 20) | def add_user(email)
method remove_user (line 29) | def remove_user(email)
FILE: app/models/access_token.rb
class AccessToken (line 1) | class AccessToken < ApplicationRecord
method find_token (line 9) | def self.find_token challenge_token
method valid_token (line 13) | def self.valid_token challenge_token
method hash_token! (line 19) | def hash_token!
FILE: app/models/api_resource.rb
class ApiResource (line 1) | class ApiResource < ApplicationRecord
method authenticate (line 11) | def self.authenticate access_key, access_token
method hash_access_key! (line 19) | def hash_access_key!
FILE: app/models/application_record.rb
class ApplicationRecord (line 1) | class ApplicationRecord < ActiveRecord::Base
FILE: app/models/concerns/ms_chap_auth.rb
type MsChapAuth (line 1) | module MsChapAuth
function hexlify (line 3) | def hexlify(msg)
function unhexlify (line 7) | def unhexlify(msg)
function test_key (line 11) | def test_key key, challenge
function ntlm_challenge_response (line 20) | def ntlm_challenge_response word, challenge
function md4_hash (line 34) | def md4_hash word
function set_key_odd_parity (line 39) | def set_key_odd_parity key
function key56_to_key64 (line 51) | def key56_to_key64 key_raw
function nt_password_hash (line 76) | def nt_password_hash password
function get_nt_key (line 81) | def get_nt_key password
function authenticate_ms_chap (line 88) | def authenticate_ms_chap password, challenge, response
function authenticate_ms_chap_with_drift (line 95) | def authenticate_ms_chap_with_drift passwords, challenge, response
FILE: app/models/endpoint.rb
class Endpoint (line 1) | class Endpoint < ApplicationRecord
FILE: app/models/group.rb
class Group (line 1) | class Group < ApplicationRecord
method burst_host_cache (line 27) | def burst_host_cache
method add_admin (line 39) | def add_admin(user)
method set_lower_case_name (line 43) | def set_lower_case_name
method add_gid (line 47) | def add_gid
method get_name_response (line 52) | def self.get_name_response(name)
method get_all_response (line 64) | def self.get_all_response
method get_gid_response (line 78) | def self.get_gid_response(gid)
method admin? (line 85) | def admin?(user)
method member? (line 89) | def member?(user)
method generate_group_response (line 93) | def self.generate_group_response(name, gid, members)
method group_response (line 102) | def group_response
method group_nss_response (line 106) | def self.group_nss_response(name)
method get_sysadmins_and_groups (line 123) | def self.get_sysadmins_and_groups(sysadmins, default_admins = true)
method get_user_ids (line 152) | def get_user_ids
method get_default_sysadmin_group_for_host (line 164) | def self.get_default_sysadmin_group_for_host(sysadmins_login_ids, defa...
method add_user (line 180) | def add_user(user_id)
method add_user_with_expiration (line 184) | def add_user_with_expiration(user_id, expiration_date)
method remove_user (line 189) | def remove_user(user_id)
FILE: app/models/group_admin.rb
class GroupAdmin (line 1) | class GroupAdmin < ApplicationRecord
FILE: app/models/group_association.rb
class GroupAssociation (line 1) | class GroupAssociation < ApplicationRecord
method revoke_expired (line 5) | def self.revoke_expired(date = Date.today)
FILE: app/models/group_endpoint.rb
class GroupEndpoint (line 1) | class GroupEndpoint < ApplicationRecord
FILE: app/models/host.rb
class Host (line 1) | class Host < ApplicationRecord
FILE: app/models/host_access_group.rb
class HostAccessGroup (line 1) | class HostAccessGroup < ApplicationRecord
FILE: app/models/host_machine.rb
class HostMachine (line 1) | class HostMachine < ApplicationRecord
method set_host_access_key (line 11) | def set_host_access_key
method set_lower_case_name (line 15) | def set_lower_case_name
method get_group_response (line 19) | def self.get_group_response name
method sysadmins (line 28) | def sysadmins
method add_host_group (line 37) | def add_host_group(name)
method add_group (line 45) | def add_group(name)
FILE: app/models/ip_address.rb
class IpAddress (line 1) | class IpAddress < ApplicationRecord
FILE: app/models/organisation.rb
class Organisation (line 1) | class Organisation < ApplicationRecord
method find_by_slug (line 17) | def self.find_by_slug(slug)
method setup (line 21) | def self.setup(attrs = {})
method update_profile (line 29) | def update_profile(attrs = {})
method saml_setup? (line 36) | def saml_setup?
method setup_saml_certs (line 40) | def setup_saml_certs
FILE: app/models/saml_app_config.rb
class SamlAppConfig (line 1) | class SamlAppConfig < ApplicationRecord
method get_config (line 7) | def self.get_config(app_name, org_id)
FILE: app/models/user.rb
class User (line 1) | class User < ApplicationRecord
method add_user (line 30) | def self.add_user(first_name, last_name, user_role, domain)
method generate_login_id (line 43) | def generate_login_id
method generate_uid (line 47) | def generate_uid(uid_buffer = 5000)
method initialise_host_and_group (line 52) | def initialise_host_and_group
method generate_two_factor_auth (line 61) | def generate_two_factor_auth(force_create = false)
method create_user (line 70) | def self.create_user(name, email)
method add_temp_user (line 83) | def self.add_temp_user(name, email)
method update_profile (line 90) | def update_profile(attrs = {})
method name_email (line 101) | def name_email
method get_sysadmins (line 105) | def self.get_sysadmins user_ids
method purge! (line 135) | def purge!
method includes_restricted_characters? (line 141) | def self.includes_restricted_characters? input_string
method check_email_address (line 154) | def self.check_email_address email_address
method valid_domain? (line 158) | def self.valid_domain? domain
method verify (line 163) | def self.verify params
method authenticate_pam (line 175) | def self.authenticate_pam params
method check_user_host (line 189) | def self.check_user_host email, address_array
method permitted_vpns? (line 194) | def permitted_vpns? address_array
method permitted_hosts? (line 203) | def permitted_hosts? address_array
method authenticate_cas (line 219) | def self.authenticate_cas encoded_string
method authenticate (line 232) | def self.authenticate params
method get_user (line 238) | def self.get_user user_login_id
method find_and_validate_saml_user (line 242) | def self.find_and_validate_saml_user(email, password, app_name)
method valid_otp? (line 252) | def valid_otp?(password)
method find_and_check_user (line 260) | def self.find_and_check_user email, token
method get_user_pass_attributes (line 271) | def self.get_user_pass_attributes params
method get_shadow_name_response (line 279) | def self.get_shadow_name_response name
method get_shadow_hash (line 286) | def get_shadow_hash
method get_all_shadow_response (line 300) | def self.get_all_shadow_response
method get_all_passwd_response (line 308) | def self.get_all_passwd_response
method get_passwd_name_response (line 316) | def self.get_passwd_name_response name
method response_array (line 322) | def self.response_array response
method find_active_user_by_email (line 328) | def self.find_active_user_by_email(email)
method group_names_list (line 332) | def group_names_list
method reset_login_limit (line 336) | def reset_login_limit
method within_limits? (line 341) | def within_limits?
method ms_chap_auth (line 348) | def self.ms_chap_auth params
method get_user_otp (line 375) | def get_user_otp
method get_user_otp_at (line 379) | def get_user_otp_at time
method user_passwd_response (line 383) | def user_passwd_response
method group_admin? (line 406) | def group_admin?
method permitted_endpoint? (line 410) | def permitted_endpoint?(endpoint)
method remove_default_admin (line 422) | def remove_default_admin
method validate_email_domain (line 429) | def validate_email_domain
method revoke_admin_when_inactive (line 435) | def revoke_admin_when_inactive
method set_deactivated_at_when_inactive (line 439) | def set_deactivated_at_when_inactive
FILE: app/models/vpn.rb
class Vpn (line 1) | class Vpn < ApplicationRecord
method administrator? (line 15) | def self.administrator?(user)
method managed_vpns (line 21) | def self.managed_vpns(user)
method user_vpns (line 32) | def self.user_vpns user
method migrate_to_new_group (line 43) | def migrate_to_new_group
FILE: app/models/vpn_domain_name_server.rb
class VpnDomainNameServer (line 1) | class VpnDomainNameServer < ApplicationRecord
FILE: app/models/vpn_group_association.rb
class VpnGroupAssociation (line 1) | class VpnGroupAssociation < ApplicationRecord
FILE: app/models/vpn_group_user_association.rb
class VpnGroupUserAssociation (line 1) | class VpnGroupUserAssociation < ApplicationRecord
FILE: app/models/vpn_search_domain.rb
class VpnSearchDomain (line 1) | class VpnSearchDomain < ApplicationRecord
FILE: app/models/vpn_supplemental_match_domain.rb
class VpnSupplementalMatchDomain (line 1) | class VpnSupplementalMatchDomain < ApplicationRecord
FILE: app/validators/email_validator.rb
class EmailValidator (line 1) | class EmailValidator < ActiveModel::EachValidator
method validate_each (line 2) | def validate_each(record, attribute, value)
FILE: config/application.rb
type Gate (line 9) | module Gate
class Application (line 10) | class Application < Rails::Application
FILE: db/migrate/20160419122430_devise_create_users.rb
class DeviseCreateUsers (line 1) | class DeviseCreateUsers < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20160419132647_add_provider_to_users.rb
class AddProviderToUsers (line 1) | class AddProviderToUsers < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20160419144739_add_name_to_users.rb
class AddNameToUsers (line 1) | class AddNameToUsers < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20160427123146_add_auth_key_to_user.rb
class AddAuthKeyToUser (line 1) | class AddAuthKeyToUser < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20160427123233_add_provisioning_uri_to_user.rb
class AddProvisioningUriToUser (line 1) | class AddProvisioningUriToUser < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20160519042340_add_active_to_users.rb
class AddActiveToUsers (line 1) | class AddActiveToUsers < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20160519064340_add_default_value_to_users.rb
class AddDefaultValueToUsers (line 1) | class AddDefaultValueToUsers < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20160615044834_create_hosts.rb
class CreateHosts (line 1) | class CreateHosts < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20160615045052_add_admin_to_user.rb
class AddAdminToUser (line 1) | class AddAdminToUser < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20160615112805_add_user_to_host.rb
class AddUserToHost (line 1) | class AddUserToHost < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20160628140022_add_deleted_at_to_host.rb
class AddDeletedAtToHost (line 1) | class AddDeletedAtToHost < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20160628140440_add_deleted_by_to_host.rb
class AddDeletedByToHost (line 1) | class AddDeletedByToHost < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20160629043358_add_homedir_to_user.rb
class AddHomedirToUser (line 1) | class AddHomedirToUser < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20160629043415_add_shell_to_user.rb
class AddShellToUser (line 1) | class AddShellToUser < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20160629075435_create_groups.rb
class CreateGroups (line 1) | class CreateGroups < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20160701090045_create_group_associations.rb
class CreateGroupAssociations (line 1) | class CreateGroupAssociations < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20160701112600_add_deleted_properties_to_group.rb
class AddDeletedPropertiesToGroup (line 1) | class AddDeletedPropertiesToGroup < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20160707115313_create_access_tokens.rb
class CreateAccessTokens (line 1) | class CreateAccessTokens < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20160714115228_add_public_key_to_user.rb
class AddPublicKeyToUser (line 1) | class AddPublicKeyToUser < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20160908081651_create_host_machines.rb
class CreateHostMachines (line 1) | class CreateHostMachines < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20161003145832_create_host_access_groups.rb
class CreateHostAccessGroups (line 1) | class CreateHostAccessGroups < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20170803140620_add_user_login_id_to_user.rb
class AddUserLoginIdToUser (line 1) | class AddUserLoginIdToUser < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20171013115441_create_versions.rb
class CreateVersions (line 3) | class CreateVersions < ActiveRecord::Migration[5.0]
method change (line 11) | def change
FILE: db/migrate/20171016064705_remove_index_group_name.rb
class RemoveIndexGroupName (line 1) | class RemoveIndexGroupName < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20171016071526_add_unique_index_on_groups_name.rb
class AddUniqueIndexOnGroupsName (line 1) | class AddUniqueIndexOnGroupsName < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20171031060034_create_group_admin.rb
class CreateGroupAdmin (line 1) | class CreateGroupAdmin < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20171031060217_add_foreign_key_ref_on_group_admin.rb
class AddForeignKeyRefOnGroupAdmin (line 1) | class AddForeignKeyRefOnGroupAdmin < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20171031100758_create_vpns.rb
class CreateVpns (line 1) | class CreateVpns < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20171031101026_create_vpn_group_association.rb
class CreateVpnGroupAssociation (line 1) | class CreateVpnGroupAssociation < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20171031103518_add_foreign_key_ref_on_vpn_group_association.rb
class AddForeignKeyRefOnVpnGroupAssociation (line 1) | class AddForeignKeyRefOnVpnGroupAssociation < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20171031113123_create_vpn_group_user_association.rb
class CreateVpnGroupUserAssociation (line 1) | class CreateVpnGroupUserAssociation < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20171031121702_add_foreign_key_ref_on_vpn_group_user_association.rb
class AddForeignKeyRefOnVpnGroupUserAssociation (line 1) | class AddForeignKeyRefOnVpnGroupUserAssociation < ActiveRecord::Migratio...
method change (line 2) | def change
FILE: db/migrate/20171102071909_add_ip_address_to_vpns.rb
class AddIpAddressToVpns (line 1) | class AddIpAddressToVpns < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20171107114249_remove_url_from_vpns.rb
class RemoveUrlFromVpns (line 1) | class RemoveUrlFromVpns < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20171108130234_add_user_id_to_access_token.rb
class AddUserIdToAccessToken (line 1) | class AddUserIdToAccessToken < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20171108130353_add_foreign_key_ref_on_access_tokens.rb
class AddForeignKeyRefOnAccessTokens (line 1) | class AddForeignKeyRefOnAccessTokens < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20171124090240_add_uuid_to_vpns.rb
class AddUuidToVpns (line 1) | class AddUuidToVpns < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20171124114427_create_vpn_domain_name_servers.rb
class CreateVpnDomainNameServers (line 1) | class CreateVpnDomainNameServers < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20171124114830_create_vpn_search_domains.rb
class CreateVpnSearchDomains (line 1) | class CreateVpnSearchDomains < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20171124115925_create_vpn_supplemental_match_domains.rb
class CreateVpnSupplementalMatchDomains (line 1) | class CreateVpnSupplementalMatchDomains < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20180104081814_add_product_name_to_users.rb
class AddProductNameToUsers (line 1) | class AddProductNameToUsers < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20180202102206_create_saml_service_providers.rb
class CreateSamlServiceProviders (line 1) | class CreateSamlServiceProviders < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20180214050204_add_api_key_to_host_machines.rb
class AddApiKeyToHostMachines (line 1) | class AddApiKeyToHostMachines < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20180214052451_create_ip_addresses.rb
class CreateIpAddresses (line 1) | class CreateIpAddresses < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20180214052644_add_host_machine_to_ip_address.rb
class AddHostMachineToIpAddress (line 1) | class AddHostMachineToIpAddress < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20180219150818_add_description_to_group.rb
class AddDescriptionToGroup (line 1) | class AddDescriptionToGroup < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20180222135930_add_access_key_to_host_machine.rb
class AddAccessKeyToHostMachine (line 1) | class AddAccessKeyToHostMachine < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20180222140000_add_access_key_to_user.rb
class AddAccessKeyToUser (line 1) | class AddAccessKeyToUser < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20180227051732_create_api_resources.rb
class CreateApiResources (line 1) | class CreateApiResources < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20180301010021_add_user_to_api_resources.rb
class AddUserToApiResources (line 1) | class AddUserToApiResources < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20180301010035_add_group_to_api_resources.rb
class AddGroupToApiResources (line 1) | class AddGroupToApiResources < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20180306231200_add_deactivated_at_to_users.rb
class AddDeactivatedAtToUsers (line 1) | class AddDeactivatedAtToUsers < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20180311082600_rename_access_key_in_api_resources.rb
class RenameAccessKeyInApiResources (line 1) | class RenameAccessKeyInApiResources < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20180311161200_rename_token_in_access_tokens.rb
class RenameTokenInAccessTokens (line 1) | class RenameTokenInAccessTokens < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20180318083000_create_indexes_to_speedup_nss_controller.rb
class CreateIndexesToSpeedupNssController (line 1) | class CreateIndexesToSpeedupNssController < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20180613074108_create_organisations.rb
class CreateOrganisations (line 1) | class CreateOrganisations < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20180613165050_drop_saml_service_providers.rb
class DropSamlServiceProviders (line 1) | class DropSamlServiceProviders < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20180723175600_update_organisations_for_saml.rb
class UpdateOrganisationsForSaml (line 1) | class UpdateOrganisationsForSaml < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20181002023107_add_default_admins_to_host_machines.rb
class AddDefaultAdminsToHostMachines (line 1) | class AddDefaultAdminsToHostMachines < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20181016093315_create_saml_app_configs.rb
class CreateSamlAppConfigs (line 1) | class CreateSamlAppConfigs < ActiveRecord::Migration[5.0]
method change (line 2) | def change
FILE: db/migrate/20181208184236_add_fields_to_user.rb
class AddFieldsToUser (line 1) | class AddFieldsToUser < ActiveRecord::Migration[5.1]
method change (line 2) | def change
FILE: db/migrate/20190624024930_add_expiration_date_to_group_associations.rb
class AddExpirationDateToGroupAssociations (line 1) | class AddExpirationDateToGroupAssociations < ActiveRecord::Migration[5.1]
method change (line 2) | def change
FILE: db/migrate/20190820070910_create_endpoints.rb
class CreateEndpoints (line 1) | class CreateEndpoints < ActiveRecord::Migration[5.1]
method change (line 2) | def change
FILE: db/migrate/20190820075040_create_group_endpoints.rb
class CreateGroupEndpoints (line 1) | class CreateGroupEndpoints < ActiveRecord::Migration[5.1]
method change (line 2) | def change
FILE: db/migrate/20190820080624_add_foreign_key_ref_on_group_endpoints.rb
class AddForeignKeyRefOnGroupEndpoints (line 1) | class AddForeignKeyRefOnGroupEndpoints < ActiveRecord::Migration[5.1]
method change (line 2) | def change
FILE: db/migrate/20200113065717_add_sessions_table.rb
class AddSessionsTable (line 1) | class AddSessionsTable < ActiveRecord::Migration[5.1]
method change (line 2) | def change
FILE: db/migrate/20220926001848_add_service_name_to_active_storage_blobs.active_storage.rb
class AddServiceNameToActiveStorageBlobs (line 2) | class AddServiceNameToActiveStorageBlobs < ActiveRecord::Migration[6.0]
method up (line 3) | def up
method down (line 17) | def down
FILE: db/migrate/20220926001849_create_active_storage_variant_records.active_storage.rb
class CreateActiveStorageVariantRecords (line 2) | class CreateActiveStorageVariantRecords < ActiveRecord::Migration[6.0]
method change (line 3) | def change
method primary_key_type (line 17) | def primary_key_type
method blobs_primary_key_type (line 22) | def blobs_primary_key_type
FILE: db/migrate/20220926001850_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb
class RemoveNotNullOnActiveStorageBlobsChecksum (line 2) | class RemoveNotNullOnActiveStorageBlobsChecksum < ActiveRecord::Migratio...
method change (line 3) | def change
FILE: lib/vpn/mobileconfig.rb
class Mobileconfig (line 5) | class Mobileconfig
method generate (line 6) | def generate (vpns, user)
method sign_mobileconfig (line 44) | def sign_mobileconfig(mobileconfig)
FILE: lib/vpn/namespace.rb
class Namespace (line 1) | class Namespace
method initialize (line 2) | def initialize(hash)
method get_binding (line 7) | def get_binding
FILE: spec/controllers/api/v1/api_controller_spec.rb
function index (line 6) | def index
FILE: spec/support/helpers/x509_certificate_helper.rb
class CertificateHelper (line 1) | class CertificateHelper
method initialize (line 2) | def initialize
method get_cert (line 19) | def get_cert
method get_private_key (line 23) | def get_private_key
method get_fingerprint (line 27) | def get_fingerprint
Condensed preview — 370 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (534K chars).
[
{
"path": ".deepsource.toml",
"chars": 106,
"preview": "version = 1\n\n[[analyzers]]\nname = \"ruby\"\nenabled = true\n\n[[analyzers]]\nname = \"javascript\"\nenabled = true\n"
},
{
"path": ".dockerignore",
"chars": 87,
"preview": "/log/*\n!/log/.keep\n/tmp\n.idea\n.env\n*.swp\nconfig/application.yml\ndump.rdb\ncoverage\n.git\n"
},
{
"path": ".gitignore",
"chars": 583,
"preview": "# See https://help.github.com/articles/ignoring-files for more about ignoring files.\n#\n# If you find yourself ignoring t"
},
{
"path": ".rspec",
"chars": 53,
"preview": "--color\n--format documentation\n--require spec_helper\n"
},
{
"path": ".rubocop.yml",
"chars": 19585,
"preview": "---\nrequire: \n - rubocop-rails\n - rubocop-performance\n - rubocop-faker\n\nAllCops:\n NewCops: enable\n Exclude:\n - con"
},
{
"path": ".ruby-version",
"chars": 11,
"preview": "ruby-3.1.2\n"
},
{
"path": ".travis.yml",
"chars": 5080,
"preview": "dist: xenial\nsudo: required\nlanguage: ruby\nrvm:\n - ruby-2.4.4\nservices:\n - redis-server\n - mysql\n\nenv:\n global:\n - "
},
{
"path": "CHANGELOG.md",
"chars": 2523,
"preview": "# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changel"
},
{
"path": "CONTRIBUTING.md",
"chars": 447,
"preview": "# Contributing Guidelines\n\n## Releasing Gate\n\n> Gate uses semantic versioning, check [this page](https://semver.org/) fo"
},
{
"path": "Dockerfile",
"chars": 365,
"preview": "FROM ruby:2.4\n\nRUN apt-get update\nRUN curl -sL https://deb.nodesource.com/setup_10.x | bash\nRUN apt-get update -qq && ap"
},
{
"path": "Gemfile",
"chars": 1200,
"preview": "source 'https://rubygems.org'\n\ngem 'rails', '7.1.3.2'\n\ngem 'activerecord-session_store'\ngem 'ansi'\ngem 'bootstrap'\ngem '"
},
{
"path": "LICENSE",
"chars": 1075,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2016 gate-sso\n\nPermission is hereby granted, free of charge, to any person obtainin"
},
{
"path": "README.md",
"chars": 5334,
"preview": "# Gate is now Gate-WireGuard \n\n## DEPRECATED\n\n#### Please use [Gate-WireGuard](https://github.com/gate-sso/gate-wireguar"
},
{
"path": "Rakefile",
"chars": 249,
"preview": "# Add your own tasks in files placed in lib/tasks ending in .rake,\n# for example lib/tasks/capistrano.rake, and they wil"
},
{
"path": "VERSION",
"chars": 6,
"preview": "1.1.8\n"
},
{
"path": "api_blueprint/bin/dredd_server.sh",
"chars": 170,
"preview": "#!/bin/bash\n# dredd_server.sh\nkill -9 $(lsof -i tcp:9865 -t)\nexport RAILS_ENV=test\nexport LOG_LEVEL=info\nrake db:drop\nra"
},
{
"path": "api_blueprint/group.apib",
"chars": 4372,
"preview": "FORMAT: 1A\n\n# API Group\n\n# Group [/api/v1/groups]\n\n## Create Groups [POST]\nCreate new group\n\n+ Request(application/json)"
},
{
"path": "api_blueprint/hooks/dredd_hooks.rb",
"chars": 639,
"preview": "ENV['RAILS_ENV'] ||= 'test'\n\nrequire File.expand_path('../../config/environment', __dir__)\nrequire 'dredd_hooks/methods'"
},
{
"path": "api_blueprint/user.apib",
"chars": 6560,
"preview": "FORMAT: 1A\n\n# API User\n\n# User [/api/v1/users]\n\n## Create Users [POST]\nCreate new users gate\n\n+ Request(application/json"
},
{
"path": "api_blueprint/vpns.apib",
"chars": 1601,
"preview": "FORMAT: 1A\n\n# API VPNS\n\n# VPNS [/api/v1/vpns]\n\n## Create VPNS [POST]\nCreate new vpns\n\n+ Request(application/json)\n\n +"
},
{
"path": "app/assets/config/manifest.js",
"chars": 210,
"preview": "//= link application.css\n//= link apple-touch-icon-144x144-precomposed.png\n//= link apple-touch-icon-72x72-precomposed.p"
},
{
"path": "app/assets/images/.keep",
"chars": 0,
"preview": ""
},
{
"path": "app/assets/javascripts/admin.coffee",
"chars": 211,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/api_resources.coffee",
"chars": 1132,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/application.js",
"chars": 707,
"preview": "// This is a manifest file that'll be compiled into application.js, which will include all the files\n// listed below.\n//"
},
{
"path": "app/assets/javascripts/bootstrap.js.coffee",
"chars": 104,
"preview": "jQuery ->\n $(\"a[rel~=popover], .has-popover\").popover()\n $(\"a[rel~=tooltip], .has-tooltip\").tooltip()\n"
},
{
"path": "app/assets/javascripts/group.coffee",
"chars": 3553,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/groups.coffee",
"chars": 211,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/home.coffee",
"chars": 211,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/host_access_groups.coffee",
"chars": 211,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/host_machine_groups.coffee",
"chars": 211,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/host_machines.coffee",
"chars": 924,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/nss.coffee",
"chars": 211,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/omniauth_callbacks.coffee",
"chars": 211,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/profile.coffee",
"chars": 211,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/users.coffee",
"chars": 908,
"preview": "# Place all the behaviors and hooks related to the matching controller here.\n# All this logic will automatically be avai"
},
{
"path": "app/assets/javascripts/utilities.coffee",
"chars": 1039,
"preview": "# Utility functions\n\n@append_error_msg = (elem, res, msg) ->\n if !res\n elem.addClass('is-invalid')\n elem.next('.i"
},
{
"path": "app/assets/javascripts/viewport.js",
"chars": 641,
"preview": "/*!\n * IE10 viewport hack for Surface/desktop Windows 8 bug\n * Copyright 2014-2015 Twitter, Inc.\n * Licensed under MIT ("
},
{
"path": "app/assets/stylesheets/application.scss",
"chars": 1589,
"preview": "/*\n * This is a manifest file that'll be compiled into application.css, which will include all the files\n * listed below"
},
{
"path": "app/assets/stylesheets/bootstrap-social.scss",
"chars": 17512,
"preview": "/*\n * Social Buttons for Bootstrap\n *\n * Copyright 2013-2016 Panayiotis Lipiridis\n * Licensed under the MIT License\n *\n "
},
{
"path": "app/assets/stylesheets/general.css",
"chars": 30,
"preview": "body {\n padding-top: 70px;\n}\n"
},
{
"path": "app/assets/stylesheets/home.scss.erb",
"chars": 1376,
"preview": "// Place all the styles related to the Home controller here.\n// They will automatically be included in application.css.\n"
},
{
"path": "app/assets/stylesheets/profile.css",
"chars": 140,
"preview": "/* Everything but the jumbotron gets side spacing for mobile first views */\n\n.container-profile {\n max-width: 730px;\n "
},
{
"path": "app/assets/stylesheets/scaffolds.scss",
"chars": 1031,
"preview": "body {\n background-color: #fff;\n color: #333;\n font-family: verdana, arial, helvetica, sans-serif;\n font-size: 13px;"
},
{
"path": "app/clients/data_dog_client.rb",
"chars": 1501,
"preview": "class DataDogClient\n include HTTParty\n base_uri 'https://api.datadoghq.com/api/v1'\n\n def initialize(app_key, api_key)"
},
{
"path": "app/controllers/admin_controller.rb",
"chars": 67,
"preview": "class AdminController < ApplicationController\n def index; end\nend\n"
},
{
"path": "app/controllers/api/v1/base_controller.rb",
"chars": 713,
"preview": "class ::Api::V1::BaseController < ActionController::Base\n protect_from_forgery with: :null_session\n before_action :aut"
},
{
"path": "app/controllers/api/v1/endpoints_controller.rb",
"chars": 985,
"preview": "class ::Api::V1::EndpointsController < ::Api::V1::BaseController\n before_action :authorize_user\n\n def create\n endpo"
},
{
"path": "app/controllers/api/v1/groups_controller.rb",
"chars": 1309,
"preview": "class ::Api::V1::GroupsController < ::Api::V1::BaseController\n def create\n if current_user.admin?\n @group = Gro"
},
{
"path": "app/controllers/api/v1/users_controller.rb",
"chars": 2158,
"preview": "class ::Api::V1::UsersController < ::Api::V1::BaseController\n before_action :set_user, only: %i[show update]\n\n def cre"
},
{
"path": "app/controllers/api/v1/vpns_controller.rb",
"chars": 886,
"preview": "class ::Api::V1::VpnsController < ::Api::V1::BaseController\n before_action :set_vpn, only: [:assign_group]\n\n def creat"
},
{
"path": "app/controllers/api_resources_controller.rb",
"chars": 4412,
"preview": "class ApiResourcesController < ApplicationController\n before_action :set_api_resource, only: %i[show edit update destro"
},
{
"path": "app/controllers/application_controller.rb",
"chars": 706,
"preview": "class ApplicationController < ActionController::Base\n # Prevent CSRF attacks by raising an exception.\n # For APIs, you"
},
{
"path": "app/controllers/concerns/.keep",
"chars": 0,
"preview": ""
},
{
"path": "app/controllers/groups_controller.rb",
"chars": 6072,
"preview": "class GroupsController < ApplicationController\n before_action :set_group, only: %i[show edit update destroy\n "
},
{
"path": "app/controllers/home_controller.rb",
"chars": 173,
"preview": "class HomeController < ApplicationController\n\n before_action :check_signed_in\n\n def check_signed_in\n redirect_to pr"
},
{
"path": "app/controllers/host_controller.rb",
"chars": 564,
"preview": "class HostController < ApplicationController\n before_action :authenticate_user!\n def add_host\n @user = User.find(pa"
},
{
"path": "app/controllers/host_machine_groups_controller.rb",
"chars": 764,
"preview": "class HostMachineGroupsController < ApplicationController\n def show\n @host_machines = HostMachine.all\n end\n\n def c"
},
{
"path": "app/controllers/host_machines_controller.rb",
"chars": 2620,
"preview": "class HostMachinesController < ApplicationController\n before_action :set_host_machine, only: %i[add_group show edit upd"
},
{
"path": "app/controllers/nss_controller.rb",
"chars": 3797,
"preview": "class NssController < ApplicationController\n skip_before_action :verify_authenticity_token, only: %i[add_host add_user_"
},
{
"path": "app/controllers/organisations_controller.rb",
"chars": 3727,
"preview": "class OrganisationsController < ApplicationController\n before_action :authorize_user, except: [:index]\n before_action "
},
{
"path": "app/controllers/pings_controller.rb",
"chars": 92,
"preview": "class PingsController < ApplicationController\n def show\n render plain: 'pong'\n end\nend\n"
},
{
"path": "app/controllers/profile_controller.rb",
"chars": 6344,
"preview": "class ProfileController < ApplicationController\n require 'vpn/mobileconfig'\n\n skip_before_action :verify_authenticity_"
},
{
"path": "app/controllers/saml_idp_controller.rb",
"chars": 2071,
"preview": "#TODO rename back to SAMLController\n\n#class SamlIdpController < SamlIdp::IdpController\nclass SamlIdpController < Applica"
},
{
"path": "app/controllers/users/auth_controller.rb",
"chars": 500,
"preview": "class Users::AuthController < ApplicationController\n\n def log_in\n unless ENV['SIGN_IN_TYPE'] == 'form'\n return "
},
{
"path": "app/controllers/users/omniauth_callbacks_controller.rb",
"chars": 733,
"preview": "class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController\n def google_oauth2\n # You need to imp"
},
{
"path": "app/controllers/users_controller.rb",
"chars": 4114,
"preview": "class UsersController < ApplicationController\n before_action :authenticate_user!, except: %i[user_id verify authenticat"
},
{
"path": "app/controllers/vpn_domain_name_servers_controller.rb",
"chars": 306,
"preview": "class VpnsController < ApplicationController\n before_action :authorize_user\n before_action :set_vpn, only: %i[show edi"
},
{
"path": "app/controllers/vpns_controller.rb",
"chars": 6323,
"preview": "class VpnsController < ApplicationController\n before_action :authorize_user, except: %i[create_group_associated_users s"
},
{
"path": "app/helpers/admin_helper.rb",
"chars": 23,
"preview": "module AdminHelper\nend\n"
},
{
"path": "app/helpers/api_resources_helper.rb",
"chars": 30,
"preview": "module ApiResourcesHelper\nend\n"
},
{
"path": "app/helpers/application_helper.rb",
"chars": 268,
"preview": "module ApplicationHelper\n def add_placeholder_to_list(list, placeholder, string_convert: 'titleize')\n (list.map do |"
},
{
"path": "app/helpers/group_helper.rb",
"chars": 23,
"preview": "module GroupHelper\nend\n"
},
{
"path": "app/helpers/groups_helper.rb",
"chars": 24,
"preview": "module GroupsHelper\nend\n"
},
{
"path": "app/helpers/home_helper.rb",
"chars": 22,
"preview": "module HomeHelper\nend\n"
},
{
"path": "app/helpers/host_access_groups_helper.rb",
"chars": 34,
"preview": "module HostAccessGroupsHelper\nend\n"
},
{
"path": "app/helpers/host_machine_groups_helper.rb",
"chars": 35,
"preview": "module HostMachineGroupsHelper\nend\n"
},
{
"path": "app/helpers/host_machines_helper.rb",
"chars": 30,
"preview": "module HostMachinesHelper\nend\n"
},
{
"path": "app/helpers/nss_helper.rb",
"chars": 21,
"preview": "module NssHelper\nend\n"
},
{
"path": "app/helpers/omniauth_callbacks_helper.rb",
"chars": 35,
"preview": "module OmniauthCallbacksHelper\nend\n"
},
{
"path": "app/helpers/profile_helper.rb",
"chars": 25,
"preview": "module ProfileHelper\nend\n"
},
{
"path": "app/helpers/users_helper.rb",
"chars": 23,
"preview": "module UsersHelper\nend\n"
},
{
"path": "app/lib/datadog.rb",
"chars": 851,
"preview": "class Datadog < SamlApp\n\n def initialize(org_id)\n @app_name = 'datadog'\n super(org_id)\n if @config.persisted?\n"
},
{
"path": "app/lib/saml_app.rb",
"chars": 805,
"preview": "class SamlApp\n\n attr_accessor :config, :app_name\n\n def initialize(org_id)\n @config = SamlAppConfig.find_or_initiali"
},
{
"path": "app/mailers/.keep",
"chars": 0,
"preview": ""
},
{
"path": "app/models/.keep",
"chars": 0,
"preview": ""
},
{
"path": "app/models/access_token.rb",
"chars": 452,
"preview": "class AccessToken < ApplicationRecord\n attr_accessor :token\n\n\n belongs_to :user\n\n before_save :hash_token!\n\n def sel"
},
{
"path": "app/models/api_resource.rb",
"chars": 707,
"preview": "class ApiResource < ApplicationRecord\n attr_accessor :access_key\n\n validates :name, format: { with: /\\A[a-zA-Z0-9_-]+\\"
},
{
"path": "app/models/application_record.rb",
"chars": 78,
"preview": "class ApplicationRecord < ActiveRecord::Base\n self.abstract_class = true\nend\n"
},
{
"path": "app/models/concerns/.keep",
"chars": 0,
"preview": ""
},
{
"path": "app/models/concerns/ms_chap_auth.rb",
"chars": 2927,
"preview": "module MsChapAuth\n\n def hexlify(msg)\n msg.unpack('H*').first\n end\n\n def unhexlify(msg)\n msg.scan(/../).collect "
},
{
"path": "app/models/endpoint.rb",
"chars": 344,
"preview": "class Endpoint < ApplicationRecord\n\n\n has_many :group_endpoints\n has_many :groups, through: :group_endpoints\n\n valida"
},
{
"path": "app/models/group.rb",
"chars": 5307,
"preview": "class Group < ApplicationRecord\n\n has_many :group_admins, dependent: :destroy\n has_many :group_associations\n has_many"
},
{
"path": "app/models/group_admin.rb",
"chars": 80,
"preview": "class GroupAdmin < ApplicationRecord\n belongs_to :user\n belongs_to :group\nend\n"
},
{
"path": "app/models/group_association.rb",
"chars": 189,
"preview": "class GroupAssociation < ApplicationRecord\n belongs_to :user\n belongs_to :group\n\n def self.revoke_expired(date = Date"
},
{
"path": "app/models/group_endpoint.rb",
"chars": 208,
"preview": "class GroupEndpoint < ApplicationRecord\n\n\n belongs_to :group\n belongs_to :endpoint\n\n validates :group, uniqueness: { "
},
{
"path": "app/models/host.rb",
"chars": 73,
"preview": "class Host < ApplicationRecord\n belongs_to :user\n acts_as_paranoid\nend\n"
},
{
"path": "app/models/host_access_group.rb",
"chars": 93,
"preview": "class HostAccessGroup < ApplicationRecord\n belongs_to :host_machine\n belongs_to :group\nend\n"
},
{
"path": "app/models/host_machine.rb",
"chars": 1272,
"preview": "class HostMachine < ApplicationRecord\n\n has_many :host_access_groups\n has_many :groups, through: :host_access_groups\n "
},
{
"path": "app/models/ip_address.rb",
"chars": 40,
"preview": "class IpAddress < ApplicationRecord\nend\n"
},
{
"path": "app/models/organisation.rb",
"chars": 2303,
"preview": "class Organisation < ApplicationRecord\n validates :name, :website, :domain, :country, :state, :address,\n :ad"
},
{
"path": "app/models/saml_app_config.rb",
"chars": 262,
"preview": "class SamlAppConfig < ApplicationRecord\n belongs_to :group\n belongs_to :organisation\n\n serialize :config, JSON\n\n def"
},
{
"path": "app/models/user.rb",
"chars": 12507,
"preview": "class User < ApplicationRecord\n\n\n include MsChapAuth\n devise :timeoutable, :omniauthable, omniauth_providers: [:google"
},
{
"path": "app/models/vpn.rb",
"chars": 1981,
"preview": "class Vpn < ApplicationRecord\n belongs_to :user\n belongs_to :group\n\n has_many :vpn_group_associations\n has_many :gro"
},
{
"path": "app/models/vpn_domain_name_server.rb",
"chars": 68,
"preview": "class VpnDomainNameServer < ApplicationRecord\n belongs_to :vpn\nend\n"
},
{
"path": "app/models/vpn_group_association.rb",
"chars": 89,
"preview": "class VpnGroupAssociation < ApplicationRecord\n belongs_to :vpn\n belongs_to :group\nend\n\n"
},
{
"path": "app/models/vpn_group_user_association.rb",
"chars": 93,
"preview": "class VpnGroupUserAssociation < ApplicationRecord\n belongs_to :vpn\n belongs_to :user\nend\n\n\n"
},
{
"path": "app/models/vpn_search_domain.rb",
"chars": 64,
"preview": "class VpnSearchDomain < ApplicationRecord\n belongs_to :vpn\nend\n"
},
{
"path": "app/models/vpn_supplemental_match_domain.rb",
"chars": 75,
"preview": "class VpnSupplementalMatchDomain < ApplicationRecord\n belongs_to :vpn\nend\n"
},
{
"path": "app/validators/email_validator.rb",
"chars": 265,
"preview": "class EmailValidator < ActiveModel::EachValidator\n def validate_each(record, attribute, value)\n unless value.to_s.ma"
},
{
"path": "app/views/admin/index.html.slim",
"chars": 9,
"preview": "h1 hello\n"
},
{
"path": "app/views/api/v1/users/show.json.jbuilder",
"chars": 152,
"preview": "json.(@user, :email, :uid, :name, :active, :admin, :home_dir, :shell, :public_key, :user_login_id, :product_name)\njson.g"
},
{
"path": "app/views/api_resources/_api_resource.json.jbuilder",
"chars": 147,
"preview": "json.extract! api_resource, :id, :name, :description, :access_key, :created_at, :updated_at\njson.url api_resource_url(ap"
},
{
"path": "app/views/api_resources/_form.html.slim",
"chars": 782,
"preview": "= form_for @api_resource, :class => 'form-horizontal', html: {novalidate: 'true'} do |f|\n - if @api_resource.errors.any"
},
{
"path": "app/views/api_resources/edit.html.slim",
"chars": 118,
"preview": "h1 Editing api_resource\n\n== render 'form'\n\n=> link_to 'Show', @api_resource\n'|\n=< link_to 'Back', api_resources_path\n\n"
},
{
"path": "app/views/api_resources/index.html.slim",
"chars": 918,
"preview": ".container-fluid.col-md-8\n - if notice.present?\n .alert.alert-primary role=\"alert\"\n #notice\n = notice\n\n\n"
},
{
"path": "app/views/api_resources/index.json.jbuilder",
"chars": 85,
"preview": "json.array! @api_resources, partial: 'api_resources/api_resource', as: :api_resource\n"
},
{
"path": "app/views/api_resources/new.html.slim",
"chars": 279,
"preview": ".container-fluid.col-md-4.col-md-offset-4\n - if notice.present?\n .alert.alert-primary role=\"alert\"\n #notice\n "
},
{
"path": "app/views/api_resources/show.html.slim",
"chars": 988,
"preview": ".container-fluid.col-md-4.col-md-offset-4\n - if notice.present?\n .alert.alert-primary role=\"alert\"\n #notice\n "
},
{
"path": "app/views/api_resources/show.json.jbuilder",
"chars": 72,
"preview": "json.partial! \"api_resources/api_resource\", api_resource: @api_resource\n"
},
{
"path": "app/views/application/_admin.html.slim",
"chars": 124,
"preview": "div\n ul.navbar-nav\n li.nav-item.active\n a.nav-link href=\"#\" Users\n li.nav-item\n a.nav-link href=\"#\" Gro"
},
{
"path": "app/views/application/_groups_header.html.slim",
"chars": 581,
"preview": "#notice\n = notice\n- if current_user.admin?\n = form_tag groups_path, method: 'post' do\n .row\n .col-md-8\n "
},
{
"path": "app/views/application/_host_header.html.slim",
"chars": 336,
"preview": "ul.nav.nav-tabs\n li#host_machine role=\"presentation\" \n = link_to \"MyHosts\", host_machines_path\n li#group role=\"pres"
},
{
"path": "app/views/common/errors.json.jbuilder",
"chars": 38,
"preview": "json.success false\njson.errors errors\n"
},
{
"path": "app/views/groups/_form.html.slim",
"chars": 0,
"preview": ""
},
{
"path": "app/views/groups/index.html.slim",
"chars": 1044,
"preview": ".container-fluid.col.container-profile\n - if current_user.admin?\n = form_tag groups_path, method: 'get', class: \"p-2"
},
{
"path": "app/views/groups/new.html.slim",
"chars": 642,
"preview": ".container-fluid.col-md-4.col-md-offset-4\n h5 Add new group\n = form_for @group, :class => 'form-horizontal' do |f|\n "
},
{
"path": "app/views/groups/show.html.slim",
"chars": 5789,
"preview": ".container.col-md-8\n h5.mb-3 Group Details\n hr\n .row\n .col \n = \"Group Name: #{@group.name}\"\n .col\n = "
},
{
"path": "app/views/home/index.html.slim",
"chars": 757,
"preview": ".form-signin\n .row\n .col\n h1 Gate-SSO \n br\n .row\n .col\n h3 Single Sign-On\n br\n br\n br\n br\n - cas"
},
{
"path": "app/views/host_machines/index.html.slim",
"chars": 773,
"preview": ".container-fluid.col-md-6.col-md-offset-2\n = form_tag host_machines_path, method: 'get', class: \"p-2\" do\n .input-gro"
},
{
"path": "app/views/host_machines/new.html.slim",
"chars": 313,
"preview": ".container-fluid.col-md-4.col-md-offset-4\n = form_tag host_machines_path, method: 'post' do\n .input-group \n = t"
},
{
"path": "app/views/host_machines/show.html.slim",
"chars": 1637,
"preview": ".container.col-md-8\n h5.mb-3 Host Details\n hr\n .row\n .col \n = @host_machine.name\n - if current_user.admin?\n "
},
{
"path": "app/views/layouts/application.html.slim",
"chars": 2981,
"preview": "doctype html\nhtml lang=\"en\"\n head\n meta charset=\"utf-8\"\n meta http-equiv=\"X-UA-Compatible\" content=\"IE=Edge,chrom"
},
{
"path": "app/views/layouts/home.html.slim",
"chars": 1148,
"preview": "doctype html\nhtml lang=\"en\"\n head\n link href='https://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type="
},
{
"path": "app/views/layouts/profile.html.slim.disabled",
"chars": 1211,
"preview": "doctype html\nhtml lang=\"en\"\n head\n meta charset=\"utf-8\"\n meta http-equiv=\"X-UA-Compatible\" content=\"IE=Edge,chrom"
},
{
"path": "app/views/nss/add_host.json.jbuilder",
"chars": 106,
"preview": "json.success true\njson.access_key host.access_key\njson.host host.name\njson.groups host.groups.map(&:name)\n"
},
{
"path": "app/views/organisations/_form.html.slim",
"chars": 976,
"preview": "- if flash.key?(:errors)\n .alert.alert-danger#organisation_form_errors\n b Issue creating application\n br\n - fl"
},
{
"path": "app/views/organisations/config_saml_app.html.slim",
"chars": 266,
"preview": ".container.col-md-8\n .row.mb-3.mt-2\n .col-md-12\n h5 Configure #{app_name.titleize}\n .row.mb-3.mt-2\n .col-md"
},
{
"path": "app/views/organisations/index.html.slim",
"chars": 1680,
"preview": ".container.col-md-8\n .row.mb-3.mt-2\n .col-md-8\n h5 Organisations\n .col-md-4.text-right\n = link_to \"New "
},
{
"path": "app/views/organisations/new.html.slim",
"chars": 224,
"preview": ".container.col-md-8\n .row.mb-3.mt-2\n .col-md-12\n h5 Create Organisation\n hr\n = form_for(org) do |f|\n = ren"
},
{
"path": "app/views/organisations/saml_apps/_datadog.html.erb",
"chars": 6384,
"preview": "<ul class=\"nav nav-tabs\" id=\"configAppTabs\" role=\"tablist\">\n <li class=\"nav-item\">\n <a class=\"nav-link active\" href="
},
{
"path": "app/views/organisations/show.html.slim",
"chars": 224,
"preview": ".container.col-md-8\n .row.mb-3.mt-2\n .col-md-12\n h5 Update Organisation\n hr\n = form_for(org) do |f|\n = ren"
},
{
"path": "app/views/profile/_group_search.html.slim",
"chars": 331,
"preview": ".container.container-profile\n = form_tag profile_group_admin_path, method: 'get' do\n .row \n .col-md-8\n ="
},
{
"path": "app/views/profile/_user_search.html.slim",
"chars": 326,
"preview": ".container.container-profile\n = form_tag profile_user_admin_path, method: 'get' do\n .row \n .col-md-8\n = "
},
{
"path": "app/views/profile/group_admin.html.slim",
"chars": 33,
"preview": "= render partial: \"group_search\"\n"
},
{
"path": "app/views/profile/list.html.slim",
"chars": 511,
"preview": "= render partial: \"user_search\"\n- if @users.count > 0\n .table-responsive\n table.table.table-striped\n thead\n "
},
{
"path": "app/views/profile/public_key.html.slim",
"chars": 0,
"preview": ""
},
{
"path": "app/views/profile/show.html.slim",
"chars": 2674,
"preview": ".container.container-profile\n .row.mt-3\n .jumbotron\n .row.marketing\n .col-lg-6\n .row\n .col-lg-"
},
{
"path": "app/views/profile/user.html.slim",
"chars": 3227,
"preview": ".container.container-profile\n .row\n .col-md-4.text-primary Name\n .col-md-8\n = @user.name\n .row\n .col-md-"
},
{
"path": "app/views/profile/user_admin.html.slim",
"chars": 32,
"preview": "= render partial: \"user_search\"\n"
},
{
"path": "app/views/saml_idp/idp/new.html.erb",
"chars": 2486,
"preview": "<!DOCTYPE html>\n<html xmlns:layout=\"http://www.ultraq.net.nz/thymeleaf/layout\">\n<head>\n <meta charset=\"UTF-8\"/>\n <meta"
},
{
"path": "app/views/users/_search.html.slim",
"chars": 353,
"preview": ".container-fluid.col-md-4.col-md-offset-4\n = form_tag users_path, method: 'get', class: \"p-2\" do\n .input-group\n "
},
{
"path": "app/views/users/index.html.slim",
"chars": 559,
"preview": "= render partial: \"search\"\n- if @users.count > 0\n .table-responsive\n table.table.table-striped\n thead\n t"
},
{
"path": "app/views/users/new.html.erb",
"chars": 1593,
"preview": "<div class=\"container col-md-8\">\n <div class=\"row mb-3 mt-2\">\n <div class=\"col-md-12\">\n <h5>Create User</h5>\n "
},
{
"path": "app/views/users/show.html.slim",
"chars": 5014,
"preview": ".container.col-md-8\n h5.mb-3 User Profile \n hr\n - if flash.key?(:success)\n .alert.alert-success\n = flash[:suc"
},
{
"path": "app/views/vpns/_form.html.slim",
"chars": 945,
"preview": " = form_for @vpn, :class => 'form-horizontal' do |f|\n - if @vpn.errors.any?\n #error_explanation\n h2 = \"#"
},
{
"path": "app/views/vpns/edit.html.slim",
"chars": 231,
"preview": ".container-fluid.col-md-4.col-md-offset-4\n - if notice.present?\n .alert.alert-primary role=\"alert\"\n #notice\n "
},
{
"path": "app/views/vpns/index.html.slim",
"chars": 986,
"preview": ".container-fluid.col-md-8.col-md-offset-4\n - if notice.present?\n .alert.alert-primary role=\"alert\"\n #notice\n "
},
{
"path": "app/views/vpns/new.html.slim",
"chars": 225,
"preview": ".container-fluid.col-md-4.col-md-offset-4\n - if notice.present?\n .alert.alert-primary role=\"alert\"\n #notice\n "
},
{
"path": "app/views/vpns/show.html.slim",
"chars": 3906,
"preview": ".container.container-profile\n - if notice.present?\n .alert.alert-primary role=\"alert\"\n #notice\n = notice"
},
{
"path": "bin/bundle",
"chars": 129,
"preview": "#!/usr/bin/env ruby\nENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)\nload Gem.bin_path('bundler', '"
},
{
"path": "bin/rails",
"chars": 141,
"preview": "#!/usr/bin/env ruby\nAPP_PATH = File.expand_path(\"../config/application\", __dir__)\nrequire_relative \"../config/boot\"\nrequ"
},
{
"path": "bin/rake",
"chars": 90,
"preview": "#!/usr/bin/env ruby\nrequire_relative \"../config/boot\"\nrequire \"rake\"\nRake.application.run\n"
},
{
"path": "bin/setup",
"chars": 1010,
"preview": "#!/usr/bin/env ruby\nrequire \"fileutils\"\n\n# path to your application root.\nAPP_ROOT = File.expand_path(\"..\", __dir__)\n\nde"
},
{
"path": "bin/update",
"chars": 782,
"preview": "#!/usr/bin/env ruby\nrequire 'pathname'\nrequire 'fileutils'\ninclude FileUtils\n\n# path to your application root.\nAPP_ROOT "
},
{
"path": "config/application.rb",
"chars": 701,
"preview": "require_relative \"boot\"\n\nrequire \"rails/all\"\n\n# Require the gems listed in Gemfile, including any gems\n# you've limited "
},
{
"path": "config/boot.rb",
"chars": 128,
"preview": "ENV[\"BUNDLE_GEMFILE\"] ||= File.expand_path(\"../Gemfile\", __dir__)\n\nrequire \"bundler/setup\" # Set up gems listed in the G"
},
{
"path": "config/cable.yml",
"chars": 116,
"preview": "development:\n adapter: async\n\ntest:\n adapter: async\n\nproduction:\n adapter: redis\n url: redis://localhost:6379/1\n"
},
{
"path": "config/database.yml",
"chars": 682,
"preview": "default: &default\n adapter: mysql2\n pool: 5\n timeout: 5000\n host: <%= ENV['GATE_DB_HOST'] %>\n port: <%= ENV['GATE_D"
},
{
"path": "config/environment.rb",
"chars": 128,
"preview": "# Load the Rails application.\nrequire_relative \"application\"\n\n# Initialize the Rails application.\nRails.application.init"
},
{
"path": "config/environments/development.rb",
"chars": 2454,
"preview": "require \"active_support/core_ext/integer/time\"\n\nRails.application.configure do\n # Settings specified here will take pre"
},
{
"path": "config/environments/integration.rb",
"chars": 3342,
"preview": "Rails.application.configure do\n # Settings specified here will take precedence over those in config/application.rb.\n\n "
},
{
"path": "config/environments/production.rb",
"chars": 3934,
"preview": "require \"active_support/core_ext/integer/time\"\n\nRails.application.configure do\n # Settings specified here will take pre"
},
{
"path": "config/environments/test.rb",
"chars": 2445,
"preview": "require \"active_support/core_ext/integer/time\"\n\n# The test environment is used exclusively to run your application's\n# t"
},
{
"path": "config/initializers/application_controller_renderer.rb",
"chars": 162,
"preview": "# Be sure to restart your server when you modify this file.\n\n# ApplicationController.renderer.defaults.merge!(\n# http_"
},
{
"path": "config/initializers/assets.rb",
"chars": 502,
"preview": "# Be sure to restart your server when you modify this file.\n\n# Version of your assets, change this if you want to expire"
},
{
"path": "config/initializers/backtrace_silencers.rb",
"chars": 404,
"preview": "# Be sure to restart your server when you modify this file.\n\n# You can add backtrace silencers for libraries that you're"
},
{
"path": "config/initializers/content_security_policy.rb",
"chars": 1044,
"preview": "# Be sure to restart your server when you modify this file.\n\n# Define an application-wide content security policy.\n# See"
},
{
"path": "config/initializers/cookies_serializer.rb",
"chars": 244,
"preview": "# Be sure to restart your server when you modify this file.\n\n# Specify a serializer for the signed and encrypted cookie "
},
{
"path": "config/initializers/devise.rb",
"chars": 13554,
"preview": "# Use this hook to configure devise mailer, warden hooks and so forth.\n# Many of these configuration options can be set "
},
{
"path": "config/initializers/dotenv.rb",
"chars": 254,
"preview": "begin\n Dotenv.require_keys('GATE_DB_HOST',\n 'GATE_DB_PORT',\n 'GATE_DB_USER',\n 'GATE_DB_PASSWORD',\n 'CACHE_H"
},
{
"path": "config/initializers/filter_parameter_logging.rb",
"chars": 396,
"preview": "# Be sure to restart your server when you modify this file.\n\n# Configure parameters to be filtered from the log file. Us"
},
{
"path": "config/initializers/inflections.rb",
"chars": 649,
"preview": "# Be sure to restart your server when you modify this file.\n\n# Add new inflection rules using the following format. Infl"
},
{
"path": "config/initializers/mime_types.rb",
"chars": 156,
"preview": "# Be sure to restart your server when you modify this file.\n\n# Add new mime types for use in respond_to blocks:\n# Mime::"
},
{
"path": "config/initializers/new_framework_defaults.rb",
"chars": 882,
"preview": "# Be sure to restart your server when you modify this file.\n#\n# This file contains migration options to ease your Rails "
},
{
"path": "config/initializers/new_framework_defaults_7_0.rb",
"chars": 6107,
"preview": "# Be sure to restart your server when you modify this file.\n#\n# This file eases your Rails 7.0 framework defaults upgrad"
},
{
"path": "config/initializers/permissions_policy.rb",
"chars": 384,
"preview": "# Define an application-wide HTTP permissions policy. For further\n# information see https://developers.google.com/web/up"
},
{
"path": "config/initializers/session_store.rb",
"chars": 143,
"preview": "# Be sure to restart your server when you modify this file.\n\nRails.application.config.session_store :active_record_store"
},
{
"path": "config/initializers/wrap_parameters.rb",
"chars": 485,
"preview": "# Be sure to restart your server when you modify this file.\n\n# This file contains settings for ActionController::ParamsW"
},
{
"path": "config/locales/devise.en.yml",
"chars": 4084,
"preview": "# Additional translations at https://github.com/plataformatec/devise/wiki/I18n\n\nen:\n devise:\n confirmations:\n c"
},
{
"path": "config/locales/en.bootstrap.yml",
"chars": 579,
"preview": "# Sample localization file for English. Add more files in this directory for other locales.\n# See https://github.com/sve"
},
{
"path": "config/locales/en.yml",
"chars": 634,
"preview": "# Files in the config/locales directory are used for internationalization\n# and are automatically loaded by Rails. If yo"
},
{
"path": "config/newrelic.yml",
"chars": 1059,
"preview": "common: &default_settings\n # Required license key associated with your New Relic account.\n license_key: <%= ENV['NEWRE"
},
{
"path": "config/puma.rb",
"chars": 2005,
"preview": "# Puma can serve each request in a thread from an internal thread pool.\n# The `threads` method setting takes two numbers"
},
{
"path": "config/redis.yml",
"chars": 204,
"preview": "default: &default\n host: <%= ENV['CACHE_HOST'] %>\n port: <%= ENV['CACHE_PORT'] %>\n limit: 20\n\ndevelopment:\n <<: *def"
},
{
"path": "config/routes.rb",
"chars": 7622,
"preview": "Rails.application.routes.draw do\n devise_for :users, :controllers => { :omniauth_callbacks => \"users/omniauth_callbacks"
},
{
"path": "config/schedule.rb",
"chars": 589,
"preview": "# Use this file to easily define all of your cron jobs.\n#\n# It's helpful, but not entirely necessary to understand cron "
},
{
"path": "config/secrets.yml",
"chars": 1122,
"preview": "# Be sure to restart your server when you modify this file.\n\n# Your secret key is used for verifying the integrity of si"
},
{
"path": "config/spring.rb",
"chars": 111,
"preview": "%w(\n .ruby-version\n .rbenv-vars\n tmp/restart.txt\n tmp/caching-dev.txt\n).each { |path| Spring.watch(path) }\n"
},
{
"path": "config/storage.yml",
"chars": 1152,
"preview": "test:\n service: Disk\n root: <%= Rails.root.join(\"tmp/storage\") %>\n\nlocal:\n service: Disk\n root: <%= Rails.root.join("
}
]
// ... and 170 more files (download for full content)
About this extraction
This page contains the full source code of the gate-sso/gate GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 370 files (479.5 KB), approximately 139.5k tokens, and a symbol index with 488 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.