├── .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 in /var/log/.log 8 | */ 9 | 10 | const winston = require('winston'); 11 | const File = winston.transports.File; 12 | const util = require('util'); 13 | const configuration = require("../../configuration"); 14 | const path = require('path'); 15 | const mkdirp = require('mkdirp'); 16 | const _ = require('underscore'); 17 | 18 | "use strict"; 19 | 20 | // go through the configuration and determine log location 21 | var log_path = path.join(configuration.get('var_path'), 'log'); 22 | if (!log_path) 23 | return console.log("no log path! Not logging!"); 24 | else 25 | mkdirp.sync(log_path, "0755"); 26 | 27 | var filename = path.join(log_path, configuration.get('process_type') + ".log"); 28 | 29 | var FileTransport = function(options) { 30 | options = _.extend({ 31 | timestamp: function () { return new Date().toISOString(); }, 32 | filename: filename, 33 | colorize: true, 34 | handleExceptions: true 35 | }, options); 36 | 37 | File.call(this, options); 38 | }; 39 | util.inherits(FileTransport, File); 40 | 41 | FileTransport.prototype.name = 'fileTransport'; 42 | 43 | 44 | module.exports = FileTransport; 45 | 46 | -------------------------------------------------------------------------------- /lib/logging/transports/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 util = require('util'); 6 | const winston = require('winston'); 7 | const StatsD = require("node-statsd").StatsD; 8 | const logger = require('../logging').logger; 9 | const config = require('../../configuration'); 10 | const timing_filter = require('./filters/statsd-timing'); 11 | const increment_filter = require('./filters/statsd-increment'); 12 | 13 | "use strict"; 14 | 15 | var StatsdTransport = function(options) { 16 | options = options || {}; 17 | 18 | this.name = 'statsdTransport'; 19 | 20 | this.statsd = options.statsd || getStatsdIfEnabled(); 21 | }; 22 | 23 | util.inherits(StatsdTransport, winston.Transport); 24 | 25 | StatsdTransport.prototype.log = function(level, msg, meta, callback) { 26 | if ( ! this.statsd) return callback(null, true); 27 | 28 | if (increment_filter.test(msg)) { 29 | this.statsd.increment(increment_filter.toType(msg), meta); 30 | } 31 | else if (timing_filter.test(msg)) { 32 | this.statsd.timing(timing_filter.toType(msg), meta, meta); 33 | } 34 | 35 | callback(null, true); 36 | }; 37 | 38 | 39 | function getStatsdIfEnabled() { 40 | var statsdConfig = config.get('statsd'); 41 | if (statsdConfig && statsdConfig.enabled) { 42 | var statsdOptions = {}; 43 | statsdOptions.host = statsdConfig.host || "localhost"; 44 | statsdOptions.port = statsdConfig.port || 8125; 45 | 46 | return new StatsD(statsdOptions.host, statsdOptions.port); 47 | } 48 | } 49 | 50 | 51 | module.exports = StatsdTransport; 52 | -------------------------------------------------------------------------------- /lib/p3p.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 | var useragent = require('useragent'), 6 | policy = 'CP="This is not a P3P policy, but Mozilla deeply cares about ' + 7 | 'your privacy. See http://www.mozilla.org/persona/privacy-policy ' + 8 | 'for more."'; 9 | 10 | // add 'P3P' headers so that IE8, with default security settings, will allow 11 | // us to set third-party cookies. Only add the headers in that case, saving 12 | // bytes for all the other browsers. #2340 13 | module.exports = function(req, res, next) { 14 | var browser = useragent.parse(req.headers['user-agent']); 15 | if (browser.family === 'IE') { 16 | res.on('header', function() { 17 | res.setHeader('P3P', policy); 18 | }); 19 | } 20 | next(); 21 | }; 22 | -------------------------------------------------------------------------------- /lib/proxy-secure.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 | 7 | const OVER_SSL = config.get('scheme') === 'https'; 8 | 9 | // we set this parameter so that hood.hsts() and clientSessions() 10 | // can work even though the local connection is HTTP 11 | // (the load balancer does SSL) 12 | module.exports = function proxySecureFactory() { 13 | return OVER_SSL ? function proxySecure(req, res, next) { 14 | req.connection.proxySecure = true; 15 | next(); 16 | } : function proxyNotSecure(req, res, next) { 17 | next(); 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /lib/verifier/verifier-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 | certassertion = require('./certassertion.js'); 7 | 8 | process.on('message', function(m) { 9 | try { 10 | certassertion.verify( 11 | m.assertion, m.audience, m.forceIssuer, !!m.allowUnverified, 12 | function(email, audienceFromAssertion, expires, issuer, verified) { 13 | var data = { 14 | success: { 15 | audience: audienceFromAssertion, 16 | expires: expires, 17 | issuer: issuer 18 | } 19 | }; 20 | verified ? data.success.email = email : data.success['unverified-email'] = email; 21 | process.send(data); 22 | }, 23 | function(error) { 24 | process.send({error: error}); 25 | }); 26 | } catch(e) { 27 | process.send({error: e.toString()}); 28 | } 29 | }); 30 | -------------------------------------------------------------------------------- /lib/wsapi/account_cancel.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 | db = require('../db.js'), 7 | wsapi = require('../wsapi'), 8 | logger = require('../logging/logging.js').logger, 9 | cef_logger = require('../logging/cef_logger').getInstance(); 10 | 11 | exports.method = 'post'; 12 | exports.writes_db = true; 13 | exports.authed = 'assertion'; 14 | exports.i18n = false; 15 | 16 | exports.process = function(req, res) { 17 | db.cancelAccount(req.session.userid, function(error) { 18 | if (error) { 19 | cef_logger.alert("ACCOUNT_CANCEL", "Error canceling account", 20 | req, {duser: req.session.userid, msg: error}); 21 | wsapi.databaseDown(res, error); 22 | } else { 23 | cef_logger.warn("ACCOUNT_CANCEL", "Canceled user account", 24 | req, {duser: req.session.userid}); 25 | res.json({ success: true }); 26 | }}); 27 | }; 28 | -------------------------------------------------------------------------------- /lib/wsapi/create_account_with_assertion.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 | db = require('../db.js'), 7 | wsapi = require('../wsapi.js'), 8 | httputils = require('../httputils'), 9 | primary = require('../primary.js'), 10 | logger = require('../logging/logging.js').logger; 11 | 12 | exports.method = 'post'; 13 | exports.writes_db = true; 14 | exports.authed = false; 15 | exports.internal = true; 16 | exports.args = { 17 | assertion: 'assertion' 18 | }; 19 | exports.i18n = false; 20 | 21 | exports.process = function(req, res) { 22 | // let's (re)verify that the assertion is valid 23 | primary.verifyAssertion(req.params.assertion, function(err, email) { 24 | if (err) { 25 | // this should not be an error, the assertion should have already been 26 | // tested on the webhead 27 | logger.error('verfication of primary assertion failed unexpectedly dbwriter (' + err + '): ' + 28 | req.params.assertion); 29 | 30 | return httputils.serverError(res); 31 | } 32 | 33 | db.createUserWithPrimaryEmail(email, function(err, uid, lastPasswordReset) { 34 | if (err) return wsapi.databaseDown(res); 35 | 36 | logger.info('idp.create_new_user', { idp: toIdp(email) }); 37 | res.json({ 38 | success: true, 39 | userid: uid, 40 | lastPasswordReset: lastPasswordReset 41 | }); 42 | }); 43 | }); 44 | }; 45 | 46 | function toIdp(email) { 47 | return email.split('@')[1]; 48 | } 49 | -------------------------------------------------------------------------------- /lib/wsapi/email_reverify_status.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 | db = require('../db.js'), 7 | wsapi = require('../wsapi.js'); 8 | 9 | /* A polled API which returns whether the user has completed reverification 10 | * of an email address 11 | */ 12 | 13 | exports.method = 'get'; 14 | exports.writes_db = false; 15 | exports.authed = 'assertion'; 16 | exports.args = { email: 'email' }; 17 | exports.i18n = false; 18 | 19 | exports.process = function(req, res) { 20 | 21 | // For simplicity, all we check is if an email is verified. We do not check that 22 | // the email is owned by the currently authenticated user, nor that the verification 23 | // secret still exists. These checks would require more database interactions, and 24 | // other calls will fail in such circumstances. 25 | db.emailIsVerified(req.params.email, function(err, verified) { 26 | if (err) return wsapi.databaseDown(res, err); 27 | res.json({ status: verified ? 'complete' : 'pending' }); 28 | }); 29 | }; 30 | -------------------------------------------------------------------------------- /lib/wsapi/forget_idp.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 | // update the 'idp' table noting that an idp was recently "seen", 6 | // that they serve a valid support document. This is an internal 7 | // api on the dbwriter, invoked by the browserid process when 8 | // checking idps. 9 | 10 | const 11 | db = require('../db.js'), 12 | wsapi = require('../wsapi.js'), 13 | httputils = require('../httputils'), 14 | primary = require('../primary.js'), 15 | logger = require('../logging/logging.js').logger; 16 | 17 | exports.method = 'get'; 18 | exports.writes_db = true; 19 | exports.authed = false; 20 | exports.internal = true; 21 | exports.args = { 22 | domain: 'hostname' 23 | }; 24 | exports.i18n = false; 25 | 26 | exports.process = function(req, res) { 27 | db.forgetIDP(req.params.domain, function(err) { 28 | if (err) return wsapi.databaseDown(res); 29 | res.json({ success: true }); 30 | }); 31 | }; 32 | -------------------------------------------------------------------------------- /lib/wsapi/have_email.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 | db = require('../db.js'), 7 | wsapi = require('../wsapi.js'), 8 | url = require('url'), 9 | cef_logger = require('../logging/cef_logger').getInstance(); 10 | 11 | // return if an email is known to browserid 12 | 13 | exports.method = 'get'; 14 | exports.writes_db = false; 15 | exports.authed = false; 16 | exports.i18n = false; 17 | exports.args = { 18 | 'email': 'email' 19 | }; 20 | 21 | exports.process = function(req, res) { 22 | db.emailKnown(req.params.email, function(err, known) { 23 | if (err) { 24 | cef_logger.alert("DB_FAILURE", "emailKnown failed", 25 | req, {duser: req.params.email, msg: err}); 26 | return wsapi.databaseDown(res, err); 27 | } 28 | res.json({ email_known: known }); 29 | }); 30 | }; 31 | -------------------------------------------------------------------------------- /lib/wsapi/increment_failed_auth_tries.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 | db = require('../db.js'), 7 | wsapi = require('../wsapi.js'); 8 | 9 | exports.method = 'get'; 10 | exports.writes_db = true; 11 | exports.authed = false; 12 | exports.internal = true; 13 | exports.args = { 14 | userid: 'userid' 15 | }; 16 | exports.i18n = false; 17 | 18 | exports.process = function(req, res) { 19 | db.incAuthFailures(req.params.userid, function(err) { 20 | if (err) return wsapi.databaseDown(res); 21 | res.json({ success: true }); 22 | }); 23 | }; 24 | 25 | -------------------------------------------------------------------------------- /lib/wsapi/interaction_data.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 coarse = require('../coarse_user_agent_parser'), 6 | logger = require('../logging/logging').logger, 7 | und = require('underscore'), 8 | kpiTransport = require('../logging/transports/metrics-kpi').getInstance(); 9 | 10 | // Accept JSON formatted interaction data and send it to the KPI Backend 11 | 12 | // WSAPI provides CSRF protection 13 | // TODO size limit is currently 10kb from bin/browserid, may need to expand this 14 | 15 | exports.method = 'post'; 16 | exports.writes_db = false; 17 | exports.authed = false; 18 | exports.i18n = false; 19 | 20 | 21 | exports.process = function(req, res) { 22 | // Always send a quick success response. The client won't know if 23 | // the interaction_data blob successfully made it into the backend, 24 | // but because this is non-critical data, it's not worth leaving 25 | // the connection open and reporting this information for now. 26 | res.json({ success: true }); 27 | 28 | if (req.body.data) { 29 | var kpi_json = req.body.data; 30 | 31 | if (req.headers['user-agent']) { 32 | var ua = coarse.parse(req.headers['user-agent']); 33 | und.each(kpi_json, function (kpi) { 34 | if (! kpi.user_agent) { 35 | kpi.user_agent = {}; 36 | } 37 | und.extend(kpi.user_agent, ua); 38 | }); 39 | } 40 | 41 | kpiTransport.push(kpi_json); 42 | } else { 43 | logger.info("failed to store interaction data, client sent no .data"); 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /lib/wsapi/list_emails.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 | db = require('../db.js'), 7 | logger = require('../logging/logging.js').logger, 8 | wsapi = require('../wsapi.js'); 9 | 10 | // returns a list of emails owned by the user: 11 | // 12 | // { 13 | // "foo@foo.com" : {..properties..} 14 | // ... 15 | // } 16 | 17 | exports.method = 'get'; 18 | exports.writes_db = false; 19 | exports.authed = 'assertion'; 20 | exports.i18n = false; 21 | 22 | exports.process = function(req, res) { 23 | logger.debug('listing emails for user ' + req.session.userid); 24 | db.listEmails(req.session.userid, function(err, emails) { 25 | if (err) wsapi.databaseDown(res, err); 26 | else res.json({ 27 | success: true, 28 | emails: emails 29 | }); 30 | }); 31 | }; 32 | -------------------------------------------------------------------------------- /lib/wsapi/logout.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 | wsapi = require('../wsapi.js'), 7 | cef_logger = require('../logging/cef_logger').getInstance(); 8 | 9 | exports.method = 'post'; 10 | exports.writes_db = false; 11 | exports.authed = 'assertion'; 12 | exports.i18n = false; 13 | 14 | exports.process = function(req, res) { 15 | wsapi.clearAuthenticatedUser(req.session); 16 | cef_logger.info("USER_LOGOUT", "User logout", req); 17 | res.json({ success: true }); 18 | }; 19 | -------------------------------------------------------------------------------- /lib/wsapi/password_reset_status.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 | db = require('../db.js'), 7 | wsapi = require('../wsapi.js'), 8 | logger = require('../logging/logging.js').logger, 9 | httputils = require('../httputils.js'); 10 | 11 | exports.method = 'get'; 12 | exports.writes_db = false; 13 | exports.authed = false; 14 | exports.args = { email: 'email' }; 15 | exports.i18n = false; 16 | 17 | exports.process = function(req, res) { 18 | var email = req.params.email; 19 | 20 | // if the email is in the staged table, we are not complete yet. 21 | // if the email is not in the staged table - 22 | // * if we are authenticated as the owner of the email we're done 23 | // * if we are not authenticated as the owner of the email, we must auth 24 | db.isStaged(email, function(err, staged) { 25 | if (err) wsapi.databaseDown(res, err); 26 | 27 | if (staged) { 28 | return res.json({ status: 'pending' }); 29 | } else { 30 | if (wsapi.isAuthed(req, 'assertion')) { 31 | db.userOwnsEmail(req.session.userid, email, function(err, owned) { 32 | if (err) wsapi.databaseDown(res, err); 33 | else if (owned) res.json({ status: 'complete', userid: req.session.userid }); 34 | else res.json({ status: 'mustAuth' }); 35 | }); 36 | } else { 37 | return res.json({ status: 'mustAuth' }); 38 | } 39 | } 40 | }); 41 | }; 42 | -------------------------------------------------------------------------------- /lib/wsapi/ping.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 db = require('../db.js'); 6 | 7 | exports.method = 'get'; 8 | exports.writes_db = false; 9 | exports.i18n = false; 10 | 11 | exports.process = function(req, res) { 12 | db.ping(function(err) { 13 | if (err) res.send("fail", 500); 14 | else res.send("ok",200); 15 | }); 16 | }; 17 | -------------------------------------------------------------------------------- /lib/wsapi/prolong_session.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 | config = require('../configuration.js'), 7 | wsapi = require('../wsapi.js'), 8 | wsapiutils = require('../wsapiutils'); 9 | 10 | exports.method = 'post'; 11 | exports.writes_db = false; 12 | exports.authed = 'assertion'; 13 | exports.i18n = false; 14 | 15 | exports.process = function(req, res) { 16 | wsapi.authenticateSession({session: req.session, 17 | uid: req.session.userid, 18 | level: req.session.auth_level, 19 | duration_ms: wsapiutils.getDurationInfo(req).durationMS 20 | }, function(err) { 21 | if (err) return wsapi.databaseDown(res, err); 22 | res.send(200); 23 | }); 24 | }; 25 | -------------------------------------------------------------------------------- /lib/wsapi/remove_email.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 | db = require('../db.js'), 7 | wsapi = require('../wsapi'), 8 | httputils = require('../httputils'), 9 | logger = require('../logging/logging.js').logger, 10 | cef_logger = require('../logging/cef_logger').getInstance(); 11 | 12 | exports.method = 'post'; 13 | exports.writes_db = true; 14 | exports.authed = 'assertion'; 15 | exports.args = { 16 | 'email': 'email' 17 | }; 18 | exports.i18n = false; 19 | 20 | exports.process = function(req, res) { 21 | var email = req.params.email; 22 | 23 | db.removeEmail(req.session.userid, email, function(error) { 24 | if (error) { 25 | cef_logger.alert("REMOVE_EMAIL", "Error removing email", 26 | req, {duser: req.session.userid, msg: error}); 27 | logger.warn("error removing email " + email); 28 | if (error === 'database connection unavailable') { 29 | wsapi.databaseDown(res, error); 30 | } else { 31 | httputils.badRequest(res, error.toString()); 32 | } 33 | } else { 34 | cef_logger.info("REMOVE_EMAIL", "Removed user email", 35 | req, {duser: req.session.userid}); 36 | res.json({ success: true }); 37 | }}); 38 | }; 39 | -------------------------------------------------------------------------------- /lib/wsapi/reset_failed_auth_tries.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 | db = require('../db.js'), 7 | wsapi = require('../wsapi.js'); 8 | 9 | exports.method = 'get'; 10 | exports.writes_db = true; 11 | exports.authed = true; 12 | exports.internal = true; 13 | exports.args = {}; 14 | exports.i18n = false; 15 | 16 | exports.process = function(req, res) { 17 | db.clearAuthFailures(req.session.userid, function(err) { 18 | if (err) return wsapi.databaseDown(res); 19 | res.json({ success: true }); 20 | }); 21 | }; 22 | 23 | -------------------------------------------------------------------------------- /lib/wsapi/saw_idp.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 | // update the 'idp' table noting that an idp was recently "seen", 6 | // that they serve a valid support document. This is an internal 7 | // api on the dbwriter, invoked by the browserid process when 8 | // checking idps. 9 | 10 | const 11 | db = require('../db.js'), 12 | wsapi = require('../wsapi.js'), 13 | httputils = require('../httputils'), 14 | primary = require('../primary.js'), 15 | logger = require('../logging/logging.js').logger; 16 | 17 | exports.method = 'get'; 18 | exports.writes_db = true; 19 | exports.authed = false; 20 | exports.internal = true; 21 | exports.args = { 22 | domain: 'hostname' 23 | }; 24 | exports.i18n = false; 25 | 26 | exports.process = function(req, res) { 27 | db.updateIDPLastSeen(req.params.domain, function(err) { 28 | if (err) return wsapi.databaseDown(res); 29 | res.json({ success: true }); 30 | }); 31 | }; 32 | 33 | -------------------------------------------------------------------------------- /lib/wsapi/transition_status.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 | db = require('../db.js'), 7 | wsapi = require('../wsapi.js'), 8 | logger = require('../logging/logging.js').logger, 9 | httputils = require('../httputils.js'); 10 | 11 | exports.method = 'get'; 12 | exports.writes_db = false; 13 | exports.authed = false; 14 | exports.args = { email: 'email' }; 15 | exports.i18n = false; 16 | 17 | exports.process = function(req, res) { 18 | var email = req.params.email; 19 | 20 | // if the email is in the staged table, we are not complete yet. 21 | // if the email is not in the staged table - 22 | // * if we are authenticated as the owner of the email we're done 23 | // * if we are not authenticated as the owner of the email, we must auth 24 | db.isStaged(email, function(err, staged) { 25 | if (err) wsapi.databaseDown(res, err); 26 | 27 | if (staged) { 28 | return res.json({ status: 'pending' }); 29 | } else { 30 | if (wsapi.isAuthed(req, 'assertion')) { 31 | db.userOwnsEmail(req.session.userid, email, function(err, owned) { 32 | if (err) wsapi.databaseDown(res, err); 33 | else if (owned) res.json({ status: 'complete', userid: req.session.userid }); 34 | else res.json({ status: 'mustAuth' }); 35 | }); 36 | } else { 37 | return res.json({ status: 'mustAuth' }); 38 | } 39 | } 40 | }); 41 | }; 42 | -------------------------------------------------------------------------------- /lib/wsapi/user_used_email_as.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 | // an internal api on the dbwriter to update "lastUsedAs". 6 | // This is an internal api on the dbwriter, invoked by the browserid 7 | // process when a user calls cert_key. 8 | 9 | const 10 | db = require('../db.js'), 11 | wsapi = require('../wsapi.js'), 12 | httputils = require('../httputils'), 13 | primary = require('../primary.js'), 14 | logger = require('../logging/logging.js').logger; 15 | 16 | exports.method = 'post'; 17 | exports.writes_db = true; 18 | exports.authed = 'assertion'; 19 | exports.internal = true; 20 | exports.args = { 21 | email: 'email', 22 | used_as: 'email_type' 23 | }; 24 | 25 | exports.i18n = false; 26 | 27 | exports.process = function(req, res) { 28 | // this check is redundant. Because this is an internal API, it can only be 29 | // called from our software. we expect that the browserid process forwards 30 | // us the user's credentials in a cookie AND double check that the authenticated 31 | // user owns the email address. Expensive but safe. Optimize later. 32 | db.userOwnsEmail(req.session.userid, req.params.email, function(err, owned) { 33 | if (err) return wsapi.databaseDown(res, err); 34 | 35 | if (!owned) { 36 | return httputils.badRequest(res, "email does not belong to authenticated user"); 37 | } 38 | 39 | db.updateEmailLastUsedAs(req.params.email, req.params.used_as, function (err) { 40 | if (err) return wsapi.databaseDown(res, err); 41 | res.json({ success: true }); 42 | }); 43 | }); 44 | }; 45 | 46 | -------------------------------------------------------------------------------- /lib/wsapiutils.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 | // utility functions for wsapi modules 6 | 7 | const config = require('./configuration'); 8 | 9 | const FIREFOX_OS_DURATION = 315360000000; // 10 years 10 | 11 | /** 12 | * Get info about how long the session should be and why 13 | * 14 | * @param {object} req - the http request object 15 | * 16 | * Returns object with properties sessionDurationMS and 17 | * isFirefoxOSDuration. 18 | */ 19 | module.exports.getDurationInfo = function getDurationInfo(req) { 20 | req.params = req.params || {}; 21 | req.headers = req.headers || {}; 22 | 23 | const ephemeral = req.params.ephemeral; 24 | const ua_string = req.headers['user-agent'] || ""; 25 | 26 | var result = { 27 | durationMS: ephemeral 28 | ? config.get('ephemeral_session_duration_ms') 29 | : config.get('authentication_duration_ms'), 30 | suppressAskIsUsersComputer: false 31 | }; 32 | 33 | // FirefoxOS wants sessions to last for 10 years. 34 | // 35 | // (Kittens die when you match user agent strings. So if you 36 | // like kittens, avert your eyes now.) 37 | // 38 | // Example ua: Mozilla/5.0 (Mobile; rv:18.0) Gecko/18.0 Firefox/18.0 39 | // Note: V8 compiles regexes automatically. 40 | if (ua_string.match(/Mobile.*Firefox/)) { 41 | result.durationMS = FIREFOX_OS_DURATION; 42 | result.suppressAskIsUsersComputer = true; 43 | } 44 | 45 | return result; 46 | }; 47 | 48 | -------------------------------------------------------------------------------- /resources/.gitignore: -------------------------------------------------------------------------------- 1 | static/dialog/views/templates.js 2 | -------------------------------------------------------------------------------- /resources/assets/account-buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/assets/account-buttons.png -------------------------------------------------------------------------------- /resources/assets/browserID-135x35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/assets/browserID-135x35.png -------------------------------------------------------------------------------- /resources/assets/browserID-366x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/assets/browserID-366x72.png -------------------------------------------------------------------------------- /resources/assets/browserID-80x20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/assets/browserID-80x20.png -------------------------------------------------------------------------------- /resources/assets/browserID-buttons.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/assets/browserID-buttons.psd -------------------------------------------------------------------------------- /resources/assets/browserID-logo.eps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/assets/browserID-logo.eps -------------------------------------------------------------------------------- /resources/dnt-policy.txt: -------------------------------------------------------------------------------- 1 | PRELIMINARY DNT POLICY 2 | 3 | This domain interprets DNT as a request for an opt out of collection and 4 | retention of visitors' reading habits, which we will respect, subject to 5 | reasonable exceptions that respect user privacy. 6 | 7 | This is a temporary document. A full DNT Policy is being drafted at 8 | https://eff.org/dnt-policy . When that document is finished, this domain may 9 | decide to adopt it. 10 | 11 | You can agree to this same policy by posting it at 12 | https://subdomain.example.com/.well-known/dnt-policy.txt, where "subdomain" is 13 | any domain to which the policy applies. Commonly it will be posted on third 14 | party domains. HTTPS is required. 15 | 16 | -------------------------------------------------------------------------------- /resources/email_templates/_footer.html.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 19 | 20 |
17 | <%- 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 |
21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /resources/email_templates/confirm.ejs: -------------------------------------------------------------------------------- 1 | <%= format(gettext('Click this link to confirm access to %(site)s:'), { site: site })%> 2 | <%= link %> 3 | 4 | <%= gettext('If you were NOT attempting this sign-in, please ignore this email.') %> 5 | 6 | :::<%= gettext('Mozilla Persona') %> 7 | :::<%= gettext('Simple sign-in from the non-profit behind Firefox') %> 8 | :::<%= gettext('Learn more at https://login.persona.org/about') %> 9 | -------------------------------------------------------------------------------- /resources/email_templates/confirm.html.ejs: -------------------------------------------------------------------------------- 1 | <% include _header.html.ejs %> 2 | 3 | 4 | 5 | <%- format(gettext('Click this link to confirm access to %(site)s:'), { site: '' + site + '' })%> 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | <%= gettext('Confirm your address now') %> 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | <%= gettext('If you were NOT attempting this sign-in, please ignore this email.') %> 30 | 31 | 32 | 33 | 34 | <% include _footer.html.ejs %> 35 | 36 | -------------------------------------------------------------------------------- /resources/email_templates/new.ejs: -------------------------------------------------------------------------------- 1 | <%= format(gettext('Click this link to confirm access to %(site)s:'), { site: site })%> 2 | <%= link %> 3 | 4 | <%= gettext('If you were NOT attempting this sign-in, please ignore this email.') %> 5 | 6 | :::<%= gettext('Mozilla Persona') %> 7 | :::<%= gettext('Simple sign-in from the non-profit behind Firefox') %> 8 | :::<%= gettext('Learn more at https://login.persona.org/about') %> 9 | -------------------------------------------------------------------------------- /resources/email_templates/new.html.ejs: -------------------------------------------------------------------------------- 1 | <% include _header.html.ejs %> 2 | 3 | 4 | 5 | 6 | <%- format(gettext('Click this link to confirm access to %(site)s:'), { site: '' + site + '' })%> 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | <%= gettext('Confirm your account now') %> 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | <%= gettext('If you were NOT attempting this sign-in, please ignore this email.') %> 31 | 32 | 33 | 34 | 35 | 36 | <% include _footer.html.ejs %> 37 | 38 | -------------------------------------------------------------------------------- /resources/email_templates/reset.ejs: -------------------------------------------------------------------------------- 1 | <%= gettext('Forgot your password for Persona? It happens to the best of us.') %> 2 | 3 | <%= gettext('Click to reset your password:') %> 4 | <%= link %> 5 | 6 | <%= gettext('If you were NOT attempting to reset your password, please ignore this email.') %> 7 | 8 | :::<%= gettext('Mozilla Persona') %> 9 | :::<%= gettext('Simple sign-in from the non-profit behind Firefox') %> 10 | :::<%= gettext('Learn more at https://login.persona.org/about') %> 11 | -------------------------------------------------------------------------------- /resources/email_templates/reset.html.ejs: -------------------------------------------------------------------------------- 1 | <% include _header.html.ejs %> 2 | 3 | 4 | 5 | <%= gettext('Forgot your password for Persona? It happens to the best of us.') %> 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | <%= gettext('Reset your password now') %> 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | <%= gettext('If you were NOT attempting to reset your password, please ignore this email.') %> 30 | 31 | 32 | 33 | 34 | <% include _footer.html.ejs %> 35 | -------------------------------------------------------------------------------- /resources/email_templates/transition.ejs: -------------------------------------------------------------------------------- 1 | <%= gettext('It looks like your email provider is having trouble with their Persona support.') %> 2 | 3 | <%= format(gettext('Click this link to confirm access to %(site)s:'), { site: site })%> 4 | <%= link %> 5 | 6 | <%= gettext('If you were NOT attempting this sign-in, please ignore this email.') %> 7 | 8 | :::<%= gettext('Mozilla Persona') %> 9 | :::<%= gettext('Simple sign-in from the non-profit behind Firefox') %> 10 | :::<%= gettext('Learn more at https://login.persona.org/about') %> 11 | -------------------------------------------------------------------------------- /resources/email_templates/transition.html.ejs: -------------------------------------------------------------------------------- 1 | <% include _header.html.ejs %> 2 | 3 | 4 | 5 | <%= gettext('It looks like your email provider is having trouble with their Persona support.') %> 6 | 7 | 8 | <%- format(gettext('Click this link to confirm access to %(site)s:'), { site: '' + site + '' })%> 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | <%= gettext('Confirm your address now') %> 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | <%= gettext('If you were NOT attempting this sign-in, please ignore this email.') %> 33 | 34 | 35 | 36 | <% include _footer.html.ejs %> 37 | 38 | -------------------------------------------------------------------------------- /resources/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: /sign_in 3 | Disallow: /unsupported_dialog 4 | Disallow: /verify_email_address 5 | Disallow: /add_email_address 6 | Disallow: /cookies_disabled 7 | Disallow: /reset_password 8 | Disallow: /confirm 9 | Disallow: /complete_transition 10 | Disallow: /auth 11 | Disallow: /unsupported_dialog_without_watch 12 | Disallow: /relay 13 | Disallow: /provision 14 | Disallow: /build 15 | Disallow: /production 16 | 17 | -------------------------------------------------------------------------------- /resources/static/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "passfail": false, 3 | "maxerr": 100, 4 | "browser": true, 5 | "forin": false, 6 | "boss": true, 7 | "noarg": true, 8 | "undef": true, 9 | "laxbreak": true, 10 | "laxcomma": true, 11 | "eqeqeq": true, 12 | "eqnull": true, 13 | "expr": true, 14 | "jquery": true, 15 | "white": false, 16 | "predef": [ 17 | "BrowserID", 18 | "_", 19 | "$", 20 | "jQuery", 21 | "gettext", 22 | "format", 23 | "Channel", 24 | "WinChan", 25 | "Hub", 26 | "URLParse" 27 | ], 28 | "shadow": false, 29 | "supernew": false 30 | } 31 | -------------------------------------------------------------------------------- /resources/static/500/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 23 | 24 | 25 |
BrowserID is down for maintenence. We'll be back in a minute or two. Probably less.
26 |

