├── .awsbox.json ├── .gitignore ├── .jshintrc ├── .travis.yml ├── CONTRIBUTORS ├── ChangeLog ├── LICENSE ├── Makefile ├── README.md ├── automation-tests ├── README.md ├── config │ ├── local-platforms.js │ ├── sauce-platforms.js │ └── tests-to-ignore.js ├── lib │ ├── asserts.js │ ├── personatestuser.js │ ├── reporters │ │ ├── file-reporter.js │ │ ├── std-err-reporter.js │ │ └── std-out-reporter.js │ ├── restmail.js │ ├── results-aggregator.js │ ├── runner.js │ ├── test-finder.js │ ├── test-setup.js │ ├── testidp.js │ ├── timeouts.js │ ├── toolbelt.js │ ├── urls.js │ ├── user.js │ ├── utils.js │ ├── vows_harness.js │ └── wd-extensions.js ├── package.json ├── pages │ ├── 123done.js │ ├── css.js │ └── dialog.js ├── scripts │ ├── post-update.js │ └── run-all.js └── tests │ ├── add-primary-to-primary.js │ ├── add-primary-to-secondary.js │ ├── api-tests │ └── oncancel.js │ ├── cancel-account.js │ ├── change-password-test.js │ ├── frontend-qunit-test.js │ ├── health-check-tests.js │ ├── idp-transition │ ├── broken-primary.js │ ├── primary-shuts-down-single-email.js │ ├── primary-starts-up-single-email.js │ ├── transition-to-secondary-forgot-password.js │ └── transition-to-secondary.js │ ├── new-user │ ├── new-user-primary-test.js │ └── new-user-secondary-test.js │ ├── public-terminals.js │ ├── remove-email.js │ ├── reset-password-test.js │ ├── returning-user.js │ └── sign-in-test.js ├── bin ├── browserid ├── dbwriter ├── keysigner ├── load_gen ├── proxy ├── router ├── static └── verifier ├── config ├── aws.json ├── l10n-all.json ├── l10n-prod.json ├── local.json └── production.json ├── docs ├── AWS_DEPLOYMENT.md ├── I18N.md ├── KPI_LOAD_GENERATION.md ├── LOAD_GENERATION.md ├── ORGANIZATION.md ├── PRIMARY_PROTOCOL.md ├── SETUP_FREEBSD.md ├── SETUP_RHEL.md ├── SETUP_UBUNTU.md ├── SETUP_WINDOWS.md └── TESTING.md ├── example ├── bigtent │ ├── .well-known │ │ └── browserid │ ├── README.md │ ├── key.publickey │ └── key.secretkey ├── delegated_primary │ └── .well-known │ │ └── browserid ├── primary │ ├── .well-known │ │ └── browserid │ ├── index.html │ ├── jquery.js │ ├── provision.html │ ├── sample.privatekey │ ├── sample.publickey │ └── sign_in.html └── rp │ ├── EventListener.js │ ├── app.js │ ├── index.html │ ├── postVerificationReturn.html │ ├── privacy.html │ ├── pure-0.5.0 │ ├── HISTORY.md │ ├── LICENSE.md │ ├── README.md │ ├── base-context-min.css │ ├── base-context.css │ ├── base-min.css │ ├── base.css │ ├── bower.json │ ├── buttons-core-min.css │ ├── buttons-core.css │ ├── buttons-min.css │ ├── buttons.css │ ├── forms-min.css │ ├── forms-nr-min.css │ ├── forms-nr.css │ ├── forms.css │ ├── grids-core-min.css │ ├── grids-core.css │ ├── grids-min.css │ ├── grids-responsive-min.css │ ├── grids-responsive-old-ie-min.css │ ├── grids-responsive-old-ie.css │ ├── grids-responsive.css │ ├── grids-units-min.css │ ├── grids-units.css │ ├── grids.css │ ├── menus-core-min.css │ ├── menus-core.css │ ├── menus-min.css │ ├── menus-nr-min.css │ ├── menus-nr.css │ ├── menus-paginator-min.css │ ├── menus-paginator.css │ ├── menus.css │ ├── pure-min.css │ ├── pure-nr-min.css │ ├── pure-nr.css │ ├── pure.css │ ├── tables-min.css │ └── tables.css │ ├── style.css │ └── terms.html ├── lib ├── baseExceptions.js ├── bcrypt-compute.js ├── bcrypt.js ├── boolean-query.js ├── browserid │ └── fake_verification.js ├── busy_middleware.js ├── coarse_user_agent_parser.js ├── configuration.js ├── db.js ├── db │ ├── dbutils.js │ ├── json.js │ ├── mysql.js │ └── mysql_wrapper.js ├── email.js ├── generate_code_version.js ├── heartbeat.js ├── http_forward.js ├── httputils.js ├── i18n_client_check.js ├── keysigner │ ├── ca.js │ └── keysigner-compute.js ├── kpi_data.js ├── load_gen │ ├── activities │ │ ├── add_email.js │ │ ├── change_pass.js │ │ ├── include_only.js │ │ ├── interaction_data.js │ │ ├── reauth.js │ │ ├── reset_pass.js │ │ ├── signin.js │ │ └── signup.js │ ├── common.js │ ├── crypto.js │ └── user_db.js ├── logging │ ├── cef_logger.js │ ├── custom_logger.js │ ├── logging.js │ ├── middleware │ │ ├── metrics.js │ │ └── statsd.js │ └── transports │ │ ├── filters │ │ ├── metrics.js │ │ ├── statsd-increment.js │ │ └── statsd-timing.js │ │ ├── log-file.js │ │ ├── metrics-file.js │ │ ├── metrics-kpi.js │ │ └── statsd.js ├── p3p.js ├── primary.js ├── proxy-secure.js ├── secrets.js ├── shutdown.js ├── static │ └── views.js ├── static_resources.js ├── templates.js ├── validate.js ├── verifier │ ├── certassertion.js │ └── verifier-compute.js ├── version.js ├── well-known-parser.js ├── wsapi.js ├── wsapi │ ├── account_cancel.js │ ├── add_email_with_assertion.js │ ├── address_info.js │ ├── auth_with_assertion.js │ ├── authenticate_user.js │ ├── cert_key.js │ ├── complete_email_confirmation.js │ ├── complete_reset.js │ ├── complete_transition.js │ ├── complete_user_creation.js │ ├── create_account_with_assertion.js │ ├── discovery.js │ ├── email_addition_status.js │ ├── email_for_token.js │ ├── email_reverify_status.js │ ├── forget_idp.js │ ├── have_email.js │ ├── increment_failed_auth_tries.js │ ├── interaction_data.js │ ├── list_emails.js │ ├── logout.js │ ├── password_reset_status.js │ ├── ping.js │ ├── prolong_session.js │ ├── remove_email.js │ ├── reset_failed_auth_tries.js │ ├── saw_idp.js │ ├── session_context.js │ ├── stage_email.js │ ├── stage_reset.js │ ├── stage_reverify.js │ ├── stage_transition.js │ ├── stage_user.js │ ├── transition_status.js │ ├── update_password.js │ ├── used_address_as_primary.js │ ├── user_creation_status.js │ └── user_used_email_as.js ├── wsapi_client.js └── wsapiutils.js ├── lockdown.json ├── package.json ├── resources ├── .gitignore ├── assets │ ├── account-buttons.png │ ├── browserID-135x35.png │ ├── browserID-366x72.png │ ├── browserID-80x20.png │ ├── browserID-buttons.psd │ └── browserID-logo.eps ├── dnt-policy.txt ├── email_templates │ ├── _footer.html.ejs │ ├── _header.html.ejs │ ├── confirm.ejs │ ├── confirm.html.ejs │ ├── new.ejs │ ├── new.html.ejs │ ├── reset.ejs │ ├── reset.html.ejs │ ├── transition.ejs │ └── transition.html.ejs ├── robots.txt ├── static │ ├── 500 │ │ ├── error.html │ │ ├── error_bg.png │ │ └── error_icon.png │ ├── .jshintrc │ ├── authentication_api.js │ ├── common │ │ ├── css │ │ │ ├── ie8.css │ │ │ └── style.css │ │ ├── i │ │ │ ├── button-arrow-active.png │ │ │ ├── button-arrow-hover.png │ │ │ ├── button-arrow.png │ │ │ ├── button-loader.gif │ │ │ ├── closex.png │ │ │ └── grain.png │ │ └── js │ │ │ ├── browser-support.js │ │ │ ├── browserid.js │ │ │ ├── class.js │ │ │ ├── command.js │ │ │ ├── crypto-loader.js │ │ │ ├── dom-helpers.js │ │ │ ├── enable_cookies_url.js │ │ │ ├── error-messages.js │ │ │ ├── gettext.js │ │ │ ├── helpers.js │ │ │ ├── history.js │ │ │ ├── javascript-extensions.js │ │ │ ├── lib │ │ │ ├── base64.js │ │ │ ├── dom-jquery.js │ │ │ ├── highlight.js │ │ │ ├── html5shim.js │ │ │ ├── hub.js │ │ │ ├── jquery-1.7.1.min.js │ │ │ ├── jschannel.js │ │ │ ├── json2.js │ │ │ ├── micrajax.js │ │ │ ├── module.js │ │ │ ├── tinyscore.js │ │ │ ├── urlparse.js │ │ │ └── winchan.js │ │ │ ├── mediator.js │ │ │ ├── models │ │ │ ├── interaction_data.js │ │ │ ├── models.js │ │ │ ├── network-context.js │ │ │ ├── rp_info.js │ │ │ └── user-context.js │ │ │ ├── modules │ │ │ ├── cookie_check.js │ │ │ ├── development.js │ │ │ ├── dom_module.js │ │ │ ├── extended-info.js │ │ │ ├── interaction_data.js │ │ │ ├── module.js │ │ │ ├── page_module.js │ │ │ ├── xhr.js │ │ │ ├── xhr_delay.js │ │ │ └── xhr_disable_form.js │ │ │ ├── network.js │ │ │ ├── provisioning.js │ │ │ ├── renderer.js │ │ │ ├── screens.js │ │ │ ├── state_machine.js │ │ │ ├── storage.js │ │ │ ├── templates.js │ │ │ ├── tooltip.js │ │ │ ├── user.js │ │ │ ├── validation.js │ │ │ ├── wait-messages.js │ │ │ └── xhr_transport.js │ ├── communication_iframe │ │ └── start.js │ ├── dialog │ │ ├── css │ │ │ ├── ie8.css │ │ │ ├── m.css │ │ │ └── style.css │ │ ├── i │ │ │ ├── arrow_grey.png │ │ │ ├── firefox_logo.png │ │ │ ├── persona-logo-transparent.png │ │ │ ├── persona_watermark.png │ │ │ ├── persona_watermark_dark.png │ │ │ ├── persona_watermark_dark_sm.png │ │ │ ├── persona_watermark_footer_sm.png │ │ │ └── persona_watermark_sm.png │ │ ├── js │ │ │ ├── misc │ │ │ │ ├── helpers.js │ │ │ │ ├── internal_api.js │ │ │ │ ├── screen_size_hacks.js │ │ │ │ └── state.js │ │ │ ├── modules │ │ │ │ ├── actions.js │ │ │ │ ├── add_email.js │ │ │ │ ├── authenticate.js │ │ │ │ ├── check_registration.js │ │ │ │ ├── complete_sign_in.js │ │ │ │ ├── dialog.js │ │ │ │ ├── generate_assertion.js │ │ │ │ ├── idp_authentication.js │ │ │ │ ├── inline_tospp.js │ │ │ │ ├── is_this_your_computer.js │ │ │ │ ├── pick_email.js │ │ │ │ ├── primary_offline.js │ │ │ │ ├── primary_user_not_provisioned.js │ │ │ │ ├── primary_user_provisioned.js │ │ │ │ ├── provision_primary_user.js │ │ │ │ ├── rp_info.js │ │ │ │ ├── set_password.js │ │ │ │ ├── validate_rp_params.js │ │ │ │ └── verify_primary_user.js │ │ │ └── start.js │ │ └── views │ │ │ ├── add_email.ejs │ │ │ ├── cannot_verify_required_email.ejs │ │ │ ├── complete_sign_in.ejs │ │ │ ├── confirm_email.ejs │ │ │ ├── development.ejs │ │ │ ├── error.ejs │ │ │ ├── generic.ejs │ │ │ ├── inline_tospp.ejs │ │ │ ├── invalid_required_email.ejs │ │ │ ├── is_this_your_computer.ejs │ │ │ ├── load.ejs │ │ │ ├── pick_email.ejs │ │ │ ├── primary_offline.ejs │ │ │ ├── primary_user_not_verified.ejs │ │ │ ├── rp_info.ejs │ │ │ ├── rp_info_mobile.ejs │ │ │ ├── set_password.ejs │ │ │ ├── test_template_cachify.ejs │ │ │ ├── test_template_no_input.ejs │ │ │ ├── test_template_with_input.ejs │ │ │ ├── test_template_with_partial.ejs │ │ │ ├── verify_primary_user.ejs │ │ │ └── wait.ejs │ ├── favicon.ico │ ├── i │ │ ├── email_sign_in_black.png │ │ ├── email_sign_in_blue.png │ │ ├── email_sign_in_red.png │ │ ├── persona_sign_in_black.png │ │ ├── persona_sign_in_blue.png │ │ ├── persona_sign_in_red.png │ │ ├── plain_sign_in_black.png │ │ ├── plain_sign_in_blue.png │ │ ├── plain_sign_in_red.png │ │ ├── sign_in_blue.png │ │ ├── sign_in_green.png │ │ ├── sign_in_grey.png │ │ ├── sign_in_orange.png │ │ └── sign_in_red.png │ ├── include_js │ │ ├── _header.js │ │ ├── _include.js │ │ └── _jschannel.js │ ├── pages │ │ ├── css │ │ │ ├── ie8.css │ │ │ ├── m.css │ │ │ └── style.css │ │ ├── i │ │ │ ├── badge.png │ │ │ ├── developers-link.png │ │ │ ├── flexible-graphic.png │ │ │ ├── marketplace-header.png │ │ │ ├── one-password-graphic.png │ │ │ ├── persona-logo-100x100.png │ │ │ ├── persona-logo-wordmark.png │ │ │ └── slit.png │ │ └── js │ │ │ ├── about.js │ │ │ ├── idp_authenticate.js │ │ │ ├── index.js │ │ │ ├── manage_account.js │ │ │ ├── page_helpers.js │ │ │ ├── reset_password.js │ │ │ ├── start.js │ │ │ └── verify_secondary_address.js │ ├── provisioning_api.js │ ├── relay │ │ └── relay.js │ └── test │ │ ├── .jshintrc │ │ ├── cases │ │ ├── common │ │ │ └── js │ │ │ │ ├── browser-support.js │ │ │ │ ├── class.js │ │ │ │ ├── command.js │ │ │ │ ├── crypto-loader.js │ │ │ │ ├── dom-helpers.js │ │ │ │ ├── enable_cookies_url.js │ │ │ │ ├── helpers.js │ │ │ │ ├── history.js │ │ │ │ ├── models │ │ │ │ ├── interaction_data.js │ │ │ │ └── rp_info.js │ │ │ │ ├── modules │ │ │ │ ├── cookie_check.js │ │ │ │ ├── dom_module.js │ │ │ │ ├── extended-info.js │ │ │ │ ├── interaction_data.js │ │ │ │ ├── module.js │ │ │ │ ├── page_module.js │ │ │ │ ├── xhr.js │ │ │ │ ├── xhr_delay.js │ │ │ │ └── xhr_disable_form.js │ │ │ │ ├── network.js │ │ │ │ ├── renderer.js │ │ │ │ ├── screens.js │ │ │ │ ├── state_machine.js │ │ │ │ ├── storage.js │ │ │ │ ├── tooltip.js │ │ │ │ ├── user.js │ │ │ │ └── validation.js │ │ ├── dialog │ │ │ └── js │ │ │ │ ├── misc │ │ │ │ ├── helpers.js │ │ │ │ ├── internal_api.js │ │ │ │ └── state.js │ │ │ │ └── modules │ │ │ │ ├── actions.js │ │ │ │ ├── add_email.js │ │ │ │ ├── authenticate.js │ │ │ │ ├── check_registration.js │ │ │ │ ├── complete_sign_in.js │ │ │ │ ├── dialog.js │ │ │ │ ├── forgot_password.js │ │ │ │ ├── generate_assertion.js │ │ │ │ ├── inline_tospp.js │ │ │ │ ├── is_this_your_computer.js │ │ │ │ ├── pick_email.js │ │ │ │ ├── primary_offline.js │ │ │ │ ├── primary_user_not_provisioned.js │ │ │ │ ├── primary_user_provisioned.js │ │ │ │ ├── provision_primary_user.js │ │ │ │ ├── rp_info.js │ │ │ │ ├── set_password.js │ │ │ │ ├── validate_rp_params.js │ │ │ │ └── verify_primary_user.js │ │ ├── include.js │ │ ├── other │ │ │ └── mocks │ │ │ │ └── xhr.js │ │ └── pages │ │ │ └── js │ │ │ ├── about.js │ │ │ ├── browserid.js │ │ │ ├── forgot.js │ │ │ ├── manage_account.js │ │ │ ├── page_helpers.js │ │ │ ├── reset_password.js │ │ │ ├── signin.js │ │ │ └── verify_secondary_address.js │ │ ├── mocks │ │ ├── mocks.js │ │ ├── provisioning.js │ │ ├── templates.js │ │ ├── winchan.js │ │ ├── window.js │ │ └── xhr.js │ │ ├── qunit │ │ ├── qunit.css │ │ └── qunit.js │ │ └── testHelpers │ │ └── helpers.js └── views │ ├── about.ejs │ ├── authenticate_layout.ejs │ ├── communication_iframe.ejs │ ├── confirm.ejs │ ├── cookies_disabled.ejs │ ├── dialog.ejs │ ├── dialog_layout.ejs │ ├── en │ ├── privacy.ejs │ └── tos.ejs │ ├── es │ ├── privacy.ejs │ └── tos.ejs │ ├── index.ejs │ ├── layout.ejs │ ├── partial │ ├── license_with_code_ver.ejs │ └── noscript-warning.ejs │ ├── pl │ ├── privacy.ejs │ └── tos.ejs │ ├── provision.ejs │ ├── relay.ejs │ ├── reset_password.ejs │ ├── test.ejs │ ├── unsupported_dialog.ejs │ └── unsupported_dialog_without_watch.ejs ├── scripts ├── aws_enable_locales.js ├── awsbox_local │ ├── post_create.js │ └── scp.js ├── awsbox_remote │ ├── post_create.sh │ ├── post_deploy.sh │ └── post_start.sh ├── branch_train.sh ├── browserid.spec ├── capture_deployed_resources.js ├── check_l10n_config.js ├── check_po.sh ├── check_primary_support ├── compile_mo.sh ├── compress ├── compress-worker.js ├── create_account.js ├── create_font_css.js ├── create_include.js ├── create_templates.js ├── create_test_users.js ├── deploy.js ├── every_locale.js ├── extract_po.sh ├── generate_ephemeral_keys.js ├── get_assertion.js ├── hash_password.js ├── inspect_localstorage.js ├── l10n-update.js ├── lockdown ├── merge_po.sh ├── phantomrunner.js ├── postinstall.js ├── rpmbuild.sh ├── run_locally.js ├── serve_example.js ├── serve_example_delegated_primary.js ├── serve_example_primary.js ├── show_config.js ├── test ├── test_backend ├── test_db_connectivity.js ├── test_frontend ├── test_selenium └── verify-assertion.js └── tests ├── account-cancel-test.js ├── add-email-with-assertion-test.js ├── address-info-test.js ├── auth-with-assertion-test.js ├── authentication-lockout-test.js ├── bcrypt-compatibility-test.js ├── ca-test.js ├── cef-logging.js ├── cert-key-test.js ├── coarse-user-agent-parser-test.js ├── conformance-test.js ├── cookie-session-security-test.js ├── data ├── borkedauthority.domain │ └── .well-known │ │ └── browserid ├── cycle.domain │ └── .well-known │ │ └── browserid ├── cycle2.domain │ └── .well-known │ │ └── browserid ├── delegate0.domain │ └── .well-known │ │ └── browserid ├── delegate1.domain │ └── .well-known │ │ └── browserid ├── delegate10.domain │ └── .well-known │ │ └── browserid ├── delegate2.domain │ └── .well-known │ │ └── browserid ├── delegate3.domain │ └── .well-known │ │ └── browserid ├── delegate4.domain │ └── .well-known │ │ └── browserid ├── delegate5.domain │ └── .well-known │ │ └── browserid ├── delegate6.domain │ └── .well-known │ │ └── browserid ├── delegate7.domain │ └── .well-known │ │ └── browserid ├── delegate8.domain │ └── .well-known │ │ └── browserid ├── delegate9.domain │ └── .well-known │ │ └── browserid ├── disabled.domain │ └── .well-known │ │ └── browserid ├── hozed.domain │ └── .well-known │ │ └── browserid ├── lib.jshintrc └── user_agents.json ├── db-test.js ├── discovery-test.js ├── double-stage-updates-password.js ├── email-addition-status-test.js ├── email-throttling-test.js ├── fonts-request-test.js ├── forgotten-pass-test.js ├── header-tests.js ├── heartbeat-test.js ├── i18n-tests.js ├── i18n_test_files └── bg │ ├── client.json │ └── messages.json ├── i18n_test_templates ├── i18n_fallback_test.ejs └── i18n_test.ejs ├── idp-seen-test.js ├── internal-wsapi-test.js ├── jshint-test.js ├── kpi-test.js ├── lib ├── http-mock.js ├── primary.js ├── responds-with.js ├── secondary.js ├── start-stop.js ├── statsd-mock.js ├── test_env.js └── wsapi.js ├── list-emails-wsapi-test.js ├── logout-test.js ├── metrics-header-test.js ├── no-cookie-test.js ├── p3p-header-test.js ├── page-requests-test.js ├── password-bcrypt-update-test.js ├── password-length-test.js ├── password-update-test.js ├── post-limiting-test.js ├── primary-secondary-transition-forgot-password-test.js ├── primary-secondary-transition-test.js ├── primary-then-secondary-test.js ├── proxy-idp-test.js ├── registration-status-wsapi-test.js ├── remove-email-test.js ├── rp-branded-emails-test.js ├── secrets-test.js ├── session-context-test.js ├── session-duration-test.js ├── session-prolong-test.js ├── simple-stage-user-utf8-password.js ├── software-version-test.js ├── ssl-proxy-wsapi-cookie.js ├── stalled-mysql-test.js ├── static-resource-test.js ├── statsd-test.js ├── two-level-auth-test.js ├── unverified-email-test.js ├── used-address-as-primary-test.js ├── verifier-test.js ├── verify-in-different-browser-test.js ├── well-known-browserid.js └── well-known-test.js /.awsbox.json: -------------------------------------------------------------------------------- 1 | { 2 | "processes": [ 3 | "bin/router", 4 | "bin/proxy", 5 | "bin/dbwriter", 6 | "bin/keysigner", 7 | "bin/verifier", 8 | "bin/browserid", 9 | "bin/static" 10 | ], 11 | "env": { 12 | "CONFIG_FILES": "$HOME/code/config/production.json,$HOME/code/config/aws.json,$HOME/config.json" 13 | }, 14 | "hooks": { 15 | "postdeploy": "scripts/awsbox_remote/post_deploy.sh", 16 | "poststart": "scripts/awsbox_remote/post_start.sh", 17 | "postcreate": "scripts/awsbox_remote/post_create.sh" 18 | }, 19 | "local_hooks": { 20 | "postcreate": "node scripts/awsbox_local/post_create.js" 21 | }, 22 | "packages": [ 23 | "mysql-server", 24 | "subversion", 25 | "gmp-devel", 26 | "emacs-nox" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.pyc 3 | \#*\# 4 | .\#* 5 | *.swp 6 | /node_modules 7 | /var 8 | /rpmbuild 9 | /npm-debug.log 10 | /resources/static/build 11 | /resources/static/production 12 | /resources/static/i18n 13 | /resources/static/common/js/lib/bidbundle.js 14 | /resources/static/common/js/lib/gobbledygook.js 15 | /resources/static/dialog/views/site 16 | .DS_Store 17 | Thumbs.db 18 | /locale 19 | /resources/email_templates/email-test.html 20 | /automation-tests/node_modules 21 | /automation-tests/results 22 | /automation-tests/*.jar 23 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "passfail": false, 3 | "maxerr": 100, 4 | "node": true, 5 | "forin": false, 6 | "boss": true, 7 | "noarg": true, 8 | "undef": true, 9 | "unused": true, 10 | "browser": true, 11 | "laxbreak": true, 12 | "laxcomma": true, 13 | "eqeqeq": true, 14 | "eqnull": true, 15 | "expr": true, 16 | "indent": 2, 17 | "white": false, 18 | "predef": [ 19 | "exports", 20 | "require", 21 | "process" 22 | ], 23 | "es5": true, 24 | "esnext": true, 25 | "shadow": false, 26 | "supernew": false, 27 | "strict": false 28 | } 29 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | before_script: 2 | - "export DISPLAY=:99.0" 3 | - "sh -e /etc/init.d/xvfb start" 4 | 5 | language: node_js 6 | 7 | before_install: 8 | - "uname -a" 9 | - "[ -e /etc/lsb-release ] && cat /etc/lsb-release" 10 | - "phantomjs --version" 11 | - "mysql -NBe 'select version()'" 12 | - sudo apt-get install libgmp3-dev 13 | - "mysql -e 'create database browserid;'" 14 | 15 | node_js: 16 | - "0.10" 17 | 18 | notifications: 19 | irc: 20 | channels: 21 | - "irc.mozilla.org#identity" 22 | use_notice: false 23 | skip_join: false 24 | email: 25 | - jrgm@mozilla.com 26 | 27 | env: 28 | - WHAT_TESTS=front MYSQL_USER=root DISABLE_REQUEST_THROTTLING=true 29 | - WHAT_TESTS=back_mysql MYSQL_USER=root DISABLE_REQUEST_THROTTLING=true 30 | - WHAT_TESTS=back DISABLE_REQUEST_THROTTLING=true 31 | 32 | mysql: 33 | adapter: mysql2 34 | username: root 35 | encoding: utf8 36 | database: browserid 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This Source Code Form is subject to the terms of the Mozilla Public 2 | License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 | You can obtain one at http://mozilla.org/MPL/2.0/. 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | clean: 6 | rm -rf node_modules rpmbuild 7 | 8 | npm: 9 | npm install 10 | 11 | rpm: npm 12 | scripts/rpmbuild.sh 13 | 14 | test: npm 15 | npm test 16 | 17 | jenkins_build: clean npm test rpm 18 | -------------------------------------------------------------------------------- /automation-tests/config/local-platforms.js: -------------------------------------------------------------------------------- 1 | // 2 | // By default, we assume local platforms just have default locations. 3 | // 4 | // You must have installed ChromeDriver to use Chrome. 5 | // Ditto for all Webdrivers except Firefox. 6 | // see the Webdriver wiki for more: https://code.google.com/p/selenium/w/list 7 | // 8 | const platforms = { 9 | "firefox": { 10 | platform: 'ANY', 11 | browserName: 'firefox', 12 | version: '' 13 | }, 14 | /* if you wish to add a second firefox, give it a unique name and specify 15 | the path to the binary, which will vary across systems. 16 | --> This won't work for other browsers, only FF. 17 | --> The example shows a Mac path, but you could insert a Linux or Win path too. 18 | 19 | "firefox-nightly": { 20 | platform: 'ANY', 21 | browserName: 'firefox', 22 | version: '', 23 | firefox_binary: '/Applications/FirefoxNightly.app/Contents/MacOS/firefox-bin' 24 | }, 25 | */ 26 | "chrome": { 27 | platform: 'ANY', 28 | browserName: 'chrome', 29 | version: '' 30 | }, 31 | "opera": { 32 | platform: 'ANY', 33 | browserName: 'opera', 34 | version: '' 35 | }, 36 | "safari": { 37 | platform: 'ANY', 38 | browserName: 'safari', 39 | version: '' 40 | }, 41 | "ie": { 42 | platform: 'ANY', 43 | browserName: 'internet explorer', 44 | version: '' 45 | } 46 | }; 47 | 48 | // see https://code.google.com/p/selenium/wiki/DesiredCapabilities for other opts 49 | const defaultCapabilities = { 50 | javascriptEnabled: true 51 | }; 52 | 53 | exports.platforms = platforms; 54 | exports.defaultCapabilities = defaultCapabilities; 55 | exports.defaultPlatform = "firefox"; 56 | -------------------------------------------------------------------------------- /automation-tests/config/tests-to-ignore.js: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | // These are tests to ignore 6 | // XXX extract duplication if this file gets significantly longer 7 | 8 | var testsToIgnore = { 9 | dev: [ 10 | "public-terminals.js" 11 | ], 12 | 13 | stage: [ 14 | "frontend-qunit-test.js", 15 | "public-terminals.js" 16 | ], 17 | 18 | prod: [ 19 | "frontend-qunit-test.js", 20 | "public-terminals.js" 21 | ] 22 | }; 23 | 24 | module.exports = function(env) { 25 | return testsToIgnore[env] || testsToIgnore.dev; 26 | }; 27 | -------------------------------------------------------------------------------- /automation-tests/lib/asserts.js: -------------------------------------------------------------------------------- 1 | // desc is optional textual description of the error 2 | exports.ok = function(fact, desc) { 3 | var defaultMsg = "assertion failed: '" + fact + "' is not truthy"; 4 | if (!fact) return desc || defaultMsg; 5 | }; 6 | exports.equal = function(lhs, rhs, desc) { 7 | var defaultMsg = "assertion failed: actual '" + lhs 8 | + "' does not equal expected '" + rhs + "'"; 9 | if (lhs !== rhs) return desc || defaultMsg; 10 | }; 11 | -------------------------------------------------------------------------------- /automation-tests/lib/personatestuser.js: -------------------------------------------------------------------------------- 1 | /*jshint sub: true */ 2 | 3 | const utils = require("./utils.js"), 4 | urls = require('./urls.js'), 5 | request = require('request'); 6 | 7 | // TODO factor out common bits with lib/restmail 8 | // TODO accept all the personatestuser arguments 9 | 10 | const DEFAULT_TIMEOUT = 40000; 11 | 12 | // grab user creds from personatestuser.org. 13 | // args include .timeout (optional), .env (optional) 14 | // callback is cb(error, {email, password}, fullResponse) 15 | exports.getVerifiedUser = function(args, cb) { 16 | if (arguments.length === 1) { 17 | cb = args; 18 | args = {}; 19 | } 20 | var timeout = args.timeout || DEFAULT_TIMEOUT; 21 | var url = urls.personatestuser; 22 | 23 | request({ url: url, timeout: timeout, json:true}, function (error, response, body) { 24 | if (!error && response.statusCode === 200) { 25 | if (!body.email) { return cb(new Error('funky getVerifiedUser response')); } 26 | cb(error, {email: body.email, pass: body.pass}, body); 27 | } else { 28 | cb(error || response.body); 29 | } 30 | }); 31 | }; 32 | 33 | -------------------------------------------------------------------------------- /automation-tests/lib/reporters/file-reporter.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'), 2 | mkdirp = require('mkdirp'), 3 | path = require('path'), 4 | existsSync = fs.existsSync || path.existsSync; 5 | 6 | function FileReporter(config) { 7 | var fileName = config.output_path; 8 | this.fileName = fileName; 9 | 10 | try { 11 | mkdirp.sync(path.dirname(fileName)); 12 | } 13 | catch(e) { 14 | console.log("error:", this.fileName, String(e)); 15 | } 16 | } 17 | FileReporter.prototype.report = function(msg) { 18 | try { 19 | var fd = fs.openSync(this.fileName, "w"); 20 | fs.writeSync(fd, msg, 0, msg.length, null); 21 | fs.closeSync(fd); 22 | } 23 | catch(e) { 24 | console.log("error:", this.fileName, String(e)); 25 | } 26 | }; 27 | FileReporter.prototype.done = function() { 28 | }; 29 | 30 | module.exports = FileReporter; 31 | -------------------------------------------------------------------------------- /automation-tests/lib/reporters/std-err-reporter.js: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | function StdErrReporter() { } 6 | StdErrReporter.prototype.report = function(msg) { 7 | process.stderr.write(msg); 8 | }; 9 | StdErrReporter.prototype.done = function() {}; 10 | 11 | module.exports = StdErrReporter; 12 | -------------------------------------------------------------------------------- /automation-tests/lib/reporters/std-out-reporter.js: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | function StdOutReporter() { } 6 | StdOutReporter.prototype.report = function(msg) { 7 | process.stdout.write(msg); 8 | }; 9 | StdOutReporter.prototype.done = function() {}; 10 | 11 | module.exports = StdOutReporter; 12 | 13 | -------------------------------------------------------------------------------- /automation-tests/lib/runner.js: -------------------------------------------------------------------------------- 1 | const vowsHarness = require('../lib/vows_harness.js'); 2 | 3 | var alltests = {}, 4 | rawSuites = [], 5 | globalCount = 0; 6 | 7 | // register just pushes suites onto a master list 8 | function register(suites) { 9 | if (!suites.length) suites = [suites]; 10 | rawSuites = rawSuites.concat(suites); 11 | } 12 | 13 | // run runs previously-registered suites. for convenience, 14 | // you can just pass suites into run as well. 15 | function run(mod, suites, opts) { 16 | if (suites) register(suites); 17 | 18 | rawSuites.forEach(function(suite) { 19 | for (var vow in suite) { 20 | globalCount++; 21 | // vows with duplicate names cause great sadness; use a counter to ensure 22 | // each name is unique 23 | alltests[globalCount + ': ' + vow] = suite[vow]; 24 | } 25 | }); 26 | 27 | vowsHarness(alltests, mod, opts); 28 | } 29 | 30 | exports.run = run; 31 | exports.register = register; 32 | -------------------------------------------------------------------------------- /automation-tests/lib/test-finder.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /*jshint sub: true */ 3 | 4 | /* This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 7 | 8 | const path = require('path'), 9 | fs = require('fs'), 10 | test_root_path = path.join(__dirname, "..", "tests"), 11 | env = process.env['PERSONA_ENV'] || 'dev', 12 | tests_to_ignore = require('../config/tests-to-ignore')(env), 13 | glob = require('minimatch'); 14 | 15 | exports.find = function(pattern, root, tests, ignoreTests) { 16 | root = root || test_root_path; 17 | tests = tests || []; 18 | pattern = pattern || "*"; 19 | ignoreTests = ignoreTests || ""; 20 | try { 21 | var files = fs.readdirSync(root); 22 | files.forEach(function(file) { 23 | var filePath = path.join(root, file); 24 | var stats = fs.statSync(filePath); 25 | if (stats.isFile() && /\.js$/.test(file)) { 26 | if (tests_to_ignore.indexOf(file) === -1 && ignoreTests.split(',').indexOf(file.slice(0,-3)) === -1) { 27 | if (glob(file.replace(/\.js$/, ""), pattern)) { 28 | tests.push({ 29 | name: file.replace('.js', ''), 30 | path: filePath 31 | }); 32 | console.log("adding", file); 33 | } 34 | } 35 | else { 36 | console.log("ignoring", file); 37 | } 38 | } 39 | else if (stats.isDirectory()) { 40 | exports.find(pattern, filePath, tests); 41 | } 42 | }); 43 | } catch(e) { 44 | console.log(e.toString()); 45 | return; 46 | } 47 | 48 | return tests; 49 | }; 50 | -------------------------------------------------------------------------------- /automation-tests/lib/timeouts.js: -------------------------------------------------------------------------------- 1 | exports.DEFAULT_POLL_MS = 500; 2 | exports.DEFAULT_TIMEOUT_MS = 40000; 3 | // At the advice of the WebQA team, setting the default implicit wait to 0 and 4 | // using explicit waits. This helps reduce the number of errors due to explicit 5 | // timeouts. 6 | exports.DEFAULT_IMPLICIT_WAIT_MS = 0; 7 | -------------------------------------------------------------------------------- /automation-tests/lib/toolbelt.js: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | /** 6 | * Create a copy of the process environment and extend it with extra variables 7 | */ 8 | exports.copyExtendEnv = function() { 9 | var nowEnv = exports.deepCopy(process.env); 10 | var extensions = [].slice.call(arguments, 0); 11 | var args = [ nowEnv ].concat(extensions); 12 | 13 | var newEnv = exports.extend.apply(null, args); 14 | return newEnv; 15 | }; 16 | 17 | /** 18 | * Create a deep copy of an object 19 | */ 20 | exports.deepCopy = function(obj) { 21 | return JSON.parse(JSON.stringify(obj)); 22 | }; 23 | 24 | /** 25 | * Extend an object. The first parameter is the object to extend, parameter 2+ 26 | * are the mixins. 27 | */ 28 | exports.extend = function() { 29 | var extended = arguments[0]; 30 | var extensions = Array.prototype.slice.call(arguments, 1); 31 | extensions.forEach(function(extension) { 32 | for (var key in extension) { 33 | if (typeof extension[key] !== "undefined") { 34 | extended[key] = extension[key]; 35 | } 36 | } 37 | }); 38 | 39 | return extended; 40 | }; 41 | 42 | -------------------------------------------------------------------------------- /automation-tests/lib/urls.js: -------------------------------------------------------------------------------- 1 | /*jshint sub: true */ 2 | 3 | // Depending on the environment variable PERSONA_ENV, we will change the 4 | // URLS for various sites used during testing. This lets you target 5 | // different environments 6 | 7 | const URLS = { 8 | dev: { 9 | "123done": 'http://dev.123done.org', 10 | persona: 'https://login.dev.anosrep.org', 11 | personatestuser: 'http://personatestuser.org/email/dev/', 12 | myfavoritebeer: 'http://dev.myfavoritebeer.org', 13 | eyedeeme: 'https://eyedee.me' 14 | }, 15 | stage: { 16 | "123done": 'http://beta.123done.org', 17 | persona: 'https://login.anosrep.org', 18 | personatestuser: 'http://personatestuser.org/email/stage/', 19 | myfavoritebeer: 'http://beta.myfavoritebeer.org', 20 | eyedeeme: 'https://eyedee.me' 21 | }, 22 | prod: { 23 | "123done": 'http://123done.org', 24 | persona: 'https://login.persona.org', 25 | personatestuser: 'http://personatestuser.org/email/prod/', 26 | myfavoritebeer: 'http://myfavoritebeer.org', 27 | eyedeeme: 'https://eyedee.me' 28 | } 29 | }; 30 | 31 | var env = process.env['PERSONA_ENV'] || 'dev'; 32 | 33 | if (!URLS[env]) { 34 | var personaURL = env + '.personatest.org'; 35 | URLS[env] = { 36 | "123done": 'http://'+env+'.123done.org', 37 | persona: 'https://'+personaURL, 38 | personatestuser: 'http://personatestuser.org/email/custom/?browserid='+personaURL+'&verifier='+personaURL+'/verify', 39 | myfavoritebeer: 'http://'+env+'.myfavoritebeer.org', 40 | eyedeeme: 'https://eyedee.me' 41 | }; 42 | } 43 | 44 | module.exports = URLS[env]; 45 | -------------------------------------------------------------------------------- /automation-tests/lib/utils.js: -------------------------------------------------------------------------------- 1 | // wait for something to work. 2 | // poll - how often to check in ms 3 | // timeout - how long to try before giving up in ms 4 | // check - a function that will perform the check, accepts a callback where the 5 | // first argument is a boolean indicating whether the check was successful 6 | // (if false, the check will be retried) 7 | // complete - a callback to invoke upon timeout or successful check with args.slice(1) 8 | // from the check function 9 | exports.waitFor = function (poll, timeout, check, complete) { 10 | var startTime = new Date(); 11 | function doit() { 12 | check(function(done) { 13 | if (!done && ((new Date() - startTime) > timeout)) { 14 | complete.call(null, "timeout hit"); 15 | } else if (done) { 16 | complete.apply(null, Array.prototype.slice.call(arguments, 1)); 17 | } else { 18 | setTimeout(doit, poll); 19 | } 20 | }); 21 | } 22 | setTimeout(doit, poll); 23 | }; 24 | -------------------------------------------------------------------------------- /automation-tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "browserid-selenium-tests", 3 | "description": "selenium tests for the browserid goodness", 4 | "version": "0.0.1", 5 | "private": true, 6 | "dependencies": { 7 | "vows": "0.7.0", 8 | "wd": "0.3.4", 9 | "request": "2.12.0", 10 | "optimist": "0.3.5", 11 | "q": "0.8.10", 12 | "underscore": "1.4.2", 13 | "mkdirp": "0.3.4", 14 | "minimatch": "0.2.6" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /automation-tests/pages/dialog.js: -------------------------------------------------------------------------------- 1 | /*jshint sub: true */ 2 | 3 | const CSS = require('./css.js'), 4 | utils = require('../lib/utils.js'); 5 | 6 | function verifyOpts(optionList, opts) { 7 | optionList.forEach(function(required) { 8 | if (!opts[required]) throw ("Error: missing required argument '"+required+"'"); 9 | }); 10 | } 11 | 12 | exports.signInAsNewUser = function(opts, cb) { 13 | verifyOpts(['email', 'browser', 'password'], opts); 14 | var browser = opts.browser; 15 | browser.chain({onError: cb}) 16 | .wtype(CSS['dialog'].emailInput, opts.email) 17 | .wclick(CSS['dialog'].newEmailNextButton) 18 | .wtype(CSS['dialog'].choosePassword, opts.password) 19 | .wtype(CSS['dialog'].verifyPassword, opts.password) 20 | .wclick(CSS['dialog'].createUserButton, cb); 21 | }; 22 | 23 | exports.signInExistingUser = function(opts, cb) { 24 | verifyOpts(['email', 'browser', 'password'], opts); 25 | var browser = opts.browser; 26 | browser.chain({onError: cb}) 27 | .wtype(CSS['dialog'].emailInput, opts.email) 28 | .wclick(CSS['dialog'].newEmailNextButton) 29 | .wtype(CSS['dialog'].existingPassword, opts.password) 30 | .wclick(CSS['dialog'].returningUserButton) 31 | .wclickIfExists(CSS['dialog'].notMyComputerButton, cb); 32 | }; 33 | -------------------------------------------------------------------------------- /automation-tests/tests/api-tests/oncancel.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /*jshint sub:true */ 3 | 4 | /* This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 7 | 8 | const 9 | path = require('path'), 10 | CSS = require('../../pages/css.js'), 11 | runner = require('../../lib/runner.js'), 12 | persona_urls = require('../../lib/urls.js'), 13 | testSetup = require('../../lib/test-setup.js'); 14 | 15 | var browser; 16 | 17 | runner.run(module, { 18 | "setup all the things": function(done) { 19 | testSetup.setup({ b:1 }, function(err, fix) { 20 | if (fix) { 21 | browser = fix.b[0]; 22 | } 23 | done(err); 24 | }); 25 | }, 26 | 27 | "create a new selenium session": function(done) { 28 | testSetup.newBrowserSession(browser, done); 29 | }, 30 | 31 | "open 123done, load up dialog": function(done) { 32 | browser.chain({ onError: done }) 33 | .get(persona_urls["123done"]) 34 | .wclick(CSS['123done.org'].signinButton) 35 | .wwin(CSS["persona.org"].windowName) 36 | .wfind(CSS['dialog'].emailInput, done); 37 | }, 38 | 39 | "close dialog": function(done) { 40 | browser.closeCurrentBrowserWindow(done); 41 | }, 42 | 43 | "ensure the sign in button is re-enabled and is clickable": function(done) { 44 | browser.chain({ onError: done }) 45 | .wclick(CSS['123done.org'].signinButton) 46 | .wwin(CSS["persona.org"].windowName) 47 | .wfind(CSS['dialog'].emailInput, done); 48 | } 49 | }, { 50 | suiteName: path.basename(__filename), 51 | cleanup: function(done) { testSetup.teardown(done); } 52 | }); 53 | 54 | 55 | -------------------------------------------------------------------------------- /bin/proxy: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 | 7 | // I proxy outgoing requests in dev/testing environments (not production). That's what I do. 8 | 9 | require('../lib/baseExceptions').addExceptionHandler(); 10 | 11 | const 12 | http = require('http'), 13 | forward = require('../lib/http_forward.js'), 14 | config = require('../lib/configuration.js'); 15 | 16 | var port = config.has('bind_to.port') ? config.get('bind_to.port') : 0; 17 | var addy = config.has('bind_to.host') ? config.get('bind_to.host') : "127.0.0.1"; 18 | 19 | // set a maximum allowed time on responses to declaration of support requests 20 | forward.setTimeout(config.get('declaration_of_support_timeout_ms')); 21 | 22 | const allowed = /^https:\/\/[a-zA-Z0-9\.\-_]+\/\.well-known\/browserid(\?.*)?$/; 23 | const allowed_kpi = /^https:\/\/[a-zA-Z0-9\.\-_]+\/wsapi\/interaction_data(\?.*)?$/; 24 | 25 | var server = http.createServer(function (req, res) { 26 | var url = req.url; 27 | if (!allowed.test(url) && !allowed_kpi.test(url) ) { 28 | res.writeHead(400); 29 | res.end('You can\'t get there from here'); 30 | return; 31 | } 32 | 33 | forward.forward(url, req, res, function(err) { 34 | if (err) { 35 | res.writeHead(400); 36 | res.end('Oops: ' + err.toString()); 37 | return; 38 | } 39 | }); 40 | }).listen(port, addy, function () { 41 | var a = server.address(); 42 | console.log("running on http://" + a.address + ":" + a.port); 43 | }); 44 | -------------------------------------------------------------------------------- /config/aws.json: -------------------------------------------------------------------------------- 1 | // this is configuration specific to aws deployments 2 | { 3 | // disable statsd for aws 4 | "statsd": { 5 | "enabled": false 6 | }, 7 | "kpi": { 8 | "backend_db_url" : "https://kpiggybank-dev.personatest.org/wsapi/interaction_data", 9 | "backend_sample_rate": 1.0 10 | }, 11 | // for amazon deployments, enable it-CH which is the trigger language 12 | // for localization tests db-LB (which is a testing language where chars 13 | // are inverted and reversed), and en. 14 | // This set can be overridden by adding more to config.json on the VM. 15 | "supported_languages": [ 16 | "en", "it-CH" 17 | ], 18 | "debug_lang": "it-CH", 19 | "var_path": "/home/app/var", 20 | 21 | "http_proxy": { 22 | "host": "127.0.0.1", 23 | "port": 10006 24 | }, 25 | "proxy": { "bind_to": { "port": 10006 } }, 26 | "router": { "bind_to": { "port": 8080 } }, 27 | // whether to show the development menu. 28 | "enable_development_menu": true, 29 | // explicitly undefine public_static_url and firefoxos_url, as the configuration will 30 | // then fallback to public_url. Because these values are dynamic in ephemeral 31 | // deployments and because we serve static content from the same URL, this is 32 | // exactly what we want. 33 | "public_static_url": "", 34 | "firefoxos_url": "", 35 | 36 | // enable the measurement of the dom loading 37 | "measure_dom_loading": true, 38 | 39 | // enable experimental forceIssuer for this domain 40 | "forcible_issuers": [ 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /config/l10n-all.json: -------------------------------------------------------------------------------- 1 | { 2 | "supported_languages": [ 3 | "af", "bg", "ca", "cs", "cy", "da", "db-LB", "de", "el", "en", 4 | "eo", "es", "et", "eu", "fi", "fr", "fy", "ga", "gd", "gl", 5 | "he", "hr", "hu", "id", "it", "ja", "ko", "lij", "lt", "ml", 6 | "nb-NO", "nl", "pa", "pl", "pt", "pt-BR", "rm", "ro", "ru", "si", 7 | "sk", "sl", "son", "sq", "sr", "sv", "tr", "uk", "zh-CN", "zh-TW" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /config/l10n-prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "supported_languages": [ 3 | "af", "bg", "ca", "cs", "cy", "da", "de", "el", "en", "eo", 4 | "es", "et", "eu", "fi", "fr", "fy", "ga", "gd", "gl", "he", 5 | "hr", "hu", "id", "it", "ja", "ko", "lij", "lt", "nb-NO", "nl", 6 | "pa", "pl", "pt-BR", "rm", "ro", "ru", "sk", "sl", "son", "sq", 7 | "sr", "sv", "tr", "uk", "zh-CN", "zh-TW" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /config/local.json: -------------------------------------------------------------------------------- 1 | { 2 | "verifier": { "bind_to": { "port": 10000 } }, 3 | "keysigner": { "bind_to": { "port": 10003 } }, 4 | "dbwriter": { "bind_to": { "port": 10004 } }, 5 | "proxy": { "bind_to": { "port": 10006 } }, 6 | "browserid": { "bind_to": { "port": 10007 } }, 7 | "static": { "bind_to": { "port": 10010 } }, 8 | "router": { "bind_to": { "port": 10002 } }, 9 | "use_minified_resources": false, 10 | "database": { 11 | "driver": "json" 12 | }, 13 | "express_log_format": "dev_bid", 14 | "email_to_console": true, 15 | "env": "local", 16 | "kpi": { 17 | "backend_sample_rate": 1.0 18 | }, 19 | 20 | // increase to tolerate slower server responses; useful for testing 21 | "maximum_event_loop_lag": 100, 22 | 23 | // whether to show the development menu. 24 | "enable_development_menu": true, 25 | 26 | // enable the measurement of the dom loading 27 | "measure_dom_loading": true, 28 | "forcible_issuers": ["issuer.domain"] 29 | } 30 | -------------------------------------------------------------------------------- /docs/SETUP_FREEBSD.md: -------------------------------------------------------------------------------- 1 | Installing Dependencies on FreeBSD 2 | --------------------------------- 3 | 4 | Run the following to install necessary dependencies: 5 | 6 | cd /usr/ports 7 | make -C www/node install clean 8 | make -C math/gmp install clean 9 | make -C www/npm install clean 10 | make -C devel/git install clean 11 | make -C lang/gcc install clean 12 | 13 | or with pkgng: 14 | 15 | pkg install www/node math/gmp www/npm devel/git lang/gcc 16 | 17 | GCC will install g++ at /usr/local/bin/g++XX, where XX represents the version. 18 | Somewhere in the system's PATH, add a symlink named "g++" pointing to the 19 | installed version. 20 | 21 | For example (assuming GCC 4.9) 22 | 23 | ln -s /usr/local/bin/g++49 /usr/local/bin/g++ -------------------------------------------------------------------------------- /docs/SETUP_RHEL.md: -------------------------------------------------------------------------------- 1 | Installing Dependencies on RedHat Enterprise Linux and Related Derivatives 2 | --------------------------------- 3 | [Red Hat Enterprise Linux Derivatives](https://en.wikipedia.org/wiki/Red_Hat_Enterprise_Linux_derivatives) 4 | 5 | Run the following to install necessary dependencies: 6 | 7 | sudo yum install gcc-c++ nodejs gmp-devel expat-devel 8 | -------------------------------------------------------------------------------- /docs/SETUP_UBUNTU.md: -------------------------------------------------------------------------------- 1 | Installing Dependencies on Ubuntu 2 | --------------------------------- 3 | 4 | Run the following to install necessary dependencies: 5 | 6 | sudo apt-add-repository ppa:chris-lea/node.js 7 | sudo apt-get update 8 | sudo apt-get install python-software-properties 9 | sudo apt-get install nodejs git-core libgmp3-dev g++ make 10 | -------------------------------------------------------------------------------- /docs/SETUP_WINDOWS.md: -------------------------------------------------------------------------------- 1 | Installing Dependencies on Windows 7 2 | ------------------------------------ 3 | 4 | The following packages are required to ensure `npm install` succeeds, installed in the order listed (make sure that all visual studio c++ redistributable components that might be listed in your "programs and features" list are uninstalled, first. This is inconvenient, but essential to get a working VC++ compiler stack set up). 5 | 6 | * node 0.10.20 or higher (fixes several npm bugs that might prevent install) 7 | * Microsoft Visual Studio C++ 2010 Express, http://go.microsoft.com/?linkid=9709949 8 | * For Windows 7 x64, the Windows 7 64-bit SDK, http://www.microsoft.com/en-us/download/details.aspx?id=8279 9 | * Microsoft Visual Studio C++ 2008 redistributable, http://slproweb.com/products/Win32OpenSSL.html 10 | * Win32/Win64 OpenSSL, http://slproweb.com/products/Win32OpenSSL.html 11 | 12 | After installing OpenSSL, add its `/bin` folder to your system's PATH variable. 13 | -------------------------------------------------------------------------------- /example/bigtent/.well-known/browserid: -------------------------------------------------------------------------------- 1 | { 2 | "provisioning": "/provision.html", 3 | "authentication": "/sign_in.html", 4 | "public-key": { 5 | "algorithm":"DS", 6 | "y":"7144b2e8f21b47c91d9494041b3990a7f1798f3e7505e44f153782105a6037fe336d7084e9de37f042fd34e6872c2f17db69fa5aea0c9e1702f4e676c2e3bede2bba5a72789ae38e521b2feb8112bccdc92acba550c767a891c6299bfc28e327c4ad3f07baf42bc35baa89d197f81a55049028b1b1f2d9a43fec4da8404e8e98429762c3b426075957f3e4b12f3b98bd303b95e813fc68c6af8ea7a1586d0acdbf2382c6122e91b4594ae86f1875e984d4d6e86b4753d565bcf0566139c02ab88f3602cd7eccd96ea4dc69f19846a7e0982b8f84c15781167955d560b7f0a08185e4aff98be7548a6da86d13a07c7a495395e0988bfbcbd83f00c7bd511614e6", 7 | "p":"d6c4e5045697756c7a312d02c2289c25d40f9954261f7b5876214b6df109c738b76226b199bb7e33f8fc7ac1dcc316e1e7c78973951bfc6ff2e00cc987cd76fcfb0b8c0096b0b460fffac960ca4136c28f4bfb580de47cf7e7934c3985e3b3d943b77f06ef2af3ac3494fc3c6fc49810a63853862a02bb1c824a01b7fc688e4028527a58ad58c9d512922660db5d505bc263af293bc93bcd6d885a157579d7f52952236dd9d06a4fc3bc2247d21f1a70f5848eb0176513537c983f5a36737f01f82b44546e8e7f0fabc457e3de1d9c5dba96965b10a2a0580b0ad0f88179e10066107fb74314a07e6745863bc797b7002ebec0b000a98eb697414709ac17b401", 8 | "q":"b1e370f6472c8754ccd75e99666ec8ef1fd748b748bbbc08503d82ce8055ab3b", 9 | "g":"9a8269ab2e3b733a5242179d8f8ddb17ff93297d9eab00376db211a22b19c854dfa80166df2132cbc51fb224b0904abb22da2c7b7850f782124cb575b116f41ea7c4fc75b1d77525204cd7c23a15999004c23cdeb72359ee74e886a1dde7855ae05fe847447d0a68059002c3819a75dc7dcbb30e39efac36e07e2c404b7ca98b263b25fa314ba93c0625718bd489cea6d04ba4b0b7f156eeb4c56c44b50e4fb5bce9d7ae0d55b379225feb0214a04bed72f33e0664d290e7c840df3e2abb5e48189fa4e90646f1867db289c6560476799f7be8420a6dc01d078de437f280fff2d7ddf1248d56e1a54b933a41629d6c252983c58795105802d30d7bcd819cf6ef" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /example/bigtent/README.md: -------------------------------------------------------------------------------- 1 | Currently this is used only by tests/auth_with_assertion.js 2 | 3 | Most examples have a scripts/serve_example*.js so you can do manual testing with it. This one does not... files are used only programatically in the unit tests. -------------------------------------------------------------------------------- /example/bigtent/key.publickey: -------------------------------------------------------------------------------- 1 | { 2 | "algorithm":"DS", 3 | "y":"7144b2e8f21b47c91d9494041b3990a7f1798f3e7505e44f153782105a6037fe336d7084e9de37f042fd34e6872c2f17db69fa5aea0c9e1702f4e676c2e3bede2bba5a72789ae38e521b2feb8112bccdc92acba550c767a891c6299bfc28e327c4ad3f07baf42bc35baa89d197f81a55049028b1b1f2d9a43fec4da8404e8e98429762c3b426075957f3e4b12f3b98bd303b95e813fc68c6af8ea7a1586d0acdbf2382c6122e91b4594ae86f1875e984d4d6e86b4753d565bcf0566139c02ab88f3602cd7eccd96ea4dc69f19846a7e0982b8f84c15781167955d560b7f0a08185e4aff98be7548a6da86d13a07c7a495395e0988bfbcbd83f00c7bd511614e6", 4 | "p":"d6c4e5045697756c7a312d02c2289c25d40f9954261f7b5876214b6df109c738b76226b199bb7e33f8fc7ac1dcc316e1e7c78973951bfc6ff2e00cc987cd76fcfb0b8c0096b0b460fffac960ca4136c28f4bfb580de47cf7e7934c3985e3b3d943b77f06ef2af3ac3494fc3c6fc49810a63853862a02bb1c824a01b7fc688e4028527a58ad58c9d512922660db5d505bc263af293bc93bcd6d885a157579d7f52952236dd9d06a4fc3bc2247d21f1a70f5848eb0176513537c983f5a36737f01f82b44546e8e7f0fabc457e3de1d9c5dba96965b10a2a0580b0ad0f88179e10066107fb74314a07e6745863bc797b7002ebec0b000a98eb697414709ac17b401", 5 | "q":"b1e370f6472c8754ccd75e99666ec8ef1fd748b748bbbc08503d82ce8055ab3b", 6 | "g":"9a8269ab2e3b733a5242179d8f8ddb17ff93297d9eab00376db211a22b19c854dfa80166df2132cbc51fb224b0904abb22da2c7b7850f782124cb575b116f41ea7c4fc75b1d77525204cd7c23a15999004c23cdeb72359ee74e886a1dde7855ae05fe847447d0a68059002c3819a75dc7dcbb30e39efac36e07e2c404b7ca98b263b25fa314ba93c0625718bd489cea6d04ba4b0b7f156eeb4c56c44b50e4fb5bce9d7ae0d55b379225feb0214a04bed72f33e0664d290e7c840df3e2abb5e48189fa4e90646f1867db289c6560476799f7be8420a6dc01d078de437f280fff2d7ddf1248d56e1a54b933a41629d6c252983c58795105802d30d7bcd819cf6ef" 7 | } 8 | -------------------------------------------------------------------------------- /example/bigtent/key.secretkey: -------------------------------------------------------------------------------- 1 | {"algorithm":"DS","x":"27d2871fff3e07d83291e8c31b55d9920697ed60ceab6f461d922d7f879439a","p":"d6c4e5045697756c7a312d02c2289c25d40f9954261f7b5876214b6df109c738b76226b199bb7e33f8fc7ac1dcc316e1e7c78973951bfc6ff2e00cc987cd76fcfb0b8c0096b0b460fffac960ca4136c28f4bfb580de47cf7e7934c3985e3b3d943b77f06ef2af3ac3494fc3c6fc49810a63853862a02bb1c824a01b7fc688e4028527a58ad58c9d512922660db5d505bc263af293bc93bcd6d885a157579d7f52952236dd9d06a4fc3bc2247d21f1a70f5848eb0176513537c983f5a36737f01f82b44546e8e7f0fabc457e3de1d9c5dba96965b10a2a0580b0ad0f88179e10066107fb74314a07e6745863bc797b7002ebec0b000a98eb697414709ac17b401","q":"b1e370f6472c8754ccd75e99666ec8ef1fd748b748bbbc08503d82ce8055ab3b","g":"9a8269ab2e3b733a5242179d8f8ddb17ff93297d9eab00376db211a22b19c854dfa80166df2132cbc51fb224b0904abb22da2c7b7850f782124cb575b116f41ea7c4fc75b1d77525204cd7c23a15999004c23cdeb72359ee74e886a1dde7855ae05fe847447d0a68059002c3819a75dc7dcbb30e39efac36e07e2c404b7ca98b263b25fa314ba93c0625718bd489cea6d04ba4b0b7f156eeb4c56c44b50e4fb5bce9d7ae0d55b379225feb0214a04bed72f33e0664d290e7c840df3e2abb5e48189fa4e90646f1867db289c6560476799f7be8420a6dc01d078de437f280fff2d7ddf1248d56e1a54b933a41629d6c252983c58795105802d30d7bcd819cf6ef"} -------------------------------------------------------------------------------- /example/delegated_primary/.well-known/browserid: -------------------------------------------------------------------------------- 1 | { 2 | "authority": "example.domain" 3 | } 4 | -------------------------------------------------------------------------------- /example/primary/.well-known/browserid: -------------------------------------------------------------------------------- 1 | { 2 | "provisioning": "/provision.html", 3 | "authentication": "/sign_in.html", 4 | "public-key": { 5 | "algorithm":"RS", 6 | "n":"12150646309575666544658791157045645163757575303887721078710172478749665834070170928206481109930468203684865378748391106975718718959563139020999088154811587703010353786258781016056954403240590264386124614262627869140351957459406743577995562584260319925426603313709939197457399455483061173844980456364611416651616781677992262613894501858312578942785385470086255995080524454431673067666784338623903663347118104807073332038428581918086381436489000619294471995801952293054002077519255312962379161724622526642212406262043172654176008908362058486885146430345217844546587383034154533029235541666677817563420349484368059586917", 7 | "e":"65537" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /example/primary/sample.privatekey: -------------------------------------------------------------------------------- 1 | {"algorithm":"RS","n":"12150646309575666544658791157045645163757575303887721078710172478749665834070170928206481109930468203684865378748391106975718718959563139020999088154811587703010353786258781016056954403240590264386124614262627869140351957459406743577995562584260319925426603313709939197457399455483061173844980456364611416651616781677992262613894501858312578942785385470086255995080524454431673067666784338623903663347118104807073332038428581918086381436489000619294471995801952293054002077519255312962379161724622526642212406262043172654176008908362058486885146430345217844546587383034154533029235541666677817563420349484368059586917","e":"65537","d":"4576260781837071842193157180361592071303664055813671962186294570898545886786914704989861806863508349047919986322940288592423594917052916069629682361493727501615950722587629763634798747809443360175819977323411869539211550207829724456958122453992362737374381640787683739122037791776987029525545151661621734244874349529048661411099247940582269058676233440040049437304921327491451073610454313255668312747483229646664526246661039878272676051442941399721167635066787800827207115116788251299159776482379477214028479230999290715576867912303554133701642412629365556930442426107748834086621121121510537980546710422816219192577"} -------------------------------------------------------------------------------- /example/primary/sample.publickey: -------------------------------------------------------------------------------- 1 | {"algorithm":"RS","n":"12150646309575666544658791157045645163757575303887721078710172478749665834070170928206481109930468203684865378748391106975718718959563139020999088154811587703010353786258781016056954403240590264386124614262627869140351957459406743577995562584260319925426603313709939197457399455483061173844980456364611416651616781677992262613894501858312578942785385470086255995080524454431673067666784338623903663347118104807073332038428581918086381436489000619294471995801952293054002077519255312962379161724622526642212406262043172654176008908362058486885146430345217844546587383034154533029235541666677817563420349484368059586917","e":"65537"} -------------------------------------------------------------------------------- /example/rp/privacy.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | This is my privacy policy. When you tip me over... 4 | 5 | 6 | -------------------------------------------------------------------------------- /example/rp/pure-0.5.0/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pure", 3 | "version": "0.5.0", 4 | "main": "pure.css", 5 | "devDependencies": { 6 | "normalize-css": "1.1.3" 7 | } 8 | } -------------------------------------------------------------------------------- /example/rp/pure-0.5.0/buttons-core-min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Pure v0.5.0 3 | Copyright 2014 Yahoo! Inc. All rights reserved. 4 | Licensed under the BSD License. 5 | https://github.com/yui/pure/blob/master/LICENSE.md 6 | */ 7 | .pure-button{display:inline-block;*display:inline;zoom:1;line-height:normal;white-space:nowrap;vertical-align:baseline;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.pure-button::-moz-focus-inner{padding:0;border:0} -------------------------------------------------------------------------------- /example/rp/pure-0.5.0/buttons-core.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Pure v0.5.0 3 | Copyright 2014 Yahoo! Inc. All rights reserved. 4 | Licensed under the BSD License. 5 | https://github.com/yui/pure/blob/master/LICENSE.md 6 | */ 7 | .pure-button { 8 | /* Structure */ 9 | display: inline-block; 10 | *display: inline; /*IE 6/7*/ 11 | zoom: 1; 12 | line-height: normal; 13 | white-space: nowrap; 14 | vertical-align: baseline; 15 | text-align: center; 16 | cursor: pointer; 17 | -webkit-user-drag: none; 18 | -webkit-user-select: none; 19 | -moz-user-select: none; 20 | -ms-user-select: none; 21 | user-select: none; 22 | } 23 | 24 | /* Firefox: Get rid of the inner focus border */ 25 | .pure-button::-moz-focus-inner { 26 | padding: 0; 27 | border: 0; 28 | } 29 | -------------------------------------------------------------------------------- /example/rp/pure-0.5.0/grids-core-min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Pure v0.5.0 3 | Copyright 2014 Yahoo! Inc. All rights reserved. 4 | Licensed under the BSD License. 5 | https://github.com/yui/pure/blob/master/LICENSE.md 6 | */ 7 | .pure-g{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;text-rendering:optimizespeed;font-family:FreeSans,Arimo,"Droid Sans",Helvetica,Arial,sans-serif;display:-webkit-flex;-webkit-flex-flow:row wrap;display:-ms-flexbox;-ms-flex-flow:row wrap}.opera-only :-o-prefocus,.pure-g{word-spacing:-.43em}.pure-u{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-g [class *="pure-u"]{font-family:sans-serif} -------------------------------------------------------------------------------- /example/rp/pure-0.5.0/menus-paginator-min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Pure v0.5.0 3 | Copyright 2014 Yahoo! Inc. All rights reserved. 4 | Licensed under the BSD License. 5 | https://github.com/yui/pure/blob/master/LICENSE.md 6 | */ 7 | .pure-paginator{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;text-rendering:optimizespeed;list-style:none;margin:0;padding:0}.opera-only :-o-prefocus,.pure-paginator{word-spacing:-.43em}.pure-paginator li{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-paginator .pure-button{border-radius:0;padding:.8em 1.4em;vertical-align:top;height:1.1em}.pure-paginator .pure-button:focus,.pure-paginator .pure-button:active{outline-style:none}.pure-paginator .prev,.pure-paginator .next{color:#C0C1C3;text-shadow:0 -1px 0 rgba(0,0,0,.45)}.pure-paginator .prev{border-radius:2px 0 0 2px}.pure-paginator .next{border-radius:0 2px 2px 0} -------------------------------------------------------------------------------- /example/rp/pure-0.5.0/menus-paginator.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Pure v0.5.0 3 | Copyright 2014 Yahoo! Inc. All rights reserved. 4 | Licensed under the BSD License. 5 | https://github.com/yui/pure/blob/master/LICENSE.md 6 | */ 7 | /*csslint box-model:false*/ 8 | /*TODO: Remove this lint rule override after a refactor of this code.*/ 9 | 10 | 11 | .pure-paginator { 12 | 13 | /* `pure-g` Grid styles */ 14 | letter-spacing: -0.31em; /* Webkit: collapse white-space between units */ 15 | *letter-spacing: normal; /* reset IE < 8 */ 16 | *word-spacing: -0.43em; /* IE < 8: collapse white-space between units */ 17 | text-rendering: optimizespeed; /* Webkit: fixes text-rendering: optimizeLegibility */ 18 | 19 | /* `pure-paginator` Specific styles */ 20 | list-style: none; 21 | margin: 0; 22 | padding: 0; 23 | } 24 | .opera-only :-o-prefocus, 25 | .pure-paginator { 26 | word-spacing: -0.43em; 27 | } 28 | 29 | /* `pure-u` Grid styles */ 30 | .pure-paginator li { 31 | display: inline-block; 32 | *display: inline; /* IE < 8: fake inline-block */ 33 | zoom: 1; 34 | letter-spacing: normal; 35 | word-spacing: normal; 36 | vertical-align: top; 37 | text-rendering: auto; 38 | } 39 | 40 | 41 | .pure-paginator .pure-button { 42 | border-radius: 0; 43 | padding: 0.8em 1.4em; 44 | vertical-align: top; 45 | height: 1.1em; 46 | } 47 | .pure-paginator .pure-button:focus, 48 | .pure-paginator .pure-button:active { 49 | outline-style: none; 50 | } 51 | .pure-paginator .prev, 52 | .pure-paginator .next { 53 | color: #C0C1C3; 54 | text-shadow: 0 -1px 0 rgba(0,0,0, 0.45); 55 | } 56 | .pure-paginator .prev { 57 | border-radius: 2px 0 0 2px; 58 | } 59 | .pure-paginator .next { 60 | border-radius: 0 2px 2px 0; 61 | } 62 | -------------------------------------------------------------------------------- /example/rp/pure-0.5.0/tables-min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Pure v0.5.0 3 | Copyright 2014 Yahoo! Inc. All rights reserved. 4 | Licensed under the BSD License. 5 | https://github.com/yui/pure/blob/master/LICENSE.md 6 | */ 7 | .pure-table{border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid #cbcbcb}.pure-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.pure-table td,.pure-table th{border-left:1px solid #cbcbcb;border-width:0 0 0 1px;font-size:inherit;margin:0;overflow:visible;padding:.5em 1em}.pure-table td:first-child,.pure-table th:first-child{border-left-width:0}.pure-table thead{background:#e0e0e0;color:#000;text-align:left;vertical-align:bottom}.pure-table td{background-color:transparent}.pure-table-odd td{background-color:#f2f2f2}.pure-table-striped tr:nth-child(2n-1) td{background-color:#f2f2f2}.pure-table-bordered td{border-bottom:1px solid #cbcbcb}.pure-table-bordered tbody>tr:last-child td,.pure-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.pure-table-horizontal td,.pure-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #cbcbcb}.pure-table-horizontal tbody>tr:last-child td{border-bottom-width:0} -------------------------------------------------------------------------------- /example/rp/terms.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | This is my ToS... I pour out. 4 | 5 | 6 | -------------------------------------------------------------------------------- /lib/baseExceptions.js: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | /** 6 | * The most base level features that everything else depends on while 7 | * booting up the service 8 | */ 9 | 10 | var handleUncaughtException = function (err) { 11 | console.error('UNCLE:', err.stack || err); 12 | }; 13 | 14 | exports.addExceptionHandler = function () { 15 | process.addListener('uncaughtException', handleUncaughtException); 16 | }; 17 | 18 | exports.removeExceptionHandler = function () { 19 | process.removeListener('uncaughtException', handleUncaughtException); 20 | }; 21 | -------------------------------------------------------------------------------- /lib/bcrypt-compute.js: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | const bcrypt = require('bcrypt'); 6 | 7 | process.on('message', function(m) { 8 | var r; 9 | if (m.op === 'encrypt') { 10 | r = bcrypt.hashSync(m.pass, bcrypt.genSaltSync(m.factor)); 11 | process.send({r:r}); 12 | } else if (m.op === 'compare') { 13 | r = bcrypt.compareSync(m.pass, m.hash); 14 | process.send({r:r}); 15 | } 16 | }); 17 | -------------------------------------------------------------------------------- /lib/bcrypt.js: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | const 6 | path = require('path'), 7 | computecluster = require('compute-cluster'), 8 | logger = require('../lib/logging/logging.js').logger, 9 | bcrypt = require('bcrypt'), 10 | config = require('./configuration.js'); 11 | 12 | var cc = new computecluster({ 13 | module: path.join(__dirname, "bcrypt-compute.js"), 14 | max_backlog: 100000, 15 | max_request_time: config.get('max_compute_duration') 16 | }); 17 | 18 | cc.on('error', function(e) { 19 | logger.error("error detected in bcrypt computation process! fatal: " + e.toString()); 20 | setTimeout(function() { process.exit(1); }, 0); 21 | }).on('info', function(msg) { 22 | logger.info("(compute cluster): " + msg); 23 | }).on('debug', function(msg) { 24 | logger.debug("(compute cluster): " + msg); 25 | }); 26 | 27 | exports.encrypt = function(workFactor, password, cb) { 28 | if (!cc) throw "bcrypt cluster is shut down"; 29 | cc.enqueue({ 30 | op: 'encrypt', 31 | factor: workFactor, 32 | pass: password 33 | }, function(err, r) { 34 | cb(err, r ? r.r : undefined); 35 | }); 36 | }; 37 | 38 | exports.compare = function(pass, hash, cb) { 39 | if (!cc) throw "bcrypt cluster is shut down"; 40 | cc.enqueue({ 41 | op: 'compare', 42 | pass: pass, 43 | hash: hash 44 | }, function(err, r) { 45 | cb(err, r ? r.r : undefined); 46 | }); 47 | }; 48 | 49 | exports.getRounds = function(hash) { 50 | return bcrypt.getRounds(hash); 51 | }; 52 | 53 | exports.shutdown = function() { 54 | if (cc) { 55 | cc.exit(); 56 | cc = undefined; 57 | } 58 | }; 59 | -------------------------------------------------------------------------------- /lib/boolean-query.js: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | module.exports = function boolean_query(req, res, next) { 6 | Object.keys(req.query).forEach(function(key) { 7 | if (req.query[key] === "true") req.query[key] = true; 8 | else if (req.query[key] === "false") req.query[key] = false; 9 | }); 10 | 11 | next(); 12 | }; 13 | -------------------------------------------------------------------------------- /lib/browserid/fake_verification.js: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | /* This little module will, when included, hook the email verification system 6 | * and instead of sending emails will make verification tokens available 7 | * via the WSAPI. This is *highly* insecure and should only be used when 8 | * testing (performance or otherwise). 9 | */ 10 | 11 | const 12 | configuration = require('../configuration.js'), 13 | url = require('url'), 14 | db = require('../db.js'), 15 | logger = require('../logging/logging.js').logger, 16 | wsapi = require('../wsapi'); 17 | 18 | logger.warn("HEAR YE: Fake verfication enabled, aceess via /wsapi/fake_verification?email=foo@bar.com"); 19 | logger.warn("THIS IS NEVER OK IN A PRODUCTION ENVIRONMENT"); 20 | 21 | exports.addVerificationWSAPI = function(app) { 22 | app.get('/wsapi/fake_verification', function(req, res) { 23 | var email = url.parse(req.url, true).query.email; 24 | db.verificationSecretForEmail(email, function(err, secret) { 25 | if (err) return wsapi.databaseDown(res, err); 26 | if (secret) res.write(secret); 27 | else res.writeHead(400, {"Content-Type": "text/plain"}); 28 | res.end(); 29 | }); 30 | }); 31 | }; 32 | -------------------------------------------------------------------------------- /lib/busy_middleware.js: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | // export a function that is express middleware which blocks requests 6 | // when we're too busy. uses https://npmjs.org/toobusy by lloyd 7 | 8 | var toobusy = require('toobusy'), 9 | config = require('./configuration'); 10 | 11 | const throttlingEnabled = !config.get('disable_request_throttling'); 12 | 13 | if (throttlingEnabled) { 14 | // set maximum event loop lag from configuration, which controls 15 | // just how busy we need to be before sending pre-emptive 503s. 16 | toobusy.maxLag(config.get('maximum_event_loop_lag')); 17 | } else { 18 | // when disabled, shutdown toobusy, which casues it to stop polling 19 | // the event loop to determine server load. 20 | toobusy.shutdown(); 21 | } 22 | 23 | module.exports = function(req, res, next) { 24 | if (throttlingEnabled && toobusy()) { 25 | res.send("server is too busy", {"Content-Type": "text/plain"}, 503); 26 | } else { 27 | next(); 28 | } 29 | }; 30 | 31 | module.exports.shutdown = toobusy.shutdown; 32 | -------------------------------------------------------------------------------- /lib/db/dbutils.js: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | const 6 | logger = require('../logging/logging.js').logger, 7 | primary = require('../primary.js'); 8 | 9 | // Callback has the signature `function (type) {}` 10 | exports.withType = function(email, cb) { 11 | var domain = email.replace(/[^@]*@/, ''); 12 | primary.checkSupport(domain, function (err, urls) { 13 | var type = 'secondary'; 14 | if (err) { 15 | logger.info('"' + domain + '" primary support is misconfigured, falling back to secondary: ' + err); 16 | // primary check failed, fall back to secondary email verification 17 | } else if (urls) { 18 | type = 'primary'; 19 | } 20 | cb(type); 21 | }); 22 | }; 23 | -------------------------------------------------------------------------------- /lib/httputils.js: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | // various little utilities to make crafting boilerplate responses 6 | // simple 7 | 8 | function sendResponse(resp, content, reason, code) { 9 | if (content) { 10 | if (reason) content += ": " + reason; 11 | } else if (reason) { 12 | content = reason; 13 | } else { 14 | content = ""; 15 | } 16 | resp.send(content, {"Content-Type": "text/plain"}, code); 17 | } 18 | 19 | exports.notFound = function(resp, reason) { 20 | sendResponse(resp, "Not Found", reason, 404); 21 | }; 22 | 23 | exports.serverError = function(resp, reason) { 24 | sendResponse(resp, "Server Error", reason, 500); 25 | }; 26 | 27 | exports.serviceUnavailable = function(resp, reason) { 28 | sendResponse(resp, "Service Unavailable", reason, 503); 29 | }; 30 | 31 | exports.authRequired = function(resp, reason) { 32 | sendResponse(resp, "Authentication Required", reason, 401); 33 | }; 34 | 35 | exports.badRequest = function(resp, reason) { 36 | sendResponse(resp, "Bad Request", reason, 400); 37 | }; 38 | 39 | exports.forbidden = function(resp, reason) { 40 | sendResponse(resp, "Forbidden", reason, 403); 41 | }; 42 | 43 | exports.throttled = function(resp, reason) { 44 | sendResponse(resp, "Too Many Requests", reason, 429); 45 | }; 46 | -------------------------------------------------------------------------------- /lib/keysigner/ca.js: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | // certificate authority 6 | 7 | var jwcrypto = require('jwcrypto'), 8 | cert = jwcrypto.cert, 9 | secrets = require('../secrets.js'), 10 | logger = require('../logging/logging.js').logger; 11 | 12 | // load up the right algorithms 13 | require("jwcrypto/lib/algs/rs"); 14 | require("jwcrypto/lib/algs/ds"); 15 | 16 | try { 17 | const secret_key = secrets.loadSecretKey(); 18 | const public_key = secrets.loadPublicKey(); 19 | } catch(e){ 20 | logger.error("can't read keys, exiting: " + e); 21 | setTimeout(function() { process.exit(1); }, 0); 22 | } 23 | 24 | function parsePublicKey(serializedPK) { 25 | return jwcrypto.loadPublicKey(serializedPK); 26 | } 27 | 28 | function certify(hostname, email, publicKey, expiration, unverified, cb) { 29 | if (expiration == null) 30 | return cb("expiration cannot be null"); 31 | 32 | //TODO: use a different secret if unverified 33 | 34 | var principal = {}; 35 | principal[ unverified ? 'unverified-email' : 'email' ] = email; 36 | 37 | 38 | cert.sign({publicKey: publicKey, principal: principal}, 39 | {issuer: hostname, issuedAt: new Date(), expiresAt: expiration}, 40 | null, 41 | secret_key, cb); 42 | } 43 | 44 | // exports, not the key stuff 45 | exports.certify = certify; 46 | exports.parsePublicKey = parsePublicKey; 47 | exports.PUBLIC_KEY = public_key; 48 | -------------------------------------------------------------------------------- /lib/keysigner/keysigner-compute.js: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | const 6 | ca = require('./ca.js'); 7 | 8 | process.on('message', function(m) { 9 | try { 10 | // parse the pubkey 11 | var pk = ca.parsePublicKey(m.pubkey); 12 | 13 | // same account, we certify the key 14 | // we certify it for a day for now 15 | var expiration = new Date(); 16 | expiration.setTime(new Date().valueOf() + m.validityPeriod); 17 | var issuer = !!m.forceIssuer ? m.forceIssuer : m.hostname; 18 | ca.certify(issuer, m.email, pk, expiration, m.unverified, function(err, cert) { 19 | if (err) 20 | return process.send({"error": err}); 21 | 22 | process.send({"success": cert}); 23 | }); 24 | } catch(e) { 25 | process.send({"error": e ? e.toString() : "unknown"}); 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /lib/load_gen/activities/include_only.js: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | /* this file is the "include_only" activity, which simulates the load 6 | * of an RP including include.js. */ 7 | 8 | var client = require('../../wsapi_client.js'); 9 | 10 | exports.startFunc = function(cfg, cb) { 11 | client.get(cfg, '/include.js', {}, undefined, function(err, r) { 12 | if (err) { 13 | cb(err); 14 | } else if (!r || r.code !== 200) { 15 | cb("for include.js fetch response code is not 200: " + (r ? r.code : "no response")); 16 | } else { 17 | // XXX: check the checksum of body? 18 | cb(); 19 | } 20 | }); 21 | }; 22 | -------------------------------------------------------------------------------- /lib/logging/custom_logger.js: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | /** 6 | * Enhances connect logger middleware - custom formats. See lib/configuration for usage. 7 | * 8 | * Note: No exports, ya I feel dirty too. 9 | */ 10 | var logger = require('express').logger; 11 | 12 | logger.format('default_bid', 13 | ':remote-addr - - ":method :url HTTP/:http-version" :status :response-time :res[content-length] ":referrer" ":user-agent"'); 14 | 15 | logger.format('dev_bid', ':method :url :status :response-time'); 16 | 17 | -------------------------------------------------------------------------------- /lib/logging/middleware/statsd.js: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | const baseExceptions = require('../../baseExceptions'); 6 | const config = require('../../configuration'); 7 | const logger = require('../logging').logger; 8 | const statsd_request_logger = require("connect-logger-statsd"); 9 | const PREFIX = "browserid." + config.get('process_type') + "."; 10 | 11 | module.exports = function(prefix) { 12 | var statsdConfig = config.get('statsd'); 13 | if (statsdConfig && statsdConfig.enabled) { 14 | // send the messages over the winston pipe where they will 15 | // be collected by winston-statsd 16 | return statsd_request_logger({ 17 | host: statsdConfig.hostname || "localhost", 18 | port: statsdConfig.port || 8125, 19 | prefix: statsdConfig.prefix || prefix || PREFIX 20 | }); 21 | } 22 | 23 | // Pass back a null middleware function if statsd is not configured. 24 | // This allows us to keep the callers tidy and not worry about whether 25 | // statsd is configured before calling "use" on the middleware. 26 | return function(req, res, next) { 27 | next(); 28 | }; 29 | }; 30 | 31 | // Upgrade from console.error to statsd and winston 32 | baseExceptions.removeExceptionHandler(); 33 | 34 | process.on('uncaughtException', function(err) { 35 | logger.info('uncaught_exception'); 36 | logger.error(err.stack || err); 37 | }); 38 | 39 | 40 | -------------------------------------------------------------------------------- /lib/logging/transports/filters/statsd-increment.js: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | const config = require('../../../configuration'); 6 | const PREFIX = "browserid." + config.get('process_type') + "."; 7 | 8 | 9 | var IncrementMessageMatches = { 10 | "assertion_failure": true, 11 | "uncaught_exception": true 12 | }; 13 | 14 | var IncrementRegExpMatches = [ 15 | /^wsapi_code_mismatch\./, 16 | /^wsapi\./ 17 | ]; 18 | 19 | exports.test = function(msg) { 20 | if (msg in IncrementMessageMatches) return true; 21 | 22 | for (var i = 0, regExp; regExp = IncrementRegExpMatches[i]; ++i) { 23 | if (regExp.test(msg)) return true; 24 | } 25 | 26 | return false; 27 | }; 28 | 29 | exports.toType = function(msg) { 30 | return PREFIX + msg; 31 | }; 32 | 33 | 34 | -------------------------------------------------------------------------------- /lib/logging/transports/filters/statsd-timing.js: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | const config = require('../../../configuration'); 6 | const PREFIX = "browserid." + config.get('process_type') + "."; 7 | 8 | var TimingMessageMatches = { 9 | "bcrypt.compare_time": true, 10 | "query_time": true, 11 | "certification_time": true, 12 | "assertion_verification_time": true 13 | }; 14 | 15 | var TimingRegExpMatches = [ 16 | /^elapsed_time\.(.*)/ 17 | ]; 18 | 19 | function getMatch(msg) { 20 | if (msg in TimingMessageMatches) return true; 21 | 22 | for (var i = 0, regExp; regExp = TimingRegExpMatches[i]; ++i) { 23 | if (regExp.test(msg)) return regExp; 24 | } 25 | } 26 | 27 | exports.test = function(msg) { 28 | return !!getMatch(msg); 29 | }; 30 | 31 | exports.toType = function(msg) { 32 | var match = getMatch(msg); 33 | 34 | // Use the capturing part of the match for the message. 35 | if (match instanceof RegExp) 36 | msg = msg.match(match)[1]; 37 | 38 | return PREFIX + msg; 39 | }; 40 | 41 | 42 | -------------------------------------------------------------------------------- /lib/logging/transports/log-file.js: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | /** 6 | * Winston transport that takes care of writing to the process specific log. 7 | * Logs are generally found in17 | <%- format(gettext('Mozilla Persona. Simple sign-in from the non-profit behind Firefox.'), ["href='https://login.persona.org/about' target='_blank' style='color:#3d3d3f; text-decoration: none;'"]) %> 18 | | 19 |