27 | 28 | 29 | -------------------------------------------------------------------------------- /resources/static/500/error_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/500/error_bg.png -------------------------------------------------------------------------------- /resources/static/500/error_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/500/error_icon.png -------------------------------------------------------------------------------- /resources/static/common/css/ie8.css: -------------------------------------------------------------------------------- 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 | * These fixes are specific to IE8 that are common to the main site and dialog. 7 | */ 8 | 9 | .submit button, 10 | .submit button:hover, 11 | .submit button:focus, 12 | .submit .button:hover, 13 | .submit .button:focus { 14 | background-image: url("/common/i/button-arrow.png"); 15 | background-position: center right; 16 | background-repeat: no-repeat; 17 | } 18 | 19 | button[disabled], .submit_disabled button, .submit_disabled .button, 20 | .submit_disabled button:focus, .submit_disabled .button:focus, 21 | .submit_disabled button:active, .submit_disabled .button:active { 22 | color: #d8dde0; 23 | cursor: default; 24 | background-color: #bcc4ca; 25 | background-image: none; /* Fix for IE8/IE9 still showing the blue arrow */ 26 | } 27 | -------------------------------------------------------------------------------- /resources/static/common/i/button-arrow-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/common/i/button-arrow-active.png -------------------------------------------------------------------------------- /resources/static/common/i/button-arrow-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/common/i/button-arrow-hover.png -------------------------------------------------------------------------------- /resources/static/common/i/button-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/common/i/button-arrow.png -------------------------------------------------------------------------------- /resources/static/common/i/button-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/common/i/button-loader.gif -------------------------------------------------------------------------------- /resources/static/common/i/closex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/common/i/closex.png -------------------------------------------------------------------------------- /resources/static/common/i/grain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/common/i/grain.png -------------------------------------------------------------------------------- /resources/static/common/js/browserid.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() { 6 | "use strict"; 7 | 8 | window.BrowserID = window.BrowserID || {}; 9 | 10 | var bid = window.BrowserID, constants = { 11 | // always use 1024/160 DSA keys - see issue #1293 12 | // this used to be called keysize 128, but that made 13 | // no sense since no component of this is 128 bits 14 | // so making this 160 as per DSA 1024/160 15 | // EXCEPT, for backwards compatibility this is still 128 for now 16 | KEY_LENGTH: 128, 17 | 18 | PASSWORD_MIN_LENGTH: 8, 19 | PASSWORD_MAX_LENGTH: 80, 20 | 21 | // IE8 has a max total URL length of 2083 and a max path length of 2048. 22 | // http://support.microsoft.com/kb/q208427 23 | // See issue #2080 - https://github.com/mozilla/browserid/issues/2080 24 | URL_MAX_LENGTH: 2083, 25 | PATH_MAX_LENGTH: 2048, 26 | 27 | // XHR requests are considered delayed after 10 seconds. 28 | XHR_DELAY_MS: 10 * 1000, 29 | 30 | // limit siteLogo's to 128kb. The backend does not accept data-URI 31 | // siteLogos, so this is only used for the front end. 32 | MAX_SITE_LOGO_SIZE: 128 * 1024 33 | }; 34 | 35 | for (var key in constants) { 36 | bid[key] = constants[key]; 37 | } 38 | }()); 39 | -------------------------------------------------------------------------------- /resources/static/common/js/class.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 | BrowserID.Class = (function() { 7 | function create(Constr, config) { 8 | var inst = new Constr(); 9 | inst.init(config); 10 | return inst; 11 | } 12 | 13 | function extend(sup, extension) { 14 | // No superclass 15 | if(!extension) { 16 | extension = sup; 17 | sup = null; 18 | } 19 | 20 | var subclass = extension.hasOwnProperty("constructor") ? extension.constructor : function() {}; 21 | 22 | if(sup) { 23 | // there is a superclass, set it up. 24 | // Object.create would work well here. 25 | var F = function() {}; 26 | F.prototype = sup.prototype; 27 | subclass.prototype = new F(); 28 | subclass.sc = sup.prototype; 29 | } 30 | else { 31 | // no superclass, create a prototype object. 32 | subclass.prototype = {}; 33 | } 34 | 35 | for(var key in extension) { 36 | subclass.prototype[key] = extension[key]; 37 | } 38 | subclass.prototype.constructor = subclass; 39 | 40 | /** 41 | * Extend a class to create a subclass. 42 | * @method extend 43 | * @param {object} extensions - prototype extensions 44 | * @returns {function} subclass 45 | */ 46 | subclass.extend = extend.bind(null, subclass); 47 | /** 48 | * Create an instance of a class 49 | * @method create 50 | * @param {object} [config] - configuration, passed on to init. 51 | */ 52 | subclass.create = create.bind(null, subclass); 53 | 54 | return subclass; 55 | } 56 | 57 | return extend; 58 | 59 | }()); 60 | 61 | -------------------------------------------------------------------------------- /resources/static/common/js/command.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 | BrowserID.Command = (function() { 5 | "use strict"; 6 | 7 | var bid = BrowserID; 8 | 9 | var Command = bid.Class({ 10 | init: function(options) { 11 | this.run_options = options.run_options || {}; 12 | if(!options.callback) { 13 | throw new Error("callback required"); 14 | } 15 | this.callback = options.callback; 16 | }, 17 | 18 | run: function() { 19 | this.callback(this.run_options); 20 | }, 21 | 22 | extendRunOptions: function(options) { 23 | _.extend(this.run_options, options); 24 | } 25 | }); 26 | 27 | return Command; 28 | }()); 29 | 30 | -------------------------------------------------------------------------------- /resources/static/common/js/dom-helpers.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 | BrowserID.DOMHelpers = (function() { 5 | "use strict"; 6 | 7 | function makeEqualWidth(selector) { 8 | var els = $(selector), 9 | maxWidth = 0; 10 | 11 | // Find the widest el then set the width of all the els to be the 12 | // same. To do so, first let the els be their natural width, find the 13 | // widest, and then go from there. 14 | els.css({ 15 | "min-width": "0px", 16 | "width": "" 17 | }); 18 | 19 | els.each(function(index, element) { 20 | var width = $(element).outerWidth(); 21 | if (width > maxWidth) maxWidth = width; 22 | }); 23 | 24 | els.css("width", maxWidth + "px"); 25 | } 26 | 27 | return { 28 | makeEqualWidth: makeEqualWidth 29 | }; 30 | 31 | }()); 32 | -------------------------------------------------------------------------------- /resources/static/common/js/enable_cookies_url.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 | BrowserID.EnableCookiesURL = (function(){ 5 | "use strict"; 6 | 7 | var bid = BrowserID, 8 | bs = bid.BrowserSupport; 9 | 10 | function getURL() { 11 | return bs.isIOS() ? 12 | "https://support.mozilla.org/kb/how-enable-cookies-iphone" : 13 | "http://support.mozilla.org/kb/Websites%20say%20cookies%20are%20blocked"; 14 | } 15 | 16 | return { 17 | getURL: getURL 18 | }; 19 | }()); 20 | -------------------------------------------------------------------------------- /resources/static/common/js/gettext.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() { 6 | "use strict"; 7 | 8 | var bid = BrowserID, 9 | dom = bid.DOM; 10 | 11 | function Gettext() { 12 | return { 13 | gettext: function (msgid) { 14 | if (window.Gobbledygook && 15 | dom.getAttr('html', 'lang') === 'db-LB') { 16 | return window.Gobbledygook(msgid); 17 | } 18 | /*globals json_locale_data:true*/ 19 | if (window.json_locale_data && json_locale_data.client) { 20 | var dict = json_locale_data.client; 21 | if (dict[msgid] && dict[msgid].length >= 2 && 22 | dict[msgid][1].trim() !== "") { 23 | return dict[msgid][1]; 24 | } 25 | } 26 | return msgid; 27 | }, 28 | // See lib/i18n.js format docs 29 | format: function (fmt, obj, named) { 30 | if (!fmt) return ""; 31 | if (!fmt.replace) { 32 | return fmt; 33 | } 34 | if (_.isArray(obj) || named === false) { 35 | return fmt.replace(/%s/g, function(match){return String(obj.shift());}); 36 | } else if (_.isObject(obj) || named === true) { 37 | return fmt.replace(/%\(\s*([^)]+)\s*\)s/g, function(m, v){ 38 | return String(obj[v]); 39 | }); 40 | } 41 | } 42 | }; 43 | } 44 | 45 | var gt = new Gettext(); 46 | window.gettext = gt.gettext.bind(gt); 47 | window.format = gt.format.bind(gt); 48 | }()); 49 | -------------------------------------------------------------------------------- /resources/static/common/js/history.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 | BrowserID.History = (function() { 5 | "use strict"; 6 | 7 | var bid = BrowserID, 8 | Command = bid.Command; 9 | 10 | var History = bid.Class({ 11 | init: function() { 12 | this.history = []; 13 | }, 14 | 15 | destroy: function() { 16 | this.history = null; 17 | }, 18 | 19 | createState: function(callback, options) { 20 | this.current = Command.create({ 21 | callback: callback, 22 | run_options: options 23 | }); 24 | return this.current; 25 | }, 26 | 27 | getCurrent: function() { 28 | return this.current; 29 | }, 30 | 31 | // XXX this should be renamed to pushState 32 | saveState: function() { 33 | this.history.push(this.current); 34 | }, 35 | 36 | getTop: function() { 37 | return this.history[this.history.length - 1]; 38 | }, 39 | 40 | popState: function() { 41 | this.current = this.history.pop(); 42 | return this.current; 43 | } 44 | }); 45 | 46 | return History; 47 | }()); 48 | -------------------------------------------------------------------------------- /resources/static/common/js/mediator.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 | BrowserID.Mediator = (function() { 6 | var hub = Hub; 7 | 8 | return { 9 | subscribeAll: hub.all.bind(hub), 10 | subscribe: hub.on.bind(hub), 11 | unsubscribe: hub.off.bind(hub), 12 | publish: hub.fire.bind(hub), 13 | reset: hub.reset.bind(hub) 14 | }; 15 | }()); 16 | -------------------------------------------------------------------------------- /resources/static/common/js/models/models.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 | BrowserID.Models = {}; 6 | 7 | -------------------------------------------------------------------------------- /resources/static/common/js/models/user-context.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 | BrowserID.Models.UserContext = (function() { 6 | "use strict"; 7 | /** 8 | * This model represents User Context. It contains basic info 9 | * about the user. 10 | */ 11 | 12 | var bid = BrowserID, 13 | und, 14 | sc; 15 | 16 | var Module = bid.Modules.Module.extend({ 17 | // user context - perhaps this should be somewhere else, like a user model? 18 | userid: und, 19 | auth_level: und, 20 | has_password: und, 21 | 22 | init: function(options) { 23 | var self = this; 24 | 25 | self.setContext(options); 26 | 27 | sc.init.call(self, options); 28 | }, 29 | 30 | setContext: function(context) { 31 | this.importFrom(context, 32 | 'userid', 33 | 'auth_level', 34 | 'has_password' 35 | ); 36 | }, 37 | 38 | getUserId: function() { 39 | return this.userid; 40 | }, 41 | 42 | setUserId: function(userId) { 43 | this.userid = userId; 44 | }, 45 | 46 | setAuthLevel: function(authLevel) { 47 | this.auth_level = authLevel; 48 | }, 49 | 50 | getAuthLevel: function() { 51 | return this.auth_level || false; 52 | }, 53 | 54 | isUserAuthenticated: function() { 55 | return !!this.auth_level; 56 | }, 57 | 58 | hasPassword: function() { 59 | return !!this.has_password; 60 | } 61 | }); 62 | 63 | sc = Module.sc; 64 | 65 | return Module; 66 | }()); 67 | 68 | -------------------------------------------------------------------------------- /resources/static/common/js/modules/cookie_check.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 | BrowserID.Modules.CookieCheck = (function() { 7 | "use strict"; 8 | 9 | var bid = BrowserID, 10 | complete = bid.Helpers.complete, 11 | network = bid.Network, 12 | errors = bid.Errors, 13 | sc; 14 | 15 | var Module = bid.Modules.PageModule.extend({ 16 | start: function(data) { 17 | var self=this; 18 | 19 | network.cookiesEnabled(function(status) { 20 | if(!status) { 21 | self.renderError("generic", errors.cookiesDisabled); 22 | } 23 | complete(data.ready, status); 24 | }, self.getErrorDialog(errors.cookiesEnabled, data.ready)); 25 | 26 | sc.start.call(self, data); 27 | } 28 | }); 29 | 30 | sc = Module.sc; 31 | 32 | return Module; 33 | 34 | }()); 35 | 36 | -------------------------------------------------------------------------------- /resources/static/common/js/modules/extended-info.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 | BrowserID.Modules.ExtendedInfo = (function() { 6 | "use strict"; 7 | 8 | var bid = BrowserID, 9 | dom = bid.DOM, 10 | complete = bid.Helpers.complete; 11 | 12 | 13 | var Module = bid.Modules.PageModule.extend({ 14 | start: function(config) { 15 | var self=this; 16 | 17 | self.checkRequired(config, "target"); 18 | self.target = config.target; 19 | 20 | var openerEl = self.openerEl = $(".openMoreInfo", self.target); 21 | self.click(openerEl, self.open); 22 | 23 | Module.sc.start.call(self, config); 24 | }, 25 | 26 | open: function(oncomplete) { 27 | var self = this, 28 | extendedInfoEl = $(".moreInfo", self.target); 29 | 30 | /** 31 | * XXX What a big steaming pile, use CSS animations for this! 32 | */ 33 | $(extendedInfoEl).slideDown(function() { 34 | // The expanded info may be partially obscured on mobile devices in 35 | // landscape mode. Force the screen size hacks to account for the new 36 | // expanded size. 37 | dom.fireEvent(window, "resize"); 38 | complete(oncomplete); 39 | }); 40 | $(self.openerEl).css({visibility: "hidden"}); 41 | } 42 | }); 43 | 44 | return Module; 45 | }()); 46 | 47 | -------------------------------------------------------------------------------- /resources/static/common/js/modules/xhr_delay.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 | BrowserID.Modules.XHRDelay = (function() { 5 | "use strict"; 6 | 7 | var bid = BrowserID, 8 | wait = bid.Wait, 9 | delayed, 10 | sc; 11 | 12 | function delayStart(event, request) { 13 | /*jshint validthis:true*/ 14 | delayed = true; 15 | 16 | var networkInfo; 17 | if (request) { 18 | networkInfo = request.network; 19 | } 20 | 21 | var info = { 22 | id: wait.slowXHR.id, 23 | message: wait.slowXHR.message, 24 | title: wait.slowXHR.title, 25 | network: networkInfo 26 | }; 27 | 28 | this.renderDelay("load", info); 29 | } 30 | 31 | function delayStop() { 32 | /*jshint validthis:true*/ 33 | if(delayed) { 34 | delayed = false; 35 | this.hideDelay(); 36 | } 37 | } 38 | 39 | var Module = bid.Modules.PageModule.extend({ 40 | start: function(options) { 41 | var self=this; 42 | 43 | self.subscribe("xhr_delay", delayStart); 44 | self.subscribe("xhr_complete", delayStop); 45 | 46 | sc.start.call(self, options); 47 | }, 48 | 49 | stop: function() { 50 | this.hideDelay(); 51 | sc.stop.call(this); 52 | } 53 | }); 54 | 55 | sc = Module.sc; 56 | 57 | return Module; 58 | 59 | }()); 60 | 61 | -------------------------------------------------------------------------------- /resources/static/common/js/renderer.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 | BrowserID.Renderer = (function() { 5 | "use strict"; 6 | 7 | var bid = BrowserID, 8 | dom = bid.DOM; 9 | 10 | function getTemplateHTML(templateName, vars) { 11 | var templateFn = bid.Templates[templateName]; 12 | if (!templateFn) throw new Error("Template not found: " + templateName); 13 | 14 | var localVars = _.extend({}, vars); 15 | if(!localVars.partial) { 16 | localVars.partial = function(name) { 17 | // partials are not supported by the client side EJS. Create 18 | // a standin that does what partial rendering would do on the backend. 19 | return getTemplateHTML(name, vars); 20 | }; 21 | } 22 | 23 | // arguments are: locals, filters (which cant be used client-side), escapeFn 24 | return templateFn.call(null, localVars); 25 | } 26 | 27 | function render(target, templateName, vars) { 28 | var html = getTemplateHTML(templateName, vars); 29 | return dom.setInner(target, html); 30 | } 31 | 32 | function append(target, templateName, vars) { 33 | var html = getTemplateHTML(templateName, vars); 34 | return dom.appendTo(html, target); 35 | } 36 | 37 | return { 38 | render: render, 39 | append: append 40 | }; 41 | }()); 42 | -------------------------------------------------------------------------------- /resources/static/common/js/templates.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 | BrowserID.Templates = {}; 6 | 7 | -------------------------------------------------------------------------------- /resources/static/common/js/wait-messages.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 | BrowserID.Wait = (function(){ 5 | "use strict"; 6 | 7 | var Wait = { 8 | authentication: { 9 | title: gettext("Finishing Sign In..."), 10 | message: gettext("In just a moment you'll be signed into Persona.") 11 | }, 12 | 13 | slowXHR: { 14 | title: gettext("We are sorry, this is taking longer than it should."), 15 | message: gettext("If this doesn't resolve itself within a few seconds, please close the window and try again."), 16 | id: "slowXHR" 17 | } 18 | 19 | }; 20 | 21 | 22 | return Wait; 23 | }()); 24 | 25 | 26 | -------------------------------------------------------------------------------- /resources/static/common/js/xhr_transport.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 | BrowserID.XHRTransport = window.Micrajax; 5 | -------------------------------------------------------------------------------- /resources/static/dialog/css/ie8.css: -------------------------------------------------------------------------------- 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 | * These fixes are specific to IE8. 7 | */ 8 | 9 | -------------------------------------------------------------------------------- /resources/static/dialog/i/arrow_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/dialog/i/arrow_grey.png -------------------------------------------------------------------------------- /resources/static/dialog/i/firefox_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/dialog/i/firefox_logo.png -------------------------------------------------------------------------------- /resources/static/dialog/i/persona-logo-transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/dialog/i/persona-logo-transparent.png -------------------------------------------------------------------------------- /resources/static/dialog/i/persona_watermark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/dialog/i/persona_watermark.png -------------------------------------------------------------------------------- /resources/static/dialog/i/persona_watermark_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/dialog/i/persona_watermark_dark.png -------------------------------------------------------------------------------- /resources/static/dialog/i/persona_watermark_dark_sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/dialog/i/persona_watermark_dark_sm.png -------------------------------------------------------------------------------- /resources/static/dialog/i/persona_watermark_footer_sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/dialog/i/persona_watermark_footer_sm.png -------------------------------------------------------------------------------- /resources/static/dialog/i/persona_watermark_sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/dialog/i/persona_watermark_sm.png -------------------------------------------------------------------------------- /resources/static/dialog/js/modules/primary_offline.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 | BrowserID.Modules.PrimaryOffline = (function() { 5 | "use strict"; 6 | 7 | var bid = BrowserID, 8 | helpers = bid.Helpers, 9 | user = bid.User; 10 | 11 | function startDialogOver() { 12 | /*jshint validthis:true*/ 13 | // Reset the caches so that a user who cancels from this screen can go back 14 | // and try the same address again in a few minutes. 15 | user.resetCaches(); 16 | this.close("cancel_state"); 17 | } 18 | 19 | var Module = bid.Modules.PageModule.extend({ 20 | start: function(options) { 21 | options = options || {}; 22 | var self = this; 23 | 24 | self.checkRequired(options, "email"); 25 | 26 | options.idpName = helpers.getDomainFromEmail(options.email); 27 | self.renderError("primary_offline", options); 28 | self.click("#primary_offline_confirm", startDialogOver); 29 | Module.sc.start.call(self, options); 30 | }, 31 | 32 | // BEGIN TESTING API 33 | cancel: startDialogOver 34 | // END TESTING API 35 | }); 36 | 37 | return Module; 38 | }()); 39 | -------------------------------------------------------------------------------- /resources/static/dialog/js/modules/primary_user_not_provisioned.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 | BrowserID.Modules.PrimaryUserNotProvisioned = (function() { 5 | "use strict"; 6 | 7 | var bid = BrowserID, 8 | complete = bid.Helpers.complete; 9 | 10 | var Module = bid.Modules.PageModule.extend({ 11 | start: function(options) { 12 | options = options || {}; 13 | 14 | var self=this; 15 | Module.sc.start.call(self, options); 16 | 17 | self.checkRequired(options, "idpName", "email"); 18 | 19 | self.renderError("primary_user_not_verified", { 20 | email: options.email, 21 | // idpHost first, because it could be a delegated domain. 22 | // example: mozilla.com delegates to login.mozilla.org. The 23 | // message shoulnd't say "mozilla.com". 24 | idpName: options.idpHost || options.idpName, 25 | // This is for the KPIs, not the error screen. 26 | action: { 27 | title: "Could not verify with primary" 28 | } 29 | }); 30 | 31 | complete(options.ready); 32 | } 33 | }); 34 | 35 | return Module; 36 | 37 | }()); 38 | -------------------------------------------------------------------------------- /resources/static/dialog/views/cannot_verify_required_email.ejs: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 |

<%= format(gettext('Cannot verify %s'), [email]) %>

7 | 8 |

9 | <%= format(gettext('%s is a required address, but we cannot verify that you own this address.'), [email]) %> 10 |

11 | 12 | 13 | -------------------------------------------------------------------------------- /resources/static/dialog/views/complete_sign_in.ejs: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 | <% if (email) { %> 7 | <%- format(gettext("%(email)s verified!"), { 8 | email: "" + escape(email) + "" 9 | }) %> 10 | <% } %> 11 | 12 |

13 | <%= gettext("Signing you in…") %> 14 |

15 |
16 | -------------------------------------------------------------------------------- /resources/static/dialog/views/confirm_email.ejs: -------------------------------------------------------------------------------- 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 |

<%= gettext('Check your email') %>

6 | 7 |

8 | <%- format(gettext('Click the link in the confirmation email sent to %s to immediately be signed in to %s.'), ["" + escape(email) + "" , "" + siteName + ""]) %> 9 |

10 | 11 | -------------------------------------------------------------------------------- /resources/static/dialog/views/development.ejs: -------------------------------------------------------------------------------- 1 | 15 | 16 | -------------------------------------------------------------------------------- /resources/static/dialog/views/generic.ejs: -------------------------------------------------------------------------------- 1 | 4 | 5 |

id="<%= id %>"<% } %>><%= title %>

6 | 7 | <% if (typeof message !== "undefined") { %> 8 |

<%= message %>

9 | <% } else if (typeof noescape_message !== "undefined") { %> 10 |

<%- noescape_message %>

11 | <% } %> 12 | 13 | -------------------------------------------------------------------------------- /resources/static/dialog/views/inline_tospp.ejs: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 26 | 27 | -------------------------------------------------------------------------------- /resources/static/dialog/views/invalid_required_email.ejs: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 |

<%= format(gettext('*%s* is not a valid email address!'), [email]) %>

7 | 8 |

9 | <%= gettext('To continue, please close the window and enter a valid address.') %> 10 |

11 | 12 | 13 | -------------------------------------------------------------------------------- /resources/static/dialog/views/is_this_your_computer.ejs: -------------------------------------------------------------------------------- 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 |

<%= gettext('Remember You?') %>

7 |

<%= gettext('How long would you like to remain signed in with Persona?') %>

8 |
    9 |
  • 10 | 11 | <%= gettext('I trust this computer.') %> 12 |
  • 13 | 14 |
  • 15 | 16 | <%= gettext('This is not my computer.') %> 17 |
  • 18 |
19 |

<%= gettext('Note: You can of course sign out of Persona at any time.') %>

20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /resources/static/dialog/views/load.ejs: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 | 7 |

id="<%= id %>"<% } %>><%= title %>

8 | 9 | <% if (typeof message !== "undefined") { %> 10 |

<%= message %>

11 | 12 | <% if(typeof network !== "undefined") { %> 13 | 14 | <%= gettext("See more info") %> 15 | 16 | 17 | 30 | <% } %> 31 | 32 | <% } %> 33 | -------------------------------------------------------------------------------- /resources/static/dialog/views/primary_offline.ejs: -------------------------------------------------------------------------------- 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 |

7 | <%= format(gettext('%(primary)s is not responding. Please wait a few minutes and try again.'), { primary: idpName }) %> 8 |

9 | 10 |
11 | -------------------------------------------------------------------------------- /resources/static/dialog/views/primary_user_not_verified.ejs: -------------------------------------------------------------------------------- 1 | 4 | 5 |

6 | <%= 7 | format(gettext("Cannot verify %(email)s"), { 8 | email: email 9 | }) 10 | %> 11 |

12 | 13 |

14 | <%= 15 | format(gettext("This may be due to your browser blocking third-party cookies. Please ensure your browser\'s privacy preferences are set to accept third-party cookies for %(idpName)s and try again."), { 16 | idpName: idpName 17 | }) 18 | %> 19 |

20 | 21 | -------------------------------------------------------------------------------- /resources/static/dialog/views/rp_info.ejs: -------------------------------------------------------------------------------- 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 | <% if(siteLogo) { %> 6 | 7 | <% } %> 8 | 9 | 10 |

<%- siteName %>

11 | 12 | <% if (hostname !== siteName) { %> 13 |

<%= hostname %>

14 | <% } %> 15 | 16 | <% if(privacyPolicy && termsOfService) { %> 17 |

18 | <%- format(gettext("By proceeding, you agree to %(site)s's Terms and Privacy Policy."), 19 | { 20 | terms: 'href="' + termsOfService + '" class="rp_tos" target="_blank" tabindex="10"', 21 | privacy: 'href="' + privacyPolicy + '" class="rp_pp" target="_blank" tabindex="10"', 22 | site: siteName || hostname 23 | }) 24 | %> 25 |

26 | <% } %> 27 | -------------------------------------------------------------------------------- /resources/static/dialog/views/rp_info_mobile.ejs: -------------------------------------------------------------------------------- 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 | <% if(privacyPolicy && termsOfService) { %> 6 | <%- format(gettext("You also agree to %(site)s's Terms and Privacy Policy."), 7 | { 8 | terms: 'href="' + termsOfService + '" class="rp_tos" target="_blank" tabindex="10"', 9 | privacy: 'href="' + privacyPolicy + '" class="rp_pp" target="_blank" tabindex="10"', 10 | site: siteName || hostname 11 | }) 12 | %> 13 | <% } %> 14 | -------------------------------------------------------------------------------- /resources/static/dialog/views/test_template_cachify.ejs: -------------------------------------------------------------------------------- 1 | 4 | 5 | <%- cachify('/dialog/css/style.css') %> 6 | 7 | -------------------------------------------------------------------------------- /resources/static/dialog/views/test_template_no_input.ejs: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /resources/static/dialog/views/test_template_with_input.ejs: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 | 7 |
8 | 9 | -------------------------------------------------------------------------------- /resources/static/dialog/views/test_template_with_partial.ejs: -------------------------------------------------------------------------------- 1 | 4 | 5 | <%- partial('test_template_no_input') %> 6 | 7 | -------------------------------------------------------------------------------- /resources/static/dialog/views/verify_primary_user.ejs: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 |

7 | <%= gettext("Good news!") %> 8 |

9 |

10 | <%- format(gettext("%(email)s no longer requires an extra password. Verify your account and you will immediately be signed in to %(aWebsite)s"), 11 | { email: "" + escape(email) + "" , 12 | aWebsite: "" + siteName + "" })%> 13 |

14 | 15 |

16 | 17 | 18 | <%= gettext("cancel") %> 19 |

20 | 21 | 22 |
23 | -------------------------------------------------------------------------------- /resources/static/dialog/views/wait.ejs: -------------------------------------------------------------------------------- 1 | 4 | 5 |

id="<%= id %>"<% } %>><%= title %>

6 | 7 | <% if (typeof message !== "undefined") { %> 8 |

<%= message %>

9 | <% } %> 10 | -------------------------------------------------------------------------------- /resources/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/favicon.ico -------------------------------------------------------------------------------- /resources/static/i/email_sign_in_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/i/email_sign_in_black.png -------------------------------------------------------------------------------- /resources/static/i/email_sign_in_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/i/email_sign_in_blue.png -------------------------------------------------------------------------------- /resources/static/i/email_sign_in_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/i/email_sign_in_red.png -------------------------------------------------------------------------------- /resources/static/i/persona_sign_in_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/i/persona_sign_in_black.png -------------------------------------------------------------------------------- /resources/static/i/persona_sign_in_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/i/persona_sign_in_blue.png -------------------------------------------------------------------------------- /resources/static/i/persona_sign_in_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/i/persona_sign_in_red.png -------------------------------------------------------------------------------- /resources/static/i/plain_sign_in_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/i/plain_sign_in_black.png -------------------------------------------------------------------------------- /resources/static/i/plain_sign_in_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/i/plain_sign_in_blue.png -------------------------------------------------------------------------------- /resources/static/i/plain_sign_in_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/i/plain_sign_in_red.png -------------------------------------------------------------------------------- /resources/static/i/sign_in_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/i/sign_in_blue.png -------------------------------------------------------------------------------- /resources/static/i/sign_in_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/i/sign_in_green.png -------------------------------------------------------------------------------- /resources/static/i/sign_in_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/i/sign_in_grey.png -------------------------------------------------------------------------------- /resources/static/i/sign_in_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/i/sign_in_orange.png -------------------------------------------------------------------------------- /resources/static/i/sign_in_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/i/sign_in_red.png -------------------------------------------------------------------------------- /resources/static/include_js/_header.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Uncompressed source can be found at https://login.persona.org/include.orig.js 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 | -------------------------------------------------------------------------------- /resources/static/pages/css/ie8.css: -------------------------------------------------------------------------------- 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 | * These fixes are specific to IE8 for the main site 7 | */ 8 | 9 | /** 10 | * IE8 can only handle one background image in a CSS declaration 11 | */ 12 | body { 13 | background: #6a7b86 url("/pages/i/marketplace-header.png") repeat-x center top; 14 | } 15 | 16 | 17 | /** 18 | * IE8 in the embedded context does not respect the IFRAME size and shows a 19 | * scroll bar unless the wrapper's width is set to auto 20 | */ 21 | .embedded #wrapper { 22 | background: #fff; 23 | width: auto; 24 | } 25 | 26 | /** 27 | * IE8 doesn't respect media queries that sets the padding to 20px. Duplicate 28 | * that logic here. 29 | */ 30 | .embedded #content { 31 | padding: 20px; 32 | } 33 | 34 | 35 | -------------------------------------------------------------------------------- /resources/static/pages/i/badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/pages/i/badge.png -------------------------------------------------------------------------------- /resources/static/pages/i/developers-link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/pages/i/developers-link.png -------------------------------------------------------------------------------- /resources/static/pages/i/flexible-graphic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/pages/i/flexible-graphic.png -------------------------------------------------------------------------------- /resources/static/pages/i/marketplace-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/pages/i/marketplace-header.png -------------------------------------------------------------------------------- /resources/static/pages/i/one-password-graphic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/pages/i/one-password-graphic.png -------------------------------------------------------------------------------- /resources/static/pages/i/persona-logo-100x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/pages/i/persona-logo-100x100.png -------------------------------------------------------------------------------- /resources/static/pages/i/persona-logo-wordmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/pages/i/persona-logo-wordmark.png -------------------------------------------------------------------------------- /resources/static/pages/i/slit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/resources/static/pages/i/slit.png -------------------------------------------------------------------------------- /resources/static/pages/js/about.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 | BrowserID.about = (function() { 6 | "use strict"; 7 | 8 | var bid = BrowserID; 9 | 10 | function resize() { 11 | // Get tallest blurb 12 | var tallestBlurb = 0; 13 | 14 | $('.half').each(function(index) { 15 | var $this = $(this); 16 | 17 | if (index === 0) { 18 | tallestBlurb = $this.height(); 19 | } else { 20 | 21 | if ($this.height() < tallestBlurb) { 22 | $this.css('min-height', tallestBlurb); 23 | } else { 24 | $('.half.first').css('min-height', $this.height()); 25 | } 26 | 27 | } 28 | }); 29 | } 30 | 31 | var Module = bid.Modules.PageModule.extend({ 32 | start: function(options) { 33 | var self=this; 34 | 35 | Module.sc.start.call(self, options); 36 | resize(); 37 | 38 | // The half heights can change every time there is a window resize. 39 | self.bind(window, "resize", resize); 40 | } 41 | }); 42 | 43 | return Module; 44 | }()); 45 | -------------------------------------------------------------------------------- /resources/static/pages/js/index.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() { 6 | "use strict"; 7 | 8 | BrowserID.index = function () { 9 | $('.tour a').hover(function() { 10 | $('#card').toggleClass('insert'); 11 | }); 12 | }; 13 | }()); 14 | -------------------------------------------------------------------------------- /resources/static/relay/relay.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 doPost(msg, origin) { 6 | window.parent.postMessage(msg, origin); 7 | } 8 | -------------------------------------------------------------------------------- /resources/static/test/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "passfail": false, 3 | "maxerr": 100, 4 | "browser": true, 5 | "node": true, 6 | "forin": false, 7 | "boss": true, 8 | "noarg": true, 9 | "undef": true, 10 | "laxbreak": true, 11 | "laxcomma": true, 12 | "eqeqeq": true, 13 | "eqnull": true, 14 | "expr": true, 15 | "jquery": true, 16 | "white": false, 17 | "predef": [ 18 | "BrowserID", 19 | "_", 20 | "$", 21 | "jQuery", 22 | "ok", 23 | "equal", 24 | "strictEqual", 25 | "notEqual", 26 | "deepEqual", 27 | "start", 28 | "stop", 29 | "asyncTest", 30 | "test", 31 | "raises", 32 | "module" 33 | ], 34 | "shadow": false, 35 | "supernew": false 36 | } 37 | -------------------------------------------------------------------------------- /resources/static/test/cases/common/js/command.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 | (function() { 5 | "use strict"; 6 | 7 | var bid = BrowserID, 8 | testHelpers = bid.TestHelpers, 9 | Command = bid.Command; 10 | 11 | module("common/js/command", { 12 | setup: function() { 13 | testHelpers.setup(); 14 | }, 15 | 16 | teardown: function() { 17 | testHelpers.teardown(); 18 | } 19 | }); 20 | 21 | asyncTest("run - run_options passed to callback", function() { 22 | var cmd = Command.create({ 23 | callback: function(options) { 24 | equal(options.item, "value", "correct options sent"); 25 | start(); 26 | }, 27 | run_options: { 28 | item: "value" 29 | } 30 | }); 31 | 32 | cmd.run(); 33 | }); 34 | 35 | asyncTest("extendRunOptions, run - run_options extended, passed to callback", function() { 36 | var cmd = Command.create({ 37 | callback: function(options) { 38 | equal(options.item, "value", "correct options sent"); 39 | start(); 40 | } 41 | }); 42 | 43 | cmd.extendRunOptions({ item: "value" }); 44 | cmd.run(); 45 | }); 46 | }()); 47 | -------------------------------------------------------------------------------- /resources/static/test/cases/common/js/crypto-loader.js: -------------------------------------------------------------------------------- 1 | /*jshint browser: true*/ 2 | /* This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 | (function() { 6 | "use strict"; 7 | 8 | var bid = BrowserID, 9 | testHelpers = bid.TestHelpers, 10 | cryptoLoader = bid.CryptoLoader; 11 | 12 | module("common/js/crypto-loader", { 13 | setup: function() { 14 | testHelpers.setup(); 15 | }, 16 | teardown: function() { 17 | testHelpers.teardown(); 18 | } 19 | }); 20 | 21 | asyncTest("load gets jwcrypto", function() { 22 | cryptoLoader.load(function(jwcrypto) { 23 | ok(jwcrypto); 24 | 25 | start(); 26 | }, testHelpers.unexpectedFailure); 27 | }); 28 | 29 | }()); 30 | 31 | -------------------------------------------------------------------------------- /resources/static/test/cases/common/js/dom-helpers.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 | (function() { 5 | "use strict"; 6 | 7 | var bid = BrowserID, 8 | testHelpers = bid.TestHelpers, 9 | domHelpers = bid.DOMHelpers; 10 | 11 | module("common/js/dom-helpers", { 12 | setup: testHelpers.setup, 13 | teardown: testHelpers.teardown 14 | }); 15 | 16 | test("makeEqualWidth", function() { 17 | bid.Renderer.render("#page_head", "is_this_your_computer", {}); 18 | 19 | // Ensure old width is removed before calculating the natural width of the 20 | // element. Check by setting the width of one of the elements manually and 21 | // then see if it is removed later. See issue #2066 22 | $("#your_computer_content button").eq(0).css({"width": "4000px"}); 23 | 24 | domHelpers.makeEqualWidth("#your_computer_content button"); 25 | 26 | var lastWidth; 27 | $("#your_computer_content button").each(function(index, element) { 28 | var currWidth = $(element).outerWidth(); 29 | 30 | // make sure the impossibly large width was removed. 31 | ok(parseInt(currWidth, 10) !== 4000); 32 | 33 | if (lastWidth) { 34 | equal(currWidth, lastWidth, "button widths are the same"); 35 | } 36 | lastWidth = currWidth; 37 | }); 38 | }); 39 | 40 | }()); 41 | -------------------------------------------------------------------------------- /resources/static/test/cases/common/js/enable_cookies_url.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 | (function() { 5 | "use strict"; 6 | 7 | var bid = BrowserID, 8 | testHelpers = bid.TestHelpers; 9 | 10 | module("/common/js/enable_cookies_url", { 11 | setup: function() { 12 | testHelpers.setup(); 13 | }, 14 | 15 | teardown: function() { 16 | testHelpers.teardown(); 17 | } 18 | }); 19 | 20 | test("returns a URL", function() { 21 | ok(bid.EnableCookiesURL.getURL(), "a URL is returned"); 22 | }); 23 | }()); 24 | 25 | -------------------------------------------------------------------------------- /resources/static/test/cases/common/js/modules/cookie_check.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 | (function() { 5 | "use strict"; 6 | 7 | var bid = BrowserID, 8 | network = bid.Network, 9 | testHelpers = bid.TestHelpers, 10 | controller; 11 | 12 | function createController(config) { 13 | controller = BrowserID.Modules.CookieCheck.create(); 14 | controller.start(config); 15 | } 16 | 17 | module("common/js/modules/cookie_check", { 18 | setup: function() { 19 | testHelpers.setup(); 20 | }, 21 | 22 | teardown: function() { 23 | testHelpers.teardown(); 24 | 25 | controller.destroy(); 26 | } 27 | }); 28 | 29 | asyncTest("create controller cookies disabled - ready returns with false status", function() { 30 | network.cookiesEnabledOverride = false; 31 | 32 | createController({ 33 | ready: function(status) { 34 | equal(status, false, "cookies are disabled, false status"); 35 | testHelpers.testErrorVisible(); 36 | // make sure the message is not escaped. If it is escaped, the anchor 37 | // will not be found. see issue #2979 38 | ok($("#enable_cookies").length); 39 | start(); 40 | } 41 | }); 42 | }); 43 | 44 | asyncTest("create controller with cookies enabled - ready returns with true status", function() { 45 | network.cookiesEnabledOverride = true; 46 | 47 | createController({ 48 | ready: function(status) { 49 | equal(status, true, "cookies are enabled, true status"); 50 | start(); 51 | } 52 | }); 53 | }); 54 | 55 | }()); 56 | 57 | -------------------------------------------------------------------------------- /resources/static/test/cases/common/js/modules/extended-info.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() { 6 | "use strict"; 7 | 8 | var bid = BrowserID, 9 | ExtendedInfo = bid.Modules.ExtendedInfo; 10 | 11 | module("common/js/modules/extended-info", { 12 | setup: function() { 13 | $("#error").html("
Open
"); 14 | }, 15 | teardown: function() { 16 | $("#error").hide(); 17 | } 18 | }); 19 | 20 | asyncTest("can initialize and open the extended info", function openExtendedInfo() { 21 | $("#error").show(); 22 | var errorDisplay = ExtendedInfo.create(); 23 | errorDisplay.start({ target: "#error" }); 24 | errorDisplay.open(function() { 25 | ok($("#error .moreInfo").is(":visible"), "expanded info is visible"); 26 | start(); 27 | }); 28 | }); 29 | 30 | 31 | }()); 32 | -------------------------------------------------------------------------------- /resources/static/test/cases/common/js/renderer.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 | (function() { 5 | "use strict"; 6 | 7 | var bid = BrowserID, 8 | renderer = bid.Renderer, 9 | testHelpers = bid.TestHelpers; 10 | 11 | module("common/js/renderer", { 12 | setup: function() { 13 | testHelpers.setup(); 14 | }, 15 | 16 | teardown: function() { 17 | testHelpers.teardown(); 18 | } 19 | }); 20 | 21 | test("render template from memory", function() { 22 | renderer.render("#formWrap .contents", "inMemoryTemplate"); 23 | 24 | ok($("#templateInput").length, "template written when loaded from memory"); 25 | }); 26 | 27 | test("append template to element", function() { 28 | renderer.append("#formWrap", "inMemoryTemplate"); 29 | 30 | ok($("#formWrap > #templateInput").length && $("#formWrap > .contents"), "template appended to element instead of overwriting it"); 31 | 32 | }); 33 | 34 | test("render template with partial", function() { 35 | equal($("#focusButton").length, 0, "template not yet loaded"); 36 | 37 | renderer.render("#formWrap .contents", "test_template_with_partial"); 38 | 39 | ok($("#focusButton").length, "template loaded with partial"); 40 | }); 41 | 42 | test("render dialog template with cachify", function() { 43 | renderer.render("#formWrap .contents", "test_template_cachify"); 44 | 45 | var expected = /\/dialog\/css\/style\.css$/; 46 | var value = $("#formWrap .contents").text().trim(); 47 | ok(value.match(expected), "cachify has been pre-processed"); 48 | }); 49 | 50 | }()); 51 | 52 | 53 | -------------------------------------------------------------------------------- /resources/static/test/cases/dialog/js/modules/complete_sign_in.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 | (function() { 5 | "use strict"; 6 | 7 | var bid = BrowserID, 8 | controller, 9 | testHelpers = bid.TestHelpers; 10 | 11 | function createController(config) { 12 | controller = BrowserID.Modules.CompleteSignIn.create(); 13 | controller.start(config); 14 | } 15 | 16 | module("dialog/js/modules/complete_sign_in", { 17 | setup: testHelpers.setup, 18 | teardown: function() { 19 | if (controller) { 20 | controller.destroy(); 21 | controller = null; 22 | } 23 | testHelpers.teardown(); 24 | } 25 | }); 26 | 27 | 28 | asyncTest("start - shows the complete_sign_in template", function() { 29 | createController({ 30 | email: "testuser@testuser.com", 31 | ready: function() { 32 | testHelpers.testElementExists("#complete_sign_in"); 33 | start(); 34 | } 35 | }); 36 | }); 37 | 38 | }()); 39 | 40 | -------------------------------------------------------------------------------- /resources/static/test/cases/other/mocks/xhr.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() { 6 | "use strict"; 7 | 8 | var bid = BrowserID, 9 | xhr = bid.Mocks.xhr, 10 | testHelpers = bid.TestHelpers; 11 | 12 | module("other/mocks/xhr", { 13 | setup: function() { 14 | testHelpers.setup(); 15 | }, 16 | 17 | teardown: function() { 18 | testHelpers.teardown(); 19 | } 20 | }); 21 | 22 | asyncTest("get with missing xhr request in xhr.js mock - should print out error on the console", function() { 23 | var origConsoleError = console.error, 24 | displayedError; 25 | 26 | console.error = function(msg) { 27 | displayedError = msg; 28 | }; 29 | 30 | xhr.ajax({ 31 | type: "get", 32 | url: "missing_url", 33 | error: function() { 34 | ok(displayedError, "console.error was called for a missing url"); 35 | console.error = origConsoleError; 36 | start(); 37 | } 38 | }); 39 | }); 40 | }()); 41 | -------------------------------------------------------------------------------- /resources/static/test/cases/pages/js/about.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 | (function() { 5 | "use strict"; 6 | 7 | var bid = BrowserID, 8 | testHelpers = bid.TestHelpers, 9 | controller; 10 | 11 | module("pages/js/about", { 12 | setup: function() { 13 | testHelpers.setup(); 14 | bid.Renderer.render("#page_head", "site/about", {}); 15 | }, 16 | teardown: function() { 17 | testHelpers.teardown(); 18 | } 19 | }); 20 | 21 | function createController(options, callback) { 22 | controller = BrowserID.about.create(); 23 | controller.start(options); 24 | } 25 | 26 | test("start - no errors", function() { 27 | createController({}); 28 | ok(controller, "controller created"); 29 | }); 30 | 31 | }()); 32 | -------------------------------------------------------------------------------- /resources/static/test/cases/pages/js/browserid.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 | (function() { 5 | "use strict"; 6 | 7 | module("/pages/browserid"); 8 | 9 | 10 | }()); 11 | 12 | -------------------------------------------------------------------------------- /resources/static/test/mocks/mocks.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 | BrowserID.Mocks = {}; 5 | 6 | -------------------------------------------------------------------------------- /resources/static/test/mocks/templates.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 | BrowserID.Templates = { 6 | inMemoryTemplate: function (locals, filters, escape) { 7 | return '
' 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /resources/static/test/mocks/winchan.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 | BrowserID.Mocks.WinChan = (function() { 5 | "use strict"; 6 | 7 | function WinChan() { }; 8 | 9 | WinChan.prototype = { 10 | open: function(params, callback) { 11 | this.params = params; 12 | this.oncomplete = callback; 13 | callback && callback(null, "yar"); 14 | }, 15 | 16 | onOpen: function() { 17 | return { 18 | detach: function() {} 19 | }; 20 | } 21 | }; 22 | 23 | return WinChan; 24 | 25 | }()); 26 | -------------------------------------------------------------------------------- /resources/static/test/mocks/window.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 | BrowserID.Mocks.WindowMock = (function() { 5 | "use strict"; 6 | 7 | function DocumentMock() { 8 | this.location = { 9 | href: document.location.href, 10 | hash: document.location.hash 11 | }; 12 | } 13 | 14 | function WindowMock(options) { 15 | options = options || {}; 16 | 17 | this.document = new DocumentMock(); 18 | if (options.href) { 19 | this.document.location.href = options.href; 20 | } 21 | 22 | if (options.hash) { 23 | this.document.location.hash = options.hash; 24 | } 25 | 26 | this.sessionStorage = {}; 27 | 28 | this.suppressOpen = options.suppressOpen || false; 29 | } 30 | 31 | WindowMock.prototype = { 32 | open: function(url, name, options) { 33 | if (this.suppressOpen) return; 34 | 35 | this.open_url = url; 36 | 37 | return new WindowMock({ 38 | suppressOpen: this.suppressOpen, 39 | href: url 40 | }); 41 | } 42 | }; 43 | 44 | return WindowMock; 45 | 46 | }()); 47 | -------------------------------------------------------------------------------- /resources/views/communication_iframe.ejs: -------------------------------------------------------------------------------- 1 | 2 | <%- partial('partial/license_with_code_ver') %> 3 | 4 | non-interactive iframe 5 | 6 | 7 | <% if (production) { %> 8 | <%- cachify_prefetch(util.format('/production/%s/dialog.js', locale)) %> 9 | <%- cachify_prefetch(util.format('/production/%s/dialog.css', locale)) %> 10 | <%- cachify_prefetch('/common/i/grain.png') %> 11 | <%- cachify_prefetch('/dialog/i/persona-logo-transparent.png') %> 12 | <%- cachify_prefetch('/dialog/i/arrow_grey.png') %> 13 | <%- cachify_prefetch('/common/i/button-loader.gif') %> 14 | <%- cachify_prefetch('/common/i/button-arrow.png') %> 15 | <%- cachify_prefetch('/common/i/button-arrow-hover.png') %> 16 | <%- cachify_prefetch('/common/i/button-arrow-active.png') %> 17 | <%- cachify_prefetch('/dialog/i/persona_watermark.png') %> 18 | <%- cachify_prefetch('/dialog/i/persona_watermark_sm.png') %> 19 | <%- cachify_prefetch('/dialog/i/persona_watermark_dark_sm.png') %> 20 | <% } %> 21 | <%- cachify_js('/production/communication_iframe.js') %> 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /resources/views/cookies_disabled.ejs: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 |
7 |
8 |

9 | <%= gettext("Persona requires cookies to remember you.") %> 10 |

11 | 12 |

13 | <%- format(gettext("Please close this window, enable cookies and try again"), [" target='_blank' href='http://support.mozilla.org/kb/Websites%20say%20cookies%20are%20blocked'"]) %> 14 |

15 |
16 |
17 |
18 | -------------------------------------------------------------------------------- /resources/views/partial/license_with_code_ver.ejs: -------------------------------------------------------------------------------- 1 | 7 | 8 | -------------------------------------------------------------------------------- /resources/views/partial/noscript-warning.ejs: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /resources/views/relay.ejs: -------------------------------------------------------------------------------- 1 | 2 | <%- partial('partial/license_with_code_ver') %> 3 | 4 | 5 | 6 | 7 | Persona 8 | <%- cachify_js('/production/relay.js') %> 9 | 10 | 11 | -------------------------------------------------------------------------------- /resources/views/unsupported_dialog.ejs: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 |
7 |
8 |

9 | <%- gettext('We are sorry, but currently your browser is not supported.') %> 10 |

11 | 12 | 13 | 14 | <%- gettext('Firefox logo') %> 15 | 16 | 17 |

18 | <%- format(gettext('Persona works with Firefox'), { getFirefoxLink: 'href="http://getfirefox.com" target="_blank" title="Get Firefox"' }) %> 19 | 20 | <%- format(gettext('and other modern browsers.'), { otherBrowserLink: 'href="http://whatbrowser.org" target="_blank"' }) %> 21 | 22 |

23 | 24 |
25 |
26 | 27 |
28 | -------------------------------------------------------------------------------- /resources/views/unsupported_dialog_without_watch.ejs: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 |
7 |
8 |

9 | <%= gettext("Sorry, your browser does not support signing in to this website.") %> 10 |

11 | 12 |

13 | <%- format(gettext("The owner of this website needs to update to use Persona's navigator.id.watch() feature."), [" target='_blank' href='https://developer.mozilla.org/en-US/docs/Web/API/navigator.id.watch'"]) %> 14 |

15 |
16 |
17 |
18 | -------------------------------------------------------------------------------- /scripts/awsbox_local/scp.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 | var child_process = require('child_process'), 6 | util = require('util'); 7 | 8 | exports.scp = function(path, target, done) { 9 | var cmd = 'scp -o "StrictHostKeyChecking no" ' + path + ' ' + target; 10 | var scpProcess = child_process.exec(cmd, function(err, code) { 11 | var error = null; 12 | 13 | if (!code) { 14 | console.log(">> Successful copy of " + path + " to " + target); 15 | } 16 | else { 17 | error = new Error("Could not copy " + path + " to " + target); 18 | } 19 | 20 | done(error, code); 21 | }); 22 | 23 | scpProcess.stdout.on('data', function(data) { 24 | util.print(data.toString()); 25 | }); 26 | 27 | scpProcess.stderr.on('data', function(data) { 28 | util.error(data.toString()); 29 | }); 30 | }; 31 | -------------------------------------------------------------------------------- /scripts/awsbox_remote/post_create.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | sudo /sbin/chkconfig mysqld on 4 | sudo /sbin/service mysqld start 5 | echo "CREATE USER 'browserid'@'localhost';" | mysql -u root 6 | echo "CREATE DATABASE browserid;" | mysql -u root 7 | echo "GRANT ALL ON browserid.* TO 'browserid'@'localhost';" | mysql -u root 8 | -------------------------------------------------------------------------------- /scripts/awsbox_remote/post_deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ ! -f $HOME/var/root.cert ] ; then 4 | echo ">> generating keypair" 5 | node scripts/postinstall.js 6 | mv var/root.cert var/root.secretkey $HOME/var 7 | else 8 | echo ">> no keypair needed. you gots one" 9 | fi 10 | 11 | node scripts/l10n-update.js 12 | 13 | echo ">> generating ver.txt" 14 | cd ../git 15 | git log --pretty=%h -1 > ../code/resources/static/ver.txt 16 | cd ../code 17 | 18 | echo ">> generating production resources" 19 | scripts/compress 20 | -------------------------------------------------------------------------------- /scripts/awsbox_remote/post_start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # don't run automation tests at git push time 4 | # node automation-tests/scripts/post-update.js 5 | 6 | scripts/show_config.js 7 | -------------------------------------------------------------------------------- /scripts/branch_train.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This Source Code Form is subject to the terms of the Mozilla Public 3 | # License, v. 2.0. If a copy of the MPL was not distributed with this 4 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 5 | 6 | git branch train-$(date +'%Y.%m.%d') dev 7 | 8 | -------------------------------------------------------------------------------- /scripts/check_l10n_config.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 | var fs = require('fs'), 6 | i18n = require('i18n-abide'), 7 | path = require('path'), 8 | util = require('util'); 9 | 10 | if (! process.env['CONFIG_FILES']) { 11 | console.error("You must set CONFIG_FILES to point to the json file you want to check"); 12 | process.exit(1); 13 | } 14 | 15 | var config = require('../lib/configuration.js'), 16 | error = 0, 17 | logged = false; 18 | 19 | console.log("Checking ", config.get('supported_languages').length, "languages from ", process.env['CONFIG_FILES']); 20 | 21 | config.get('supported_languages').forEach(function (lang, i) { 22 | var locale = i18n.localeFrom(lang); 23 | if (i18n.languageFrom(locale) !== lang) { 24 | console.error("Hmmm language=", lang, "seems fishy! Converts to locale=", 25 | locale, " and back again into language=", i18n.languageFrom(locale)); 26 | error = 1; 27 | } 28 | path.exists(path.join(__dirname, '..', 'locale', locale, 'LC_MESSAGES', 'messages.po'), function (m_exists) { 29 | if (! m_exists) { 30 | console.error("Language ", lang, " doesn't exist. Expected", 31 | path.join(__dirname, '..', 'locale', locale, 'LC_MESSAGES', 'messages.po')); 32 | error = 1; 33 | } 34 | }); 35 | }); 36 | 37 | process.on('exit', function () { 38 | // This will run twice... 39 | if (! logged) { 40 | logged = true; 41 | if (error === 0) { 42 | console.log("OK"); 43 | } else { 44 | console.log("FAIL"); 45 | } 46 | } 47 | process.exit(error); 48 | }); -------------------------------------------------------------------------------- /scripts/check_po.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # syntax: 4 | # check-po.sh 5 | 6 | for lang in `find locale -type f -name "*.po"`; do 7 | dir=`dirname $lang` 8 | stem=`basename $lang .po` 9 | printf "${lang}: " 10 | msgfmt --statistics ${dir}/${stem}.po 11 | done 12 | rm messages.mo 13 | -------------------------------------------------------------------------------- /scripts/compile_mo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # syntax: 4 | # compile-mo.sh locale-dir/ 5 | 6 | function usage() { 7 | echo "syntax:" 8 | echo "compile_mo.sh locale-dir/" 9 | exit 1 10 | } 11 | 12 | # check if file and dir are there 13 | if [ $# -ne 1 ] || [ ! -d "$1" ]; then usage; fi 14 | 15 | for lang in `find $1 -type f -name "*.po"`; do 16 | dir=`dirname $lang` 17 | stem=`basename $lang .po` 18 | msgfmt -o ${dir}/${stem}.mo $lang 19 | done 20 | -------------------------------------------------------------------------------- /scripts/create_account.js: -------------------------------------------------------------------------------- 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 | const 8 | wcli = require("../lib/wsapi_client.js"); 9 | 10 | var argv = require('optimist') 11 | .usage('Stage a new account for creation, causing an email to be sent.\nUsage: $0') 12 | .alias('h', 'help') 13 | .describe('h', 'display this usage message') 14 | .alias('s', 'server') 15 | .describe('s', 'server url to stage on') 16 | .default('s', 'https://login.persona.org') 17 | .alias('d', 'domain') 18 | .describe('d', 'domain that email is staged on behalf of, will be in email body') 19 | .default('d', "create_account_command_line_tool.com") 20 | .alias('e', 'email') 21 | .describe('e', 'email address to stage') 22 | .demand('e'); 23 | 24 | var args = argv.argv; 25 | 26 | // request context (cookie jar, etc) 27 | var ctx = {}; 28 | 29 | if (args.h) { 30 | argv.showHelp(); 31 | process.exit(0); 32 | } 33 | 34 | wcli.post({ 35 | browserid: args.s 36 | }, '/wsapi/stage_user', ctx, { 37 | email: args.e, 38 | site: args.d 39 | }, function(err, response) { 40 | function doError(e) { 41 | process.stderr.write("error: " + e.toString() + "\n"); 42 | process.stderr.write("response: " + response.body + "\n"); 43 | process.exit(1); 44 | } 45 | if (err) return doError(err); 46 | try { 47 | var body = JSON.parse(response.body); 48 | if (body.success !== true) { 49 | throw "request failed: " + response.body; 50 | } 51 | } catch(e) { 52 | return doError(e); 53 | } 54 | }); 55 | -------------------------------------------------------------------------------- /scripts/create_templates.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 | 6 | 7 | const 8 | fs = require("fs"), 9 | path = require('path'), 10 | templates = require('../lib/templates'), 11 | cachify = require('connect-cachify'), 12 | config = require('../lib/configuration'); 13 | 14 | cachify.setup({}, { 15 | prefix: config.get('cachify_prefix'), 16 | root: path.join(__dirname, '../resources/static') 17 | }); 18 | 19 | var existsSync = fs.existsSync || path.existsSync; 20 | var dir = process.env.TEMPLATE_DIR || process.cwd(); 21 | var output_dir = process.env.BUILD_DIR || dir; 22 | var outputFile = path.join(output_dir, "templates.js"); 23 | 24 | function generateTemplates() { 25 | var lastGen = existsSync(outputFile) ? fs.statSync(outputFile).mtime : 0; 26 | var templateData = templates.generate(dir, null, lastGen); 27 | if (templateData) { 28 | // no data most likely means we're already up-to-date 29 | fs.writeFileSync(path.join(output_dir, "templates.js"), templateData, "utf8"); 30 | } 31 | }; 32 | 33 | // run or export the function 34 | if (process.argv[1] === __filename) generateTemplates(); 35 | else module.exports = generateTemplates; 36 | -------------------------------------------------------------------------------- /scripts/every_locale.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 | var fs = require('fs'), 6 | i18n = require('i18n-abide'), 7 | path = require('path'), 8 | util = require('util'); 9 | 10 | var allLocales = [], 11 | localeDir = path.join(__dirname, '..', 'locale'); 12 | 13 | fs.readdir(localeDir, function (err, files) { 14 | files.forEach(function (file, i) { 15 | path.exists(path.join(localeDir, file, 'LC_MESSAGES', 'client.po'), function (c_exists) { 16 | if (c_exists) { 17 | path.exists(path.join(localeDir, file, 'LC_MESSAGES', 'messages.po'), function (m_exists) { 18 | if (m_exists) { 19 | allLocales.push(i18n.languageFrom(file)); 20 | } else { 21 | console.error(util.format('%s client.po exists, but not messages.po', file)); 22 | } 23 | }); 24 | } 25 | }); 26 | }); 27 | }); 28 | 29 | process.on('exit', function () { 30 | allLocales.sort(); 31 | console.log(JSON.stringify(allLocales).replace(/,"/g, ', "')); 32 | }); -------------------------------------------------------------------------------- /scripts/extract_po.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # syntax: 4 | # extract-po.sh 5 | 6 | # No -j on first line, to clear out .pot file (Issue#1170) 7 | 8 | # messages.po is server side strings 9 | xgettext --keyword=_ -L Perl --output-dir=locale/templates/LC_MESSAGES --from-code=utf-8 --output=messages.pot\ 10 | `find lib -name '*.js' | grep -v 'i18n.js' | grep -v jwcrypto` 11 | xgettext -j -L PHP --keyword=_ --output-dir=locale/templates/LC_MESSAGES --output=messages.pot `find resources/views -name '*.ejs'` 12 | xgettext -j -L PHP --keyword=_ --output-dir=locale/templates/LC_MESSAGES --output=messages.pot `find resources/email_templates -name '*.ejs'` 13 | 14 | # client.po 15 | # js 16 | xgettext -L Perl --output-dir=locale/templates/LC_MESSAGES --from-code=utf-8 --output=client.pot\ 17 | `find resources/static -name '*.js' | grep -v /lib/ | grep -v /build/ | grep -v /production/ | grep -v 'gettext.js'` 18 | xgettext -j -L Perl --output-dir=locale/templates/LC_MESSAGES --output=client.pot `find resources/static/dialog/ -name '*.js' | grep -v include.js` 19 | # ejs 20 | xgettext -j -L PHP --keyword=_ --output-dir=locale/templates/LC_MESSAGES --output=client.pot `find resources/static -name '*.ejs'` 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /scripts/hash_password.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 | 6 | 7 | const 8 | config = require('../lib/configuration'), 9 | bcrypt = require('bcrypt'); 10 | 11 | function bcryptPassword(password, cb) { 12 | var bcryptWorkFactor = config.get('bcrypt_work_factor'); 13 | 14 | bcrypt.gen_salt(bcryptWorkFactor, function (err, salt) { 15 | if (err) { 16 | var msg = "error generating salt with bcrypt: " + err; 17 | logger.error(msg); 18 | return cb(msg); 19 | } 20 | bcrypt.encrypt(password, salt, function(err, hash) { 21 | if (err) { 22 | var msg = "error generating password hash with bcrypt: " + err; 23 | logger.error(msg); 24 | return cb(msg); 25 | } 26 | return cb(undefined, hash); 27 | }); 28 | }); 29 | }; 30 | 31 | if (process.argv.length !== 3) { 32 | console.log('Usage:', process.argv[1], ''); 33 | process.exit(1); 34 | } 35 | 36 | bcryptPassword(process.argv[2], function(err, hash) { 37 | if (err) { 38 | process.sterr.write("error: " + err.toString() + "\n"); 39 | process.exit(1); 40 | } 41 | console.log(hash); 42 | }); 43 | -------------------------------------------------------------------------------- /scripts/merge_po.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # syntax: 4 | # compile-mo.sh locale-dir/ 5 | 6 | function usage() { 7 | echo "syntax:" 8 | echo "compile.sh locale-dir/" 9 | exit 1 10 | } 11 | 12 | # check if file and dir are there 13 | if [ $# -ne 1 ] || [ ! -d "$1" ]; then usage; fi 14 | 15 | for lang in `find $1 -type f -name "*.po" -not -path '*/db_LB/*'`; do 16 | dir=`dirname $lang` 17 | stem=`basename $lang .po` 18 | msgmerge -o ${dir}/${stem}.po.tmp ${dir}/${stem}.po $1/templates/LC_MESSAGES/${stem}.pot 19 | mv ${dir}/${stem}.po.tmp ${dir}/${stem}.po 20 | done 21 | 22 | # Optionally auto-localize our test locale db-LB 23 | if hash podebug >/dev/null; then 24 | 25 | # our debug locale has a tendency to be characterized as 'CHARSET' rather than 26 | # UTF-8, this hack works around the problem. 27 | # see issue #1054 28 | for file in locale/templates/LC_MESSAGES/*.pot ; do 29 | mv $file $file.old 30 | sed 's/CHARSET/UTF-8/g' $file.old > $file 31 | rm -f $file.old 32 | done 33 | 34 | for catalog in messages client; do 35 | 36 | echo "Translating ${catalog}.po" 37 | podebug --rewrite=flipped -i locale/templates/LC_MESSAGES/${catalog}.pot\ 38 | -o locale/db_LB/LC_MESSAGES/${catalog}.po 39 | done 40 | else 41 | echo 'Skipping db-LB, install translate-toolkit if you want to have that up-to-date.' 42 | fi 43 | -------------------------------------------------------------------------------- /scripts/postinstall.js: -------------------------------------------------------------------------------- 1 | "use strict"; 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 | // make symlinks 8 | var fs = require('fs'); 9 | var path = require('path'); 10 | 11 | // Windows requires Administrator cmd prompt to make file links, 12 | // so just make a copy instead. 13 | function copy(src, dest) { 14 | src = path.join(__dirname, src); 15 | dest = path.join(__dirname, dest); 16 | fs.writeFileSync(dest, fs.readFileSync(src)); 17 | } 18 | 19 | copy('../node_modules/jwcrypto/bidbundle.js', '../resources/static/common/js/lib/bidbundle.js'); 20 | copy('../node_modules/gobbledygook/gobbledygook.js', '../resources/static/common/js/lib/gobbledygook.js'); 21 | 22 | 23 | // generate ephemeral keys 24 | var child_process = require('child_process'); 25 | function node(script) { 26 | var cp = child_process.spawn('node', [path.join(__dirname, script)]); 27 | cp.stdout.pipe(process.stdout); 28 | cp.stderr.pipe(process.stderr); 29 | } 30 | 31 | node('./generate_ephemeral_keys.js'); 32 | 33 | // To install the automation-tests dependencies, specify AUTOMATION_TESTS=true 34 | // on the command line when running npm install. See issue #3160 35 | if (process.env.AUTOMATION_TESTS) { 36 | console.log(">>> Installing automation-tests dependencies"); 37 | // install automation-test dependencies 38 | var npm_process = child_process.spawn('npm', ['install'], { 39 | cwd: path.join(__dirname, '..', 'automation-tests'), 40 | env: process.env 41 | }); 42 | npm_process.stdout.pipe(process.stdout); 43 | npm_process.stderr.pipe(process.stderr); 44 | } 45 | -------------------------------------------------------------------------------- /scripts/rpmbuild.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This Source Code Form is subject to the terms of the Mozilla Public 3 | # License, v. 2.0. If a copy of the MPL was not distributed with this 4 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 5 | 6 | set -e 7 | 8 | progname=$(basename $0) 9 | 10 | cd $(dirname $0)/.. # top level of the checkout 11 | 12 | mkdir -p rpmbuild/SOURCES rpmbuild/SPECS rpmbuild/SOURCES 13 | rm -rf rpmbuild/RPMS rpmbuild/SOURCES/browserid 14 | 15 | tar --exclude rpmbuild --exclude .git --exclude .svn \ 16 | --exclude var -czf \ 17 | "$PWD/rpmbuild/SOURCES/browserid-server.tar.gz" . 18 | 19 | set +e 20 | 21 | export GIT_REVISION=$(git log -1 --oneline) 22 | export SVN_REVISION=$(svn info locale/ | sed -n -e "s,^Revision: ,,p") 23 | 24 | rpmbuild --define "_topdir $PWD/rpmbuild" \ 25 | --define "svnrev $SVN_REVISION" -ba scripts/browserid.spec 26 | rc=$? 27 | if [ $rc -eq 0 ]; then 28 | ls -l $PWD/rpmbuild/RPMS/*/*.rpm 29 | else 30 | echo "$progname: failed to build browserid RPM (rpmbuild rc=$rc)" >&2 31 | fi 32 | 33 | exit $rc 34 | -------------------------------------------------------------------------------- /scripts/serve_example_delegated_primary.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 | 6 | 7 | // A tiny webserver for the delegation of authority 8 | const 9 | express = require('express'), 10 | path = require('path'); 11 | 12 | var exampleServer = express.createServer(); 13 | 14 | exampleServer.use(express.logger({ format: 'dev' })); 15 | 16 | exampleServer.use(express.static(path.join(__dirname, "..", "example", "delegated_primary"), { redirect: false })); 17 | 18 | exampleServer.listen( 19 | process.env.PORT || 10011, 20 | process.env.HOST || process.env.IP_ADDRESS || "127.0.0.1", 21 | function() { 22 | var addy = exampleServer.address(); 23 | console.log("running on http://" + addy.address + ":" + addy.port); 24 | }); 25 | -------------------------------------------------------------------------------- /scripts/show_config.js: -------------------------------------------------------------------------------- 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 | var path = require('path'); 8 | 9 | // use the 'local' configuration if one isn't explicitly specified in the environment 10 | process.env['CONFIG_FILES'] = process.env['CONFIG_FILES'] || 11 | path.join(__dirname, '..', 'config', 'local.json'); 12 | 13 | console.log(require("../lib/configuration.js").toString()); 14 | -------------------------------------------------------------------------------- /scripts/test_backend: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This Source Code Form is subject to the terms of the Mozilla Public 3 | # License, v. 2.0. If a copy of the MPL was not distributed with this 4 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 5 | 6 | 7 | SCRIPT_DIR="$( cd "$( dirname "$0" )" && pwd )" 8 | BASEDIR=$(dirname $SCRIPT_DIR) 9 | export PATH=$PATH:$SCRIPT_DIR/../node_modules/.bin 10 | 11 | VOWS=`which vows 2> /dev/null` 12 | if [ ! -x "$VOWS" ]; then 13 | echo "vows not found in your path. try: npm install" 14 | exit 1 15 | fi 16 | 17 | # vows hates absolute paths. sheesh. 18 | cd $BASEDIR 19 | 20 | $SCRIPT_DIR/test_db_connectivity.js 21 | if [ $? = 0 ] ; then 22 | for file in tests/*.js ; do 23 | echo $file 24 | vows $file 25 | if [ $? != 0 ] ; then 26 | exit 1 27 | fi 28 | done 29 | else 30 | echo 31 | echo "Can't run tests: can't connect to the database" 32 | echo 33 | exit 1 34 | fi 35 | -------------------------------------------------------------------------------- /scripts/test_db_connectivity.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 | 6 | 7 | // a simple script to test to see if we can connect to 8 | // the database using the present configuration. 9 | const path = require('path'); 10 | 11 | if (!process.env['CONFIG_FILES']) { 12 | process.env['CONFIG_FILES'] = path.join(__dirname, "..", "config", "local.json"); 13 | } 14 | 15 | const 16 | configuration = require('../lib/configuration.js'), 17 | db = require('../lib/db.js'); 18 | 19 | var dbCfg = configuration.get('database'); 20 | 21 | // don't bother creating the schema 22 | delete dbCfg.create_schema; 23 | 24 | db.open(dbCfg, function (err, r) { 25 | function end() { process.exit(err ? 1 : 0); } 26 | if (err && err.message === "Unknown database 'browserid'") { 27 | err = undefined; 28 | end(); 29 | } else { 30 | if (!err) db.close(end); 31 | else end(); 32 | } 33 | }); 34 | -------------------------------------------------------------------------------- /tests/bcrypt-compatibility-test.js: -------------------------------------------------------------------------------- 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 | require('./lib/test_env.js'); 8 | 9 | const assert = 10 | require('assert'), 11 | vows = require('vows'), 12 | config = require('../lib/configuration.js'), 13 | bcrypt = require('bcrypt'); 14 | 15 | var suite = vows.describe('bcrypt-compatibility'); 16 | 17 | suite.addBatch({ 18 | "new bcrypt of password for given salt": { 19 | topic: function () { 20 | var salt = "$2a$04$rakQlaS/TyfjZmoVuRs9ku"; 21 | bcrypt.hash("Thisismypassword1!", salt, this.callback); 22 | }, 23 | "should match old bcrypt": function (hash) { 24 | assert.strictEqual(hash, '$2a$04$rakQlaS/TyfjZmoVuRs9kuQHFk2oShl8DNmVbxgSZyOE8Hzgk0One'); 25 | } 26 | }, 27 | "get rounds of old hash should match new bcrypt": function () { 28 | var hash = '$2a$04$rakQlaS/TyfjZmoVuRs9kuQHFk2oShl8DNmVbxgSZyOE8Hzgk0One'; 29 | assert.strictEqual(4, bcrypt.getRounds(hash)); 30 | } 31 | }); 32 | 33 | if (process.argv[1] === __filename) suite.run(); 34 | else suite.export(module); 35 | -------------------------------------------------------------------------------- /tests/data/borkedauthority.domain/.well-known/browserid: -------------------------------------------------------------------------------- 1 | { 2 | "authority": [ "arrays.are.not", "cool.in.this.document" ], 3 | "provisioning": "/provision.html", 4 | "authentication": "/sign_in.html", 5 | "public-key": { 6 | "algorithm":"RS", 7 | "n":"12150646309575666544658791157045645163757575303887721078710172478749665834070170928206481109930468203684865378748391106975718718959563139020999088154811587703010353786258781016056954403240590264386124614262627869140351957459406743577995562584260319925426603313709939197457399455483061173844980456364611416651616781677992262613894501858312578942785385470086255995080524454431673067666784338623903663347118104807073332038428581918086381436489000619294471995801952293054002077519255312962379161724622526642212406262043172654176008908362058486885146430345217844546587383034154533029235541666677817563420349484368059586917", 8 | "e":"65537" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/data/cycle.domain/.well-known/browserid: -------------------------------------------------------------------------------- 1 | { "authority": "cycle2.domain" } 2 | -------------------------------------------------------------------------------- /tests/data/cycle2.domain/.well-known/browserid: -------------------------------------------------------------------------------- 1 | { "authority": "cycle.domain" } -------------------------------------------------------------------------------- /tests/data/delegate0.domain/.well-known/browserid: -------------------------------------------------------------------------------- 1 | { "authority": "delegate1.domain" } 2 | -------------------------------------------------------------------------------- /tests/data/delegate1.domain/.well-known/browserid: -------------------------------------------------------------------------------- 1 | { "authority": "delegate2.domain" } 2 | -------------------------------------------------------------------------------- /tests/data/delegate10.domain/.well-known/browserid: -------------------------------------------------------------------------------- 1 | { "authority": "delegate11.domain" } 2 | -------------------------------------------------------------------------------- /tests/data/delegate2.domain/.well-known/browserid: -------------------------------------------------------------------------------- 1 | { "authority": "delegate3.domain" } 2 | -------------------------------------------------------------------------------- /tests/data/delegate3.domain/.well-known/browserid: -------------------------------------------------------------------------------- 1 | { "authority": "delegate4.domain" } 2 | -------------------------------------------------------------------------------- /tests/data/delegate4.domain/.well-known/browserid: -------------------------------------------------------------------------------- 1 | { "authority": "delegate5.domain" } 2 | -------------------------------------------------------------------------------- /tests/data/delegate5.domain/.well-known/browserid: -------------------------------------------------------------------------------- 1 | { "authority": "delegate6.domain" } 2 | -------------------------------------------------------------------------------- /tests/data/delegate6.domain/.well-known/browserid: -------------------------------------------------------------------------------- 1 | { "authority": "delegate7.domain" } 2 | -------------------------------------------------------------------------------- /tests/data/delegate7.domain/.well-known/browserid: -------------------------------------------------------------------------------- 1 | { "authority": "delegate8.domain" } 2 | -------------------------------------------------------------------------------- /tests/data/delegate8.domain/.well-known/browserid: -------------------------------------------------------------------------------- 1 | { "authority": "delegate9.domain" } 2 | -------------------------------------------------------------------------------- /tests/data/delegate9.domain/.well-known/browserid: -------------------------------------------------------------------------------- 1 | { "authority": "delegate10.domain" } 2 | -------------------------------------------------------------------------------- /tests/data/disabled.domain/.well-known/browserid: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": true, 3 | "provisioning": "/provision.html", 4 | "authentication": "/sign_in.html", 5 | "public-key": { 6 | "algorithm":"RS", 7 | "n":"12150646309575666544658791157045645163757575303887721078710172478749665834070170928206481109930468203684865378748391106975718718959563139020999088154811587703010353786258781016056954403240590264386124614262627869140351957459406743577995562584260319925426603313709939197457399455483061173844980456364611416651616781677992262613894501858312578942785385470086255995080524454431673067666784338623903663347118104807073332038428581918086381436489000619294471995801952293054002077519255312962379161724622526642212406262043172654176008908362058486885146430345217844546587383034154533029235541666677817563420349484368059586917", 8 | "e":"65537" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/data/hozed.domain/.well-known/browserid: -------------------------------------------------------------------------------- 1 | { "authority": "hozed.domain" } 2 | -------------------------------------------------------------------------------- /tests/data/lib.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "undef": true, 3 | "node": true, 4 | "es5": true, 5 | "esnext": true, 6 | "strict": false, 7 | "sub": true 8 | } 9 | -------------------------------------------------------------------------------- /tests/i18n_test_files/bg/client.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla/persona/59827a456d99399d4f09fb93e6f9b28bd1aaeab4/tests/i18n_test_files/bg/client.json -------------------------------------------------------------------------------- /tests/i18n_test_files/bg/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "messages": { 3 | "This is a translation test string.": [ 4 | null, 5 | "Прова? Прова? Четери, пет, шещ?" 6 | ], 7 | "This is not translated": [ 8 | null, 9 | "" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/i18n_test_templates/i18n_fallback_test.ejs: -------------------------------------------------------------------------------- 1 | <%- gettext("This is not translated") %> 2 | -------------------------------------------------------------------------------- /tests/i18n_test_templates/i18n_test.ejs: -------------------------------------------------------------------------------- 1 | <%- gettext("This is a translation test string.") %> 2 | -------------------------------------------------------------------------------- /tests/lib/http-mock.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 | * This mocks the http/https module for testing. 7 | */ 8 | 9 | const EventEmitter = require('events').EventEmitter; 10 | const util = require('util'); 11 | 12 | function HttpMock(responseOptions) { 13 | this.responseOptions = responseOptions; 14 | } 15 | HttpMock.prototype.request = function(requestOptions) { 16 | this._request = new RequestMock(requestOptions, this.responseOptions); 17 | return this._request; 18 | }; 19 | 20 | HttpMock.prototype.getRequest = function() { 21 | return this._request; 22 | }; 23 | 24 | module.exports = HttpMock; 25 | 26 | function RequestMock(requestOptions, responseOptions) { 27 | this.requestOptions = requestOptions; 28 | this.responseOptions = responseOptions; 29 | } 30 | util.inherits(RequestMock, EventEmitter); 31 | 32 | RequestMock.prototype.write = function(data) { 33 | this.data = data; 34 | }; 35 | 36 | 37 | RequestMock.prototype.end = function() { 38 | this.emit('response', { 39 | statusCode: this.responseOptions.statusCode 40 | }); 41 | }; 42 | 43 | 44 | -------------------------------------------------------------------------------- /tests/lib/responds-with.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 assert = require('assert'), 6 | http = require('http'), 7 | wsapi = require('./wsapi.js'); 8 | 9 | // Taken from the vows page. 10 | function assertStatus(code) { 11 | return function (err, res) { 12 | assert.equal(res.code, code); 13 | }; 14 | } 15 | 16 | module.exports = function(status, done) { 17 | var context = { 18 | topic: function () { 19 | // Get the current context's name, such as "POST /" 20 | // and split it at the space. 21 | var req = this.context.name.split(/ +/), // ["POST", "/"] 22 | method = req[0].toLowerCase(), // "post" 23 | path = req[1]; // "/" 24 | 25 | // Perform the contextual client request, 26 | // with the above method and path. If done is not passed in, 27 | // this.callback will be called automatically. 28 | wsapi[method](path, null, null, done).call(this); 29 | } 30 | }; 31 | 32 | // Create and assign the vow to the context. 33 | // The description is generated from the expected status code 34 | // and the status name, from node's http module. 35 | context['should respond with a ' + status + ' ' 36 | + http.STATUS_CODES[status]] = assertStatus(status); 37 | 38 | return context; 39 | }; 40 | 41 | 42 | -------------------------------------------------------------------------------- /tests/lib/secondary.js: -------------------------------------------------------------------------------- 1 | var wsapi = require('./wsapi.js'), 2 | wcli = require('../../lib/wsapi_client.js'); 3 | 4 | // create a new account via the api with (first address) 5 | exports.create = function(opts, cb) { 6 | opts = opts || {}; 7 | opts.email = opts.email || 'testuser@example.com'; 8 | opts.password = opts.password || opts.pass || 'password'; 9 | opts.site = opts.site || 'http://rp.example.com'; 10 | opts.fetchVerificationLinkCallback = opts.fetchVerificationLinkCallback || require('./start-stop.js').waitForToken; 11 | 12 | wcli.post(wsapi.configuration, '/wsapi/stage_user', wsapi.context, { 13 | email: opts.email, 14 | pass: opts.password, 15 | site: opts.site, 16 | backgroundColor: opts.backgroundColor, 17 | siteLogo: opts.siteLogo 18 | }, function(err, r) { 19 | if (err) return cb("cannot stage: " + err); 20 | if (r.code !== 200) return cb("cannot stage: " + r.body); 21 | 22 | opts.fetchVerificationLinkCallback(opts.email, function(err, t) { 23 | if (err) return cb("no verification token could be fetched: " + err); 24 | wcli.post(wsapi.configuration, '/wsapi/complete_user_creation', wsapi.context, { 25 | token: t 26 | }, function(err, r) { 27 | if (err) return cb("cannot complete: " + err); 28 | if (r.code !== 200) return cb("cannot complete: " + r.body); 29 | cb(err, r); 30 | }); 31 | }); 32 | }); 33 | }; 34 | -------------------------------------------------------------------------------- /tests/lib/statsd-mock.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 StatsdMock() { 6 | } 7 | 8 | StatsdMock.prototype = { 9 | increment: function(counterName, info) { 10 | this.lastIncrement = counterName; 11 | this.lastIncrementInfo = info; 12 | }, 13 | timing: function(counterName, info, moreInfo) { 14 | this.lastTiming = counterName; 15 | this.lastTimingInfo = info; 16 | } 17 | }; 18 | 19 | module.exports = StatsdMock; 20 | 21 | -------------------------------------------------------------------------------- /tests/lib/test_env.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 zero-exports include file should be included by each of the tests. 6 | * if NODE_ENV was not explicitly set to a test environment it will set 7 | * NODE_ENV and issue a warning on the console to developers */ 8 | 9 | if (undefined === process.env['NODE_ENV']) { 10 | console.log("Setting NODE_ENV to test_json to test with the local JSON database"); 11 | console.log("To test with a local mysql database, setup mysql and set NODE_ENV to test_mysql"); 12 | process.env['NODE_ENV'] = 'test_json'; 13 | } else if (process.env['NODE_ENV'].substr(0,5) !== 'test_') { 14 | console.log("(Woah. Running tests without a test_ configuration. Is this *really* what you want?)"); 15 | process.exit(1); 16 | } 17 | 18 | // if the environment is a 'test_' environment, then we'll use an 19 | // ephemeral database 20 | if (process.env['NODE_ENV'] === 'test_mysql') { 21 | process.env['DATABASE_NAME'] = "browserid_tmp_" + 22 | require('../../lib/secrets.js').generate(6); 23 | } else if (process.env['NODE_ENV'] === 'test_json') { 24 | process.env['DATABASE_NAME'] = require('temp').path({suffix: '.db'}); 25 | } 26 | -------------------------------------------------------------------------------- /tests/lib/wsapi.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 | wcli = require('../../lib/wsapi_client'); 7 | 8 | // the client "context" 9 | var context = exports.context = {}; 10 | 11 | // the configuration 12 | var configuration = exports.configuration = { 13 | browserid: 'http://127.0.0.1:10002/' 14 | }; 15 | 16 | exports.clearCookies = function(ctx) { 17 | wcli.clearCookies(ctx||context); 18 | }; 19 | 20 | exports.injectCookies = function(cookies, ctx) { 21 | wcli.injectCookies({cookieJar: cookies}, ctx||context); 22 | }; 23 | 24 | exports.getCookie = function(which, ctx) { 25 | return wcli.getCookie(ctx||context, which); 26 | }; 27 | 28 | exports.get = function (path, getArgs, ctx, done) { 29 | return function () { 30 | wcli.get(configuration, path, ctx||context, getArgs, (done || this.callback).bind(this)); 31 | }; 32 | }; 33 | 34 | exports.post = function (path, postArgs, ctx, done) { 35 | return function () { 36 | wcli.post(configuration, path, ctx||context, postArgs, (done || this.callback).bind(this)); 37 | }; 38 | }; 39 | 40 | exports.getCSRF = function(ctx) { 41 | var context = ctx||context; 42 | if (context && context.session && context.session.csrf_token) { 43 | return context.session.csrf_token; 44 | } 45 | return null; 46 | }; 47 | 48 | // allows for multiple clients 49 | exports.setContext = function (cxt) { 50 | context = cxt; 51 | }; 52 | 53 | exports.getContext = function () { 54 | return context; 55 | }; 56 | -------------------------------------------------------------------------------- /tests/secrets-test.js: -------------------------------------------------------------------------------- 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 | require('./lib/test_env.js'); 8 | 9 | const assert = require('assert'), 10 | vows = require('vows'), 11 | secrets = require('../lib/secrets'); 12 | 13 | var suite = vows.describe('secrets'); 14 | 15 | var LENGTH = 10; 16 | 17 | function make_secrets_batch(rand_func) { 18 | return { 19 | "generate a secret": { 20 | topic: function() { 21 | return rand_func(LENGTH); 22 | }, 23 | "of proper length" : function(err, s) { 24 | assert.equal(s.length, LENGTH); 25 | } 26 | }, 27 | "two secrets": { 28 | topic: function() { 29 | return { 30 | s1: rand_func(LENGTH), 31 | s2: rand_func(LENGTH) 32 | }; 33 | }, 34 | "are not equal" : function(err, the_secrets) { 35 | assert.notEqual(the_secrets.s1, the_secrets.s2); 36 | } 37 | } 38 | }; 39 | }; 40 | 41 | // check that we can generate random secrets 42 | suite.addBatch(make_secrets_batch(secrets.generate)); 43 | suite.addBatch(make_secrets_batch(secrets.weakGenerate)); 44 | 45 | // and the async one 46 | suite.addBatch({ 47 | "generate a secret": { 48 | topic: function() { 49 | secrets.generate(LENGTH, this.callback); 50 | }, 51 | "of proper length" : function(s, err) { 52 | assert.equal(s.length, LENGTH); 53 | } 54 | } 55 | }); 56 | // run or export the suite. 57 | if (process.argv[1] === __filename) suite.run(); 58 | else suite.export(module); 59 | -------------------------------------------------------------------------------- /tests/software-version-test.js: -------------------------------------------------------------------------------- 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 | require('./lib/test_env.js'); 8 | 9 | const 10 | assert = require('assert'), 11 | vows = require('vows'), 12 | fs = require('fs'), 13 | path = require('path'), 14 | version = require('../lib/version.js'); 15 | 16 | var suite = vows.describe('software-version'); 17 | suite.options.error = false; 18 | 19 | 20 | suite.addBatch({ 21 | "version": { 22 | topic: function() { version(this.callback); }, 23 | "works": function(r) { 24 | assert.isString(r); 25 | assert.equal(r.length, 7); 26 | } 27 | } 28 | }); 29 | 30 | // run or export the suite. 31 | if (process.argv[1] === __filename) suite.run(); 32 | else suite.export(module); 33 | --------------------------------------------------------------------------------