├── .codacy.yml ├── .codeclimate.yml ├── .coveragerc ├── .editorconfig ├── .gitignore ├── .gitlab-ci.yml ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── api ├── __init__.py ├── admin.py ├── apps.py ├── auth │ ├── __init__.py │ ├── adapter.py │ └── serializers.py ├── authentication.py ├── filters.py ├── forms.py ├── migrations │ ├── 0001_initial.py │ ├── 0002_remove_authorisedapp_scopes_delete_scope.py │ ├── 0003_rename_owner_authorisedapp_user.py │ ├── 0004_alter_authorisedapp_name_and_more.py │ └── __init__.py ├── mixins.py ├── models.py ├── permissions.py ├── serializers.py ├── templates │ └── rest_framework │ │ ├── api.html │ │ └── login.html ├── tests │ ├── __init__.py │ ├── api │ │ ├── __init__.py │ │ ├── auth │ │ │ ├── __init__.py │ │ │ └── test_auth.py │ │ ├── test_certificates.py │ │ ├── test_retrieve_crl.py │ │ └── tokens │ │ │ ├── __init__.py │ │ │ └── test_tokens.py │ ├── base.py │ ├── factories.py │ └── test_factories.py ├── tokens │ ├── __init__.py │ ├── serializers.py │ ├── urls.py │ └── views.py ├── urls.py ├── utils.py └── views.py ├── bounca ├── __init__.py ├── management │ ├── __init__.py │ └── commands │ │ ├── __init__.py │ │ └── site.py ├── settings.py ├── urls.py └── wsgi.py ├── build-front.sh ├── build-package.sh ├── certificate_engine ├── __init__.py ├── apps.py ├── ssl │ ├── __init__.py │ ├── certificate.py │ ├── crl.py │ ├── info.py │ └── key.py ├── tests │ ├── __init__.py │ ├── helpers.py │ ├── test_client_certificate.py │ ├── test_codesigning_certificate.py │ ├── test_crl.py │ ├── test_ed25519_key.py │ ├── test_intermediate_certificate.py │ ├── test_oscp_certificate.py │ ├── test_root_certificate.py │ ├── test_rsa_key.py │ └── test_server_certificate.py └── types.py ├── changelog.md ├── docker-compose.yml ├── docs ├── Makefile └── source │ ├── _static │ └── bounca.css │ ├── _templates │ ├── launchpage.html │ └── layout.html │ ├── bounca │ ├── contribution.rst │ ├── features.rst │ └── support.rst │ ├── conf.py │ ├── demo │ ├── nginx_client_auth │ │ ├── certs │ │ │ ├── BounCA_Int_Root.intermediate-chain.pem │ │ │ ├── demo1.client_cert │ │ │ │ ├── crlchain.pem │ │ │ │ ├── demo1-chain.pem │ │ │ │ ├── demo1.key │ │ │ │ ├── demo1.p12 │ │ │ │ ├── demo1.pem │ │ │ │ ├── intermediate.pem │ │ │ │ ├── intermediate_root-chain.pem │ │ │ │ └── rootca.pem │ │ │ ├── demo2.client_cert │ │ │ │ ├── crlchain.pem │ │ │ │ ├── demo2-chain.pem │ │ │ │ ├── demo2.key │ │ │ │ ├── demo2.p12 │ │ │ │ ├── demo2.pem │ │ │ │ ├── intermediate.pem │ │ │ │ ├── intermediate_root-chain.pem │ │ │ │ └── rootca.pem │ │ │ ├── int.crl.pem │ │ │ ├── localhost-chain.pem │ │ │ ├── localhost.key │ │ │ ├── root.crl.pem │ │ │ ├── root_int.crl.pem │ │ │ └── rootca.pem │ │ ├── docker-compose.yml │ │ ├── nginx.conf │ │ └── www │ │ │ └── index.html │ └── nginx_ssl │ │ ├── certs │ │ ├── localhost-chain.pem │ │ ├── localhost.key │ │ └── rootca.pem │ │ ├── docker-compose.yml │ │ ├── nginx.conf │ │ └── www │ │ └── index.html │ ├── getting_started.rst │ ├── images │ ├── BounCA-logo.png │ ├── generate-ca-certificates │ │ ├── 1-empty-root-dashboard.png │ │ ├── 10-inspect-intermediate-certificate.png │ │ ├── 11-inspect-intermediate-certificate-crl-ocsp.png │ │ ├── 2-create-root-certificate.png │ │ ├── 20-install-root-pem-certificate.png │ │ ├── 20-listed-root-pem-certificate.png │ │ ├── 21-inspect-root-pem-certificate.png │ │ ├── 22-trust-root-ca-pem.png │ │ ├── 24-trusted-self-signed-root-ca-pem.png │ │ ├── 26-root-ca-is-trusted.png │ │ ├── 27-generate-app-token.png │ │ ├── 3-create-root-certificate-crl.png │ │ ├── 4-root-certificate-generated.png │ │ ├── 5-inspect-root-certificate.png │ │ ├── 6-inspect-root-certificate-X.509v3-extensions.png │ │ ├── 7-enter-root-ca.png │ │ ├── 8-generate-intermediate-certificate.png │ │ ├── 9-generate-intermediate-certificate-enter-passphrases.png │ │ └── 9-generated-intermediate-ca.png │ ├── generate-client-certificate │ │ ├── 12-enter-int-ca.png │ │ ├── 13-open-client-certificate-create-form.png │ │ ├── 14-fill-in-the-data.png │ │ ├── 15-enter-the-passphrase.png │ │ ├── 16-create-a-second-client-certificate.png │ │ ├── 17-enter-passphrase-of-second-certificate.png │ │ ├── 18-overview-generated-certificates.png │ │ ├── 20-enter-passphrase-of-intermediate.png │ │ ├── 21-revoked-demo2-certificate.png │ │ ├── 22-download-intermediate-chain-and-crl.png │ │ ├── 31-verify-demo1-2-certificates.png │ │ ├── 32-content-of-intermediate-crl-file.png │ │ ├── 33-check-revoked-certificate.png │ │ ├── 34-no-client-cert.png │ │ ├── 35-valid-client-cert.png │ │ ├── 36-revoked-client-cert.png │ │ ├── 40-adding-client-certificate-to-keychain-of-macOS.png │ │ ├── 41-added-client-certificate-to-keychain-of-macOS.png │ │ ├── 42-inspect-client-certificate.png │ │ ├── 43-visit-mTLS-site-safari.png │ │ ├── 44-granted-mTLS-safari.png │ │ ├── 45-visit-mTLS-chrome.png │ │ ├── 46-granted-mTLS-chrome.png │ │ ├── 47-certificate-management-firefox.png │ │ ├── 48-import-pkcs12-in-firefox.png │ │ ├── 49-client-certificate-added-in-firefox.png │ │ ├── 50-visit-mTLS-firefox.png │ │ └── 51-granted-mTLS-firefox.png │ ├── generate-mail-certificate │ │ ├── 12-enter-int-ca.png │ │ ├── 14-fill-in-the-data.png │ │ ├── 15-enter-the-passphrase.png │ │ ├── 16-generated-smime-certificate.png │ │ ├── 17-inspect-subject-client-certificate.png │ │ ├── 18-inspect-subject-alt-names-certificate.png │ │ ├── 19-install-client-certificate.png │ │ ├── 20-create-signed-mail.png │ │ ├── 21-received-signed-mail.png │ │ ├── 22-received-signed-mail-thunderbird-not-trusted.png │ │ ├── 23-add-root-certificate-thunderbird.png │ │ ├── 24-trust-root-certificate-thunderbird.png │ │ ├── 25-received-signed-mail-trusted-thunderbird.png │ │ ├── 26-add-client-certificate-to-thunderbird.png │ │ ├── 27-select-p12-file-thunderbird.png │ │ ├── 28-client-certificate-added-thunderbird.png │ │ ├── 29-select-client-certificate-to-sign-and-encrypt-mail-thunderbird.png │ │ ├── 30-client-certificate-configured-thunderbird.png │ │ ├── 31-send-signed-mail-thunderbird.png │ │ ├── 32-send-encrypted-mail-Mail.png │ │ └── 33-received-encrypted-mail-Firefox.png │ ├── generate-server-certificate │ │ ├── 12-enter-int-ca.png │ │ ├── 13-copy-data-from-intermediate-certificate.png │ │ ├── 13-create-ssl-server-certificate.png │ │ ├── 14-enter-passphrase.png │ │ ├── 14-enter-subject-alternative-names.png │ │ ├── 15-inspect-server-certificate.png │ │ ├── 15-server-certificate-generated.png │ │ ├── 16-inspect-server-certificate-crl-ocsp.png │ │ ├── 18-ssl-certificate-zip-package.png │ │ ├── 19-check-ssl-certificate-chain.png │ │ ├── 26-root-ca-is-trusted.png │ │ ├── 28-visit-website-trusted-ssl-connection-https.png │ │ ├── 30-renew-certificate.png │ │ ├── 31-renew-certificate-form.png │ │ └── 32-certificate-renewed.png │ ├── hex.png │ ├── hexa.png │ ├── ico │ │ ├── android-chrome-144x144.png │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-36x36.png │ │ ├── android-chrome-48x48.png │ │ ├── android-chrome-72x72.png │ │ ├── android-chrome-96x96.png │ │ ├── apple-touch-icon-114x114.png │ │ ├── apple-touch-icon-120x120.png │ │ ├── apple-touch-icon-144x144.png │ │ ├── apple-touch-icon-152x152.png │ │ ├── apple-touch-icon-180x180.png │ │ ├── apple-touch-icon-57x57.png │ │ ├── apple-touch-icon-60x60.png │ │ ├── apple-touch-icon-72x72.png │ │ ├── apple-touch-icon-76x76.png │ │ ├── apple-touch-icon-precomposed.png │ │ ├── apple-touch-icon.png │ │ ├── browserconfig.xml │ │ ├── favicon-16x16.png │ │ ├── favicon-194x194.png │ │ ├── favicon-32x32.png │ │ ├── favicon-96x96.png │ │ ├── favicon.ico │ │ ├── manifest.json │ │ ├── mstile-144x144.png │ │ ├── mstile-150x150.png │ │ ├── mstile-310x150.png │ │ ├── mstile-310x310.png │ │ ├── mstile-70x70.png │ │ └── safari-pinned-tab.svg │ ├── install_root_certificate │ │ ├── 1_chrome_open_settings.png │ │ ├── 1_firefox_open_settings_page.png │ │ ├── 20-install-root-pem-certificate.png │ │ ├── 20-listed-root-pem-certificate.png │ │ ├── 21-inspect-root-pem-certificate.png │ │ ├── 22-trust-root-ca-pem.png │ │ ├── 24-trusted-self-signed-root-ca-pem.png │ │ ├── 26-root-ca-is-trusted.png │ │ ├── 2_chrome_click_on_advanced_settings_and_go_to_certificates.png │ │ ├── 2_firefox_click_on_advanced_settings_and_go_to_certificates.png │ │ ├── 3_chrome_click_on_authorities_and_press_import_button.png │ │ ├── 3_firefox_import_the_root_certificate.png │ │ ├── 4_chrome_select_the_root_certificate_file.png │ │ ├── 4_firefox_select_the_root_certificate_file.png │ │ ├── 5_chrome_add_the_certificate_and_select_trust_rules.png │ │ ├── 5_firefox_select_the_trust_rules.png │ │ ├── 6_chrome_certificate_is_added_to_authorities_list.png │ │ ├── 6_firefox_the_root_certificate_has_been_added.png │ │ ├── 7_chrome_inspect_the_certificate_by_clicking_on_view_button.png │ │ ├── 7_firefox_inspect_the_root_certificate.png │ │ ├── 8_chrome_visit_self-signed_website_and_verify_it_is_trusted.png │ │ ├── 8_firefox_visit_self-signed_website_and_verify_it_is_trusted.png │ │ ├── ios_certificate_installed.jpg │ │ ├── ios_open_certificate.jpg │ │ └── ios_trust_new_certificate.jpg │ ├── main │ │ ├── bounca │ │ │ ├── adding_new_intermediate_certificate.png │ │ │ ├── client_server_certificate_overview.png │ │ │ ├── intermediate_certificate_overview.png │ │ │ ├── revoke_certificate.png │ │ │ ├── revoked_certificate_overview.png │ │ │ ├── root_ca_dashboard.png │ │ │ ├── root_certificate_info.png │ │ │ ├── ssl_dashboard_bounca.png │ │ │ └── validated_certificate_chain.png │ │ ├── create.png │ │ ├── easy.png │ │ ├── integrate.png │ │ ├── manage.png │ │ ├── private.png │ │ ├── triangulated_grid.png │ │ └── world.png │ ├── readme │ │ └── ssl_dashboard_bounca.png │ └── vpn-configuration │ │ ├── 12-enter-int-ca.png │ │ ├── 13-create-openvpn-server-certificate.png │ │ ├── 14-passphrase-openvpn-server-certificate.png │ │ ├── 15-generate-dh-params.png │ │ ├── 20-create-openvpn-client-certificate.png │ │ ├── 20-passphrase-openvpn-client-certificate.png │ │ ├── 31-OpenVPN-dashboard-OpenWRT.png │ │ ├── 32-Demo-VPN-uploaded.png │ │ ├── 33-Inspect-config-Demo-VPN.png │ │ ├── 34-Save-Apply-and-start-Demo-VPN.png │ │ ├── 35-Add-firewall-rule-accepting-UDP-OpenVPN.png │ │ ├── 36-Allow-tun-interface-in-local-LAN-zone.png │ │ ├── 36a-Allow-tun-interface-in-local-LAN-zone.png │ │ ├── 40-import-ovpn-file.png │ │ ├── 41-imported-profile.png │ │ ├── 42-disconnected-profile.png │ │ ├── 43-enter-passphrase.png │ │ ├── 44-connected-vpn.png │ │ └── 45-browse-to-internal-network.png │ ├── include_files.rst │ ├── index.rst │ └── tutorials │ ├── create_certificate_authority.rst │ ├── create_client_certificate_browser.rst │ ├── create_mail_certificate.rst │ ├── create_server_certificate_webserver.rst │ ├── install_root_certificate.rst │ └── vpn_configuration.rst ├── etc ├── bounca │ └── services.yaml.example ├── nginx │ └── bounca └── uwsgi │ └── bounca.ini ├── front ├── .babelrc ├── .env ├── .env.production ├── .eslintignore ├── .eslintrc.js ├── .postcssrc.js ├── Makefile ├── README.md ├── babel.config.js ├── package.json ├── public │ ├── favicon.ico │ ├── ico │ │ ├── android-chrome-144x144.png │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-36x36.png │ │ ├── android-chrome-48x48.png │ │ ├── android-chrome-72x72.png │ │ ├── android-chrome-96x96.png │ │ ├── apple-touch-icon-114x114.png │ │ ├── apple-touch-icon-120x120.png │ │ ├── apple-touch-icon-144x144.png │ │ ├── apple-touch-icon-152x152.png │ │ ├── apple-touch-icon-180x180.png │ │ ├── apple-touch-icon-57x57.png │ │ ├── apple-touch-icon-60x60.png │ │ ├── apple-touch-icon-72x72.png │ │ ├── apple-touch-icon-76x76.png │ │ ├── apple-touch-icon-precomposed.png │ │ ├── apple-touch-icon.png │ │ ├── browserconfig.xml │ │ ├── favicon-16x16.png │ │ ├── favicon-194x194.png │ │ ├── favicon-32x32.png │ │ ├── favicon-96x96.png │ │ ├── manifest.json │ │ ├── mstile-144x144.png │ │ ├── mstile-150x150.png │ │ ├── mstile-310x150.png │ │ ├── mstile-310x310.png │ │ ├── mstile-70x70.png │ │ └── safari-pinned-tab.svg │ └── index.html ├── src │ ├── App.vue │ ├── api │ │ ├── apptokens.js │ │ ├── auth.js │ │ ├── certificates.js │ │ ├── profile.js │ │ └── session.js │ ├── assets │ │ └── img │ │ │ └── BounCA-logo.png │ ├── components │ │ ├── auth │ │ │ ├── EmailVerify.vue │ │ │ ├── Login.vue │ │ │ ├── PasswordForgot.vue │ │ │ ├── PasswordReset.vue │ │ │ ├── ResendEmail.vue │ │ │ └── Signup.vue │ │ ├── core │ │ │ ├── Drawer.vue │ │ │ ├── Footer.vue │ │ │ └── Toolbar.vue │ │ ├── dashboard │ │ │ ├── Certificate.vue │ │ │ ├── Intermediate.vue │ │ │ ├── Overview.vue │ │ │ ├── Root.vue │ │ │ └── user │ │ │ │ └── UserProfile.vue │ │ ├── error │ │ │ └── NotFound.vue │ │ ├── forms │ │ │ ├── Certificate.vue │ │ │ ├── EmailVerify.vue │ │ │ ├── IntermediateCert.vue │ │ │ ├── RenewCertificate.vue │ │ │ ├── RootCert.vue │ │ │ └── user │ │ │ │ ├── AddToken.vue │ │ │ │ ├── ChangePassword.vue │ │ │ │ └── ChangeProfile.vue │ │ └── index.js │ ├── main.js │ ├── plugins │ │ └── vuetify.js │ ├── router │ │ ├── auth.js │ │ ├── dashboard.js │ │ ├── home.js │ │ └── index.js │ ├── store │ │ ├── auth.js │ │ ├── dashboard.js │ │ ├── index.js │ │ └── version.js │ └── views │ │ ├── Auth.vue │ │ ├── Dashboard.vue │ │ └── Public.vue └── vue.config.js ├── graphics └── logo │ ├── BounCA-icon.png │ ├── BounCA.pdf │ └── BounCA.sketch ├── logs └── .gitignore ├── make-docs.sh ├── make-package.sh ├── manage.py ├── pyproject.toml ├── requirements.docs.txt ├── requirements.txt ├── run-checks-node.sh ├── run-checks-python.sh ├── run-checks.sh ├── run-dev-server.sh ├── run-tests.sh ├── setup.cfg ├── setup.py ├── superuser_signup ├── __init__.py ├── apps.py ├── forms.py ├── templates │ └── account │ │ └── signup.html └── views.py ├── vuetifyforms ├── README.md ├── __init__.py ├── apps.py ├── components.py ├── management │ └── commands │ │ ├── __init__.py │ │ └── generate_forms.py ├── templates │ └── vuetify │ │ ├── display_form.html │ │ ├── field.html │ │ ├── layout │ │ ├── baseinput.html │ │ ├── buttonholder.html │ │ ├── column.html │ │ ├── fieldset.html │ │ ├── flex.html │ │ ├── row.html │ │ └── spacer.html │ │ ├── script │ │ ├── default.js │ │ ├── imports.js │ │ └── methods.js │ │ ├── uni_form.html │ │ └── whole_uni_form.html ├── templatetags │ ├── __init__.py │ └── crispy_forms_vuetify.py ├── views.py └── vue.py └── x509_pki ├── __init__.py ├── admin.py ├── apps.py ├── management ├── __init__.py └── commands │ └── __init__.py ├── migrations ├── 0001_squashed_0015_keystore_p12.py ├── 0002_keystore_fingerprint.py ├── 0003_alter_keystore_fingerprint.py ├── 0004_alter_certificate_type.py ├── 0005_alter_certificate_crl_distribution_url.py ├── 0006_keystore_p12_legacy.py └── __init__.py ├── models.py └── tests ├── __init__.py ├── factories.py ├── test_factories.py └── test_models.py /.codacy.yml: -------------------------------------------------------------------------------- 1 | engines: 2 | eslint: 3 | enabled: true 4 | fixme: 5 | enabled: true 6 | duplication: 7 | enabled: true 8 | config: 9 | languages: 10 | - python 11 | - javascript 12 | pep8: 13 | enabled: true 14 | radon: 15 | enabled: true 16 | ratings: 17 | paths: 18 | - "**.py" 19 | exclude_paths: 20 | - '**/migrations/**' 21 | - '**/tests/**' 22 | - 'ci/*' 23 | - 'docs/*' 24 | - 'etc/*' 25 | - 'graphics/*' 26 | - 'media/*' 27 | - 'pki/*' 28 | - 'bounca/static/**' 29 | - 'bounca/webapp/static/**' 30 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | engines: 2 | eslint: 3 | enabled: true 4 | fixme: 5 | enabled: true 6 | duplication: 7 | enabled: true 8 | config: 9 | languages: 10 | - python 11 | #mass_threshold: 30 12 | - javascript 13 | pep8: 14 | enabled: true 15 | radon: 16 | enabled: true 17 | ratings: 18 | paths: 19 | - "**.py" 20 | exclude_paths: 21 | - '**/migrations/**/*' 22 | - '**/tests/**/*' 23 | - 'ci/*' 24 | - 'docs/*' 25 | - 'etc/*' 26 | - 'graphics/*' 27 | - 'media/*' 28 | - 'pki/*' 29 | - 'bounca/static/*' 30 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | source = . 3 | omit = 4 | bounca/management/* 5 | bounca/management/commands/* 6 | bounca/migrations/* 7 | **/__init__.py 8 | manage* 9 | */test* 10 | bounca/wsgi.py 11 | env/* 12 | venv/* 13 | [html] 14 | title = Coverage Report for BounCA 15 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | indent_style = space 9 | indent_size = 4 10 | end_of_line = lf 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | 15 | [gulpfile.babel.js] 16 | indent_style = space 17 | indent_size = 2 18 | 19 | [*.{yaml,yml}] 20 | indent_size = 2 21 | 22 | [*.eslintrc] 23 | indent_size = 2 24 | 25 | [*.vue] 26 | indent_size = 2 27 | tab_width = 2 28 | ij_continuation_indent_size = 2 29 | ij_vue_indent_children_of_top_level = template 30 | ij_vue_interpolation_new_line_after_start_delimiter = true 31 | ij_vue_interpolation_new_line_before_end_delimiter = true 32 | ij_vue_interpolation_wrap = off 33 | ij_vue_keep_indents_on_empty_lines = false 34 | ij_vue_spaces_within_interpolation_expressions = true 35 | ij_vue_uniform_indent = true 36 | 37 | [Makefile] 38 | indent_style = tab 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | *.pyc 6 | *.swp 7 | *.DS_Store 8 | **/doc/_build 9 | .mypy_cache 10 | node_modules 11 | package-lock.json 12 | 13 | # log files 14 | npm-debug.log* 15 | yarn-debug.log* 16 | yarn-error.log* 17 | pnpm-debug.log* 18 | *.log 19 | 20 | # C extensions 21 | *.so 22 | 23 | # Distribution / packaging 24 | out/ 25 | .Python 26 | env/ 27 | build/ 28 | develop-eggs/ 29 | downloads/ 30 | eggs/ 31 | .eggs/ 32 | lib/ 33 | libs/ 34 | lib64/ 35 | parts/ 36 | sdist/ 37 | var/ 38 | nginx/ 39 | 40 | #bounca/static/libs/ 41 | *.egg-info/ 42 | .installed.cfg 43 | *.egg 44 | 45 | # PyInstaller 46 | # Usually these files are written by a python script from a template 47 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 48 | *.manifest 49 | *.spec 50 | 51 | # Installer logs 52 | pip-log.txt 53 | pip-delete-this-directory.txt 54 | 55 | # Unit test / coverage reports 56 | htmlcov/ 57 | .tox/ 58 | .coverage 59 | coverage.xml 60 | .coverage.* 61 | .cache 62 | nosetests.xml 63 | *,cover 64 | .hypothesis/ 65 | 66 | # Translations 67 | *.mo 68 | *.pot 69 | 70 | # Sphinx documentation 71 | docs/_build/ 72 | 73 | # PyBuilder 74 | target/ 75 | 76 | #Ipython Notebook 77 | .ipynb_checkpoints 78 | 79 | # IDE 80 | .project 81 | .pydevproject 82 | .idea 83 | .settings 84 | .vscode 85 | *.suo 86 | *.ntvs* 87 | *.njsproj 88 | *.sln 89 | *.sw? 90 | 91 | # Other 92 | tmp/ 93 | pki/ 94 | etc/bounca/services.yaml 95 | TODO 96 | 97 | # Static 98 | media/static 99 | 100 | #frontend 101 | front/node_modules 102 | front/dist 103 | 104 | # local env files 105 | .env.local 106 | .env.*.local 107 | 108 | 109 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 2 | BounCA logo 3 | 4 | 5 | # Welcome to BounCA - Personal Key Management 6 | 7 | ## Contributing 8 | 9 | 10 | ## Bug Reports & Feature Requests 11 | 12 | Please use the [issue tracker](https://gitlab.com/bounca/bounca/-/issues) to report any bugs or file feature requests. 13 | 14 | ## Contributing 15 | 16 | 1. Create an issue and describe your idea 17 | 2. Create your feature branch (`git checkout -b my-new-feature`) 18 | 3. Commit your changes (`git commit -am 'Add some feature'`) 19 | 4. Publish the branch (`git push origin my-new-feature`) 20 | 5. Create a new Pull Request 21 | 6. Thanks! 22 | 23 | ## License 24 | 25 | Apache License v2 - (c) 2016-2022, Repleo, Amstelveen 26 | 27 | ## Author Information 28 | 29 | Jeroen Arnoldus (jeroen@repleo.nl) 30 | 31 | [Repleo](https://www.repleo.nl), Amsterdam, Holland -- www.repleo.nl 32 | 33 | 34 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PYTHON_FOLDERS = api bounca certificate_engine vuetifyforms x509_pki superuser_signup 2 | LOCAL_SERVER_PORT ?= 8000 3 | 4 | default: 5 | @echo "No default target!" 6 | 7 | frontend_collect: 8 | python manage.py collectstatic --link --noinput 9 | 10 | runserver: 11 | python manage.py runserver 0.0.0.0:$(LOCAL_SERVER_PORT) 12 | 13 | quality: flake8 black_check isort_check 14 | 15 | isort_check: 16 | find $(PYTHON_FOLDERS) -path '**/migrations' -prune -o -name '*.py' -print | xargs isort -c 17 | 18 | isort_fix: 19 | find $(PYTHON_FOLDERS) -path '**/migrations' -prune -o -name '*.py' -print | xargs isort 20 | 21 | flake8: 22 | flake8 $(PYTHON_FOLDERS) 23 | 24 | black_fix: 25 | black . 26 | 27 | black_check: 28 | black --check . 29 | 30 | website: 31 | $(MAKE) -C ./docs html 32 | 33 | runwebsiteserver: 34 | python3 -m http.server -d ./docs/build/html 8090 35 | 36 | createvueforms: 37 | python3 manage.py generate_forms 38 | 39 | docserver: 40 | python3 -m http.server --directory ./docs/build/html 8090 41 | 42 | update-python-packages: 43 | pur 44 | 45 | migrate: 46 | python manage.py migrate 47 | -------------------------------------------------------------------------------- /api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/api/__init__.py -------------------------------------------------------------------------------- /api/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.forms import BooleanField, ModelForm 3 | 4 | from . import utils 5 | from .models import AuthorisedApp 6 | 7 | 8 | class AuthorisedAppForm(ModelForm): 9 | generate_new_token = BooleanField(required=False, initial=False) 10 | 11 | class Meta: 12 | model = AuthorisedApp 13 | fields = "__all__" 14 | 15 | def __init__(self, *args, **kwargs): 16 | super(AuthorisedAppForm, self).__init__(*args, **kwargs) 17 | self.fields["token"].disabled = not self.current_user.is_superuser 18 | self.fields["token"].required = False 19 | 20 | def clean(self): 21 | if self.cleaned_data.get("generate_new_token", False): 22 | self.cleaned_data["token"] = utils.new_token(44) 23 | return self.cleaned_data 24 | 25 | def save(self, commit=True): 26 | obj = super(AuthorisedAppForm, self).save(commit=False) 27 | obj.save(commit) 28 | if commit: 29 | obj.save() 30 | obj.save_m2m() 31 | return obj 32 | 33 | 34 | @admin.register(AuthorisedApp) 35 | class AppAdmin(admin.ModelAdmin): 36 | form = AuthorisedAppForm 37 | list_display = ("name", "token") 38 | 39 | def get_form(self, request, obj=None, **kwargs): 40 | form = super(AppAdmin, self).get_form(request, obj, **kwargs) 41 | form.current_user = request.user 42 | return form 43 | -------------------------------------------------------------------------------- /api/apps.py: -------------------------------------------------------------------------------- 1 | """Api name""" 2 | 3 | from django.apps import AppConfig 4 | 5 | 6 | class ApiConfig(AppConfig): 7 | name = "api" 8 | -------------------------------------------------------------------------------- /api/auth/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/api/auth/__init__.py -------------------------------------------------------------------------------- /api/auth/adapter.py: -------------------------------------------------------------------------------- 1 | from allauth.account.adapter import DefaultAccountAdapter 2 | from allauth.utils import build_absolute_uri 3 | from rest_framework.reverse import reverse 4 | 5 | 6 | class DefaultAccountAdapterFrontendHost(DefaultAccountAdapter): 7 | def get_email_confirmation_url(self, request, emailconfirmation): 8 | """Constructs the email confirmation (activation) url. 9 | 10 | Note that if you have architected your system such that email 11 | confirmations are sent outside of the request context `request` 12 | can be `None` here. 13 | """ 14 | url = reverse("account_confirm_email", args=[emailconfirmation.key]) 15 | ret = build_absolute_uri(None, url) 16 | return ret 17 | -------------------------------------------------------------------------------- /api/auth/serializers.py: -------------------------------------------------------------------------------- 1 | from dj_rest_auth.serializers import PasswordResetSerializer 2 | from django.conf import settings 3 | 4 | 5 | class PasswordResetSerializerFrontendHost(PasswordResetSerializer): 6 | """ 7 | Serializer for requesting a password reset e-mail. 8 | """ 9 | 10 | def save(self): 11 | if "allauth" in settings.INSTALLED_APPS: 12 | from allauth.account.forms import default_token_generator 13 | else: 14 | from django.contrib.auth.tokens import default_token_generator 15 | 16 | request = self.context.get("request") 17 | # Set some values to trigger the send_email method. 18 | opts = { 19 | "use_https": request.is_secure(), 20 | "from_email": getattr(settings, "DEFAULT_FROM_EMAIL"), 21 | "request": None, # None triggers to use the host from site object 22 | "token_generator": default_token_generator, 23 | } 24 | 25 | opts.update(self.get_email_options()) 26 | self.reset_form.save(**opts) 27 | -------------------------------------------------------------------------------- /api/authentication.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | 3 | from django.core.cache import cache 4 | from rest_framework.authentication import BaseAuthentication 5 | 6 | from api.models import AuthorisedApp 7 | 8 | KEYS_TTL = 1800 9 | 10 | 11 | def cache_value(func): 12 | @wraps(func) 13 | def new_func(self, app_token, *args, **kwargs): 14 | key = f":app_auth:authorised_app:{app_token}:" 15 | data = cache.get(key) 16 | if data is None: 17 | data = func(self, app_token, *args, **kwargs) 18 | cache.set(key, data, KEYS_TTL) 19 | 20 | return data 21 | 22 | return new_func 23 | 24 | 25 | class AppTokenAuthentication(BaseAuthentication): 26 | def authenticate(self, request): 27 | # The tokens to set: X-AUTH-TOKEN or X-USER-AUTH-TOKEN 28 | app_token = request.META.get("HTTP_X_AUTH_TOKEN") 29 | user_token = request.META.get("HTTP_X_USER_AUTH_TOKEN") 30 | app = self.authorised_app_for_token(app_token) 31 | if app: 32 | return app.user, AuthData(app_token, user_token) 33 | else: 34 | return None 35 | 36 | # @cache_value 37 | def authorised_app_for_token(self, app_token): 38 | return AuthorisedApp.objects.filter(token=app_token).first() 39 | 40 | 41 | class AuthData(object): 42 | """ 43 | We store important data connected to the authorisation step in 44 | this object and we store this object to the request object so 45 | that the data here can be used through the view and related classes. 46 | """ 47 | 48 | def __init__(self, app_token, user_token): 49 | self.app_token = app_token 50 | self.user_token = user_token 51 | -------------------------------------------------------------------------------- /api/filters.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional, Tuple 2 | 3 | from django.db import models 4 | from rest_framework import filters 5 | 6 | # Code fragment from https://github.com/encode/django-rest-framework/issues/1005 7 | 8 | 9 | class RelatedOrderingFilter(filters.OrderingFilter): 10 | _max_related_depth = 3 11 | 12 | @staticmethod 13 | def _get_verbose_name(field: models.Field, non_verbose_name: str) -> str: 14 | return str(field.verbose_name) if hasattr(field, "verbose_name") else non_verbose_name.replace("_", " ") 15 | 16 | def _retrieve_all_related_fields( 17 | self, fields: Tuple[models.Field], model: models.Model, depth: int = 0 18 | ) -> List[Tuple[str, str]]: 19 | valid_fields: List[Tuple[str, str]] = [] 20 | if depth > self._max_related_depth: 21 | return valid_fields 22 | for field in fields: 23 | if field.related_model and field.related_model != model: 24 | rel_fields = self._retrieve_all_related_fields( 25 | field.related_model._meta.get_fields(), field.related_model, depth + 1 26 | ) 27 | for rel_field in rel_fields: 28 | valid_fields.append((f"{field.name}__{rel_field[0]}", self._get_verbose_name(field, rel_field[1]))) 29 | else: 30 | valid_fields.append( 31 | ( 32 | field.name, 33 | self._get_verbose_name(field, field.name), 34 | ) 35 | ) 36 | return valid_fields 37 | 38 | def get_valid_fields( 39 | self, queryset: models.QuerySet, view, context: Optional[dict] = None 40 | ) -> List[Tuple[str, str]]: 41 | ordering_fields = getattr(view, "ordering_fields", self.ordering_fields) 42 | valid_fields: List[Tuple[str, str]] 43 | if not ordering_fields == "__all_related__": 44 | if not context: 45 | context = {} 46 | valid_fields = super().get_valid_fields(queryset, view, context) 47 | else: 48 | valid_fields = [ 49 | *self._retrieve_all_related_fields(queryset.model._meta.get_fields(), queryset.model), 50 | *[(key, key.title().split("__")) for key in queryset.query.annotations], 51 | ] 52 | return valid_fields 53 | -------------------------------------------------------------------------------- /api/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.0.4 on 2022-05-26 20:35 2 | 3 | import django.db.models.deletion 4 | from django.conf import settings 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | ('x509_pki', '0004_alter_certificate_type'), 14 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 15 | ] 16 | 17 | operations = [ 18 | migrations.CreateModel( 19 | name='Scope', 20 | fields=[ 21 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 22 | ('access', models.CharField(choices=[('RCRL', 'Read CRL of root and intermediate certificates'), ('RCERT', 'Read root and intermediate certificates'), ('RISSUED', 'Read issued certificates, including private key')], max_length=7)), 23 | ('certificate', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='x509_pki.certificate')), 24 | ('owner', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), 25 | ], 26 | options={ 27 | 'ordering': ['owner', 'certificate', 'access'], 28 | 'unique_together': {('owner', 'access', 'certificate')}, 29 | }, 30 | ), 31 | migrations.CreateModel( 32 | name='AuthorisedApp', 33 | fields=[ 34 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 35 | ('name', models.TextField(unique=True)), 36 | ('token', models.TextField(unique=True)), 37 | ('owner', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), 38 | ('scopes', models.ManyToManyField(to='api.scope')), 39 | ], 40 | options={ 41 | 'ordering': ['name'], 42 | }, 43 | ), 44 | ] 45 | -------------------------------------------------------------------------------- /api/migrations/0002_remove_authorisedapp_scopes_delete_scope.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.0.4 on 2022-05-28 06:55 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RemoveField( 14 | model_name='authorisedapp', 15 | name='scopes', 16 | ), 17 | migrations.DeleteModel( 18 | name='Scope', 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /api/migrations/0003_rename_owner_authorisedapp_user.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.0.4 on 2022-05-28 06:58 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0002_remove_authorisedapp_scopes_delete_scope'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RenameField( 14 | model_name='authorisedapp', 15 | old_name='owner', 16 | new_name='user', 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /api/migrations/0004_alter_authorisedapp_name_and_more.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.0.4 on 2022-06-18 22:28 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 11 | ('api', '0003_rename_owner_authorisedapp_user'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='authorisedapp', 17 | name='name', 18 | field=models.TextField(), 19 | ), 20 | migrations.AlterUniqueTogether( 21 | name='authorisedapp', 22 | unique_together={('name', 'user')}, 23 | ), 24 | ] 25 | -------------------------------------------------------------------------------- /api/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/api/migrations/__init__.py -------------------------------------------------------------------------------- /api/mixins.py: -------------------------------------------------------------------------------- 1 | """Create serializer validation errors from django validation errors for automatic handling""" 2 | 3 | from django.core.exceptions import ValidationError as DjangoValidationError 4 | from rest_framework import serializers 5 | 6 | from certificate_engine.ssl.certificate import PolicyError 7 | 8 | 9 | class TrapDjangoValidationErrorCreateMixin(object): 10 | def perform_create(self, serializer): 11 | try: 12 | serializer.save() 13 | except DjangoValidationError as detail: 14 | raise serializers.ValidationError({"non_field_errors": detail.messages}) 15 | except PolicyError as detail: 16 | raise serializers.ValidationError(detail.args[0]) 17 | 18 | 19 | class TrapDjangoValidationErrorUpdateMixin(object): 20 | def perform_update(self, serializer): 21 | try: 22 | serializer.save() 23 | except DjangoValidationError as detail: 24 | raise serializers.ValidationError({"non_field_errors": detail.messages}) 25 | except PolicyError as detail: 26 | raise serializers.ValidationError(detail.args[0]) 27 | -------------------------------------------------------------------------------- /api/models.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import User 2 | from django.db import models 3 | 4 | from api import utils 5 | 6 | 7 | class AuthorisedApp(models.Model): 8 | name = models.TextField() 9 | token = models.TextField(unique=True) 10 | user = models.ForeignKey(User, on_delete=models.PROTECT) 11 | 12 | class Meta: 13 | ordering = ["name"] 14 | unique_together = ("name", "user") 15 | 16 | def save(self, *args, **kwargs): 17 | if not self.id: 18 | self.token = utils.new_token(44) 19 | super(AuthorisedApp, self).save(*args, **kwargs) 20 | 21 | def __str__(self): 22 | return "{} - {}".format(self.name, self.token) 23 | -------------------------------------------------------------------------------- /api/permissions.py: -------------------------------------------------------------------------------- 1 | """Permission classes for retrieving certificates""" 2 | 3 | from rest_framework import permissions 4 | 5 | 6 | class BounCAUserPermissions(permissions.BasePermission): 7 | def has_permission(self, request, view): 8 | if view.action == "list": 9 | return request.user.is_admin 10 | elif view.action == "retrieve": 11 | return True 12 | else: 13 | return False 14 | 15 | def has_object_permission(self, request, view, obj): 16 | if view.action == "retrieve": 17 | return request.user.is_admin or obj == request.user 18 | else: 19 | return False 20 | -------------------------------------------------------------------------------- /api/templates/rest_framework/api.html: -------------------------------------------------------------------------------- 1 | {% extends "rest_framework/base.html" %} 2 | 3 | 4 | {% block title %}BounCA API{% endblock %} 5 | 6 | {% block branding %} 7 | BounCA API 8 | 9 | Admin 10 | 11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /api/templates/rest_framework/login.html: -------------------------------------------------------------------------------- 1 | {% extends "rest_framework/login_base.html" %} 2 | 3 | {% block branding %} 4 |

BounCA API

5 | {% endblock %} 6 | -------------------------------------------------------------------------------- /api/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/api/tests/__init__.py -------------------------------------------------------------------------------- /api/tests/api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/api/tests/api/__init__.py -------------------------------------------------------------------------------- /api/tests/api/auth/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/api/tests/api/auth/__init__.py -------------------------------------------------------------------------------- /api/tests/api/auth/test_auth.py: -------------------------------------------------------------------------------- 1 | from rest_framework import status 2 | from rest_framework.test import APIClient, APITestCase 3 | 4 | 5 | class AuthRegistrationTest(APITestCase): 6 | """ 7 | Test retrieve and creating tokens 8 | """ 9 | 10 | base_url = "/api/v1/reqistration" 11 | 12 | def test_account_email_verification_sent_not_found(self): 13 | client = APIClient() 14 | response = client.get(f"{self.base_url}/account-email-verification-sent/", format="json") 15 | self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) 16 | -------------------------------------------------------------------------------- /api/tests/api/tokens/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/api/tests/api/tokens/__init__.py -------------------------------------------------------------------------------- /api/tests/base.py: -------------------------------------------------------------------------------- 1 | from rest_framework.test import APITestCase 2 | 3 | from api.tests.factories import AuthorisedAppFactory 4 | 5 | 6 | class APITokenLoginTestCase(APITestCase): 7 | """ 8 | APITestCase that uses our AuthorisedApp model token to login. 9 | """ 10 | 11 | @classmethod 12 | def setUpTestData(cls): 13 | cls.auth_app = AuthorisedAppFactory() 14 | 15 | def setUp(self): 16 | self.client.credentials(HTTP_X_AUTH_TOKEN=self.auth_app.token) 17 | 18 | 19 | class APILoginTestCase(APITestCase): 20 | """ 21 | APITestCase that uses credentials to login. 22 | """ 23 | 24 | @classmethod 25 | def setUpTestData(cls): 26 | cls.auth_app = AuthorisedAppFactory() 27 | cls.user = cls.auth_app.user 28 | 29 | def setUp(self): 30 | self.client.login(username=self.user.username, password="password123") 31 | -------------------------------------------------------------------------------- /api/tests/factories.py: -------------------------------------------------------------------------------- 1 | import factory 2 | from django.core.exceptions import ObjectDoesNotExist 3 | from factory.django import DjangoModelFactory 4 | from faker import Factory as FakerFactory 5 | 6 | from api import models, utils 7 | from x509_pki.tests.factories import UserFactory 8 | 9 | fake = FakerFactory.create() 10 | 11 | 12 | class AuthorisedAppFactory(DjangoModelFactory): 13 | class Meta: 14 | model = models.AuthorisedApp 15 | 16 | name = fake.sentence(nb_words=6, variable_nb_words=True) 17 | token = factory.LazyFunction(utils.new_token) 18 | user = factory.LazyFunction(UserFactory.default) 19 | 20 | @classmethod 21 | def default(cls): 22 | try: 23 | authorised_app = models.AuthorisedApp.objects.get(token="aasdfghjkl") 24 | except ObjectDoesNotExist: 25 | authorised_app = AuthorisedAppFactory.create(token="aasdfghjkl") 26 | return authorised_app 27 | -------------------------------------------------------------------------------- /api/tests/test_factories.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | from django.test import TestCase 5 | 6 | from api.tests.factories import AuthorisedAppFactory 7 | 8 | 9 | class FactoriesTest(TestCase): 10 | """ 11 | Very simple tests to ensure the factories work as expected. 12 | """ 13 | 14 | def test_authorised_app_factory(self): 15 | authorised_app = AuthorisedAppFactory() 16 | self.assertTrue(authorised_app.id is not None) 17 | self.assertTrue(len(authorised_app.name) > 1) 18 | self.assertTrue(authorised_app.user is not None) 19 | # Base64 encoding of 16 bit random number 20 | self.assertTrue(len(authorised_app.token) == 44) 21 | -------------------------------------------------------------------------------- /api/tokens/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/api/tokens/__init__.py -------------------------------------------------------------------------------- /api/tokens/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework.serializers import ModelSerializer 2 | 3 | from api.models import AuthorisedApp 4 | 5 | 6 | class AuthorisedAppSerializer(ModelSerializer): 7 | # TODO it is ugly that "user" is visible in the Options of the API. 8 | # But not having it as field, will fail the serializer 9 | # Solution provided in 10 | # https://www.django-rest-framework.org/tutori 11 | # al/4-authentication-and-permissions/#associating-snippets-with-users 12 | # will not work, as we have a unique constraint for user/name. 13 | class Meta: 14 | fields = ("id", "name", "token", "user") 15 | read_only_fields = ("token",) 16 | model = AuthorisedApp 17 | extra_kwargs = {"user": {"required": False}} 18 | -------------------------------------------------------------------------------- /api/tokens/urls.py: -------------------------------------------------------------------------------- 1 | from rest_framework.routers import DefaultRouter 2 | 3 | from api.tokens.views import AuthorisedAppViewSet 4 | 5 | router = DefaultRouter() 6 | router.register(r"tokens", AuthorisedAppViewSet, basename="token") 7 | urlpatterns = router.urls 8 | -------------------------------------------------------------------------------- /api/tokens/views.py: -------------------------------------------------------------------------------- 1 | from copy import deepcopy 2 | 3 | from rest_framework import mixins, status 4 | from rest_framework.permissions import IsAuthenticated 5 | from rest_framework.response import Response 6 | from rest_framework.viewsets import GenericViewSet 7 | 8 | from api.models import AuthorisedApp 9 | from api.tokens.serializers import AuthorisedAppSerializer 10 | from api.views import APIPageNumberPagination 11 | 12 | 13 | class AuthorisedAppViewSet( 14 | mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet 15 | ): 16 | """ 17 | A ViewSet for retrieving tokens. 18 | """ 19 | 20 | serializer_class = AuthorisedAppSerializer 21 | pagination_class = APIPageNumberPagination 22 | permission_classes = [ 23 | IsAuthenticated, 24 | ] 25 | 26 | def get_queryset(self): 27 | return AuthorisedApp.objects.filter(user=self.request.user) 28 | 29 | def create(self, request, *args, **kwargs): 30 | data = deepcopy(request.data) 31 | data["user"] = self.request.user.id 32 | serializer = self.get_serializer(data=data) 33 | 34 | serializer.is_valid(raise_exception=True) 35 | self.perform_create(serializer) 36 | headers = self.get_success_headers(serializer.data) 37 | return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) 38 | -------------------------------------------------------------------------------- /api/urls.py: -------------------------------------------------------------------------------- 1 | """API v1 end-points""" 2 | from dj_rest_auth.registration.urls import urlpatterns as urlpatterns_registration 3 | from dj_rest_auth.urls import urlpatterns as urlpatterns_rest_auth 4 | from django.conf.urls import include 5 | from django.urls import path 6 | from rest_framework_swagger.views import get_swagger_view 7 | 8 | from api.tokens.urls import urlpatterns as urlpatterns_token 9 | 10 | from .views import ( 11 | ApiRoot, 12 | CertificateCRLFilesView, 13 | CertificateFilesView, 14 | CertificateInfoView, 15 | CertificateInstanceView, 16 | CertificateListView, 17 | CertificateRenewView, 18 | NotFoundView, 19 | ) 20 | 21 | 22 | class CertificateCrlFileView: 23 | pass 24 | 25 | 26 | urlpatterns_apiv1 = [ 27 | path("certificates/files/", CertificateFilesView.as_view(), name="certificate-files"), 28 | path("certificates//download", CertificateFilesView.as_view(), name="certificate-download"), 29 | path("certificates//crl", CertificateCRLFilesView.as_view(), name="certificate-crl"), 30 | path("certificates//info", CertificateInfoView.as_view(), name="certificate-info"), 31 | path("certificates//renew", CertificateRenewView.as_view(), name="certificate-renew"), 32 | path("certificates/", CertificateInstanceView.as_view(), name="certificate-instance"), 33 | path("certificates", CertificateListView.as_view(), name="certificates"), 34 | path("auth/", include(urlpatterns_token)), 35 | path("auth/", include(urlpatterns_rest_auth)), 36 | path( 37 | "auth/registration/account-email-verification-sent/", 38 | NotFoundView.as_view(), 39 | name="account_email_verification_sent", 40 | ), 41 | path("auth/registration/", include(urlpatterns_registration)), 42 | ] 43 | 44 | schema_view = get_swagger_view(title="BounCA API") 45 | 46 | 47 | urlpatterns = [ 48 | path("v1/", include(urlpatterns_apiv1)), 49 | path("", ApiRoot.as_view(urlpatterns_apiv1), name="api-root"), 50 | ] 51 | -------------------------------------------------------------------------------- /api/utils.py: -------------------------------------------------------------------------------- 1 | import random 2 | import string 3 | 4 | 5 | def new_token(length=44): 6 | r = random.SystemRandom() 7 | return "".join(r.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for i in range(length)) 8 | -------------------------------------------------------------------------------- /bounca/__init__.py: -------------------------------------------------------------------------------- 1 | from django.utils.version import get_version 2 | 3 | # version types: final, 'alpha', 'beta', 'rc' 4 | 5 | VERSION = (0, 2, 0, "alpha", 0) 6 | 7 | __version__ = get_version(VERSION) 8 | -------------------------------------------------------------------------------- /bounca/management/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/bounca/management/__init__.py -------------------------------------------------------------------------------- /bounca/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/bounca/management/commands/__init__.py -------------------------------------------------------------------------------- /bounca/management/commands/site.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.contrib.sites.models import Site 3 | from django.core.management.base import BaseCommand 4 | 5 | 6 | class Command(BaseCommand): 7 | help = "Creating Site object" 8 | 9 | def add_arguments(self, parser): 10 | parser.add_argument("host", help="Base host URI of frontend") 11 | 12 | def handle(self, *args, **options): 13 | print(f"Setting site Frontend URI to: {options['host']}") 14 | if Site.objects.filter(pk=getattr(settings, "SITE_ID", 1)).exists(): 15 | site = Site.objects.get(pk=getattr(settings, "SITE_ID", 1)) 16 | site.domain = options["host"] 17 | site.name = getattr(settings, "SITE_NAME", "Bounca PKI") 18 | site.save() 19 | else: 20 | Site( 21 | pk=getattr(settings, "SITE_ID", 1), 22 | domain=options["host"], 23 | name=getattr(settings, "SITE_NAME", "Bounca PKI"), 24 | ).save() 25 | -------------------------------------------------------------------------------- /bounca/urls.py: -------------------------------------------------------------------------------- 1 | """Main URL config""" 2 | from dj_rest_auth.registration.views import VerifyEmailView 3 | from django.conf import settings 4 | from django.conf.urls import include 5 | from django.contrib import admin 6 | from django.contrib.staticfiles.urls import staticfiles_urlpatterns 7 | from django.urls import path 8 | from django.views.generic import RedirectView, TemplateView 9 | 10 | from api.urls import urlpatterns as urlpatterns_api 11 | from superuser_signup.views import CreateSuperUserView 12 | 13 | urlpatterns = [ 14 | # these urls are used to generate email content 15 | path("auth/password-reset/confirm//", TemplateView.as_view(), name="password_reset_confirm"), 16 | path("auth/login/", VerifyEmailView.as_view(), name="account_email_verification_sent"), 17 | path("api/", include(urlpatterns_api)), 18 | path("auth-api/", include("rest_framework.urls")), 19 | path("auth/account-confirm-email/", TemplateView.as_view(), name="account_confirm_email"), 20 | ] 21 | 22 | if settings.ADMIN: 23 | urlpatterns += [ 24 | path("admin/", admin.site.urls), 25 | path("grappelli/", include("grappelli.urls")), # grappelli URLS 26 | ] 27 | if settings.SUPERUSER_SIGNUP: 28 | urlpatterns += [ 29 | # Other URL patterns ... 30 | path("accounts/signup/", CreateSuperUserView.as_view(), name="superuser_signup"), 31 | path("accounts/login/", RedirectView.as_view(url="/admin/login"), name="account_login") 32 | # More URL patterns ... 33 | ] 34 | 35 | 36 | urlpatterns += staticfiles_urlpatterns() 37 | -------------------------------------------------------------------------------- /bounca/wsgi.py: -------------------------------------------------------------------------------- 1 | """uWSGI config""" 2 | 3 | import os 4 | 5 | from django.core.wsgi import get_wsgi_application 6 | 7 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "bounca.settings") 8 | 9 | application = get_wsgi_application() 10 | -------------------------------------------------------------------------------- /build-front.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash -ex 2 | 3 | BASEDIR=$(dirname "$0") 4 | VERSION=$(awk '{ sub(/.*\//, ""); print }' <<< "$CI_COMMIT_REF_NAME") 5 | 6 | if [[ $VERSION =~ ^([0-9]\.?)+$ ]]; then 7 | echo "" 8 | else 9 | VERSION="0.0.0-dev" 10 | fi 11 | 12 | echo $VERSION 13 | 14 | cd front 15 | 16 | sed -ri "s|\"version\":\ \"0.0.0-dev\"|\"version\":\ \"$VERSION\"|g" package.json 17 | 18 | # npm modules are already fetched 19 | # npm install --legacy-peer-deps 20 | # When facing error:0308010C:digital envelope routines::unsupported add this export 21 | export NODE_OPTIONS=--openssl-legacy-provider 22 | npm run build --production 23 | 24 | -------------------------------------------------------------------------------- /build-package.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash -ex 2 | 3 | 4 | BASEDIR=$(dirname "$0") 5 | 6 | cd front 7 | rm -rf node_modules public src 8 | rm .babelrc .env .env.production .eslintignore .eslintrc.js .postcssrc.js 9 | rm Makefile README.md babel.config.js package.json vue.config.js 10 | 11 | cd .. 12 | 13 | mkdir -p out/bounca/ 14 | mv api out/bounca/ 15 | mv superuser_signup out/bounca/ 16 | mv bounca out/bounca/ 17 | mv certificate_engine out/bounca/ 18 | mv vuetifyforms out/bounca/ 19 | mv etc out/bounca/ 20 | mv front out/bounca/ 21 | mv logs out/bounca/ 22 | mv x509_pki out/bounca/ 23 | mv manage.py out/bounca/ 24 | mv CONTRIBUTING.md out/bounca/ 25 | mv LICENSE out/bounca/ 26 | mv README.md out/bounca/ 27 | mv changelog.md out/bounca/ 28 | mv requirements.txt out/bounca/ 29 | 30 | tar -czvf "bounca.tar.gz" --owner=0 --group=0 -C out . 31 | -------------------------------------------------------------------------------- /certificate_engine/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/certificate_engine/__init__.py -------------------------------------------------------------------------------- /certificate_engine/apps.py: -------------------------------------------------------------------------------- 1 | """App name""" 2 | 3 | from django.apps import AppConfig 4 | 5 | 6 | class CertificateEngineConfig(AppConfig): 7 | name = "certificate_engine" 8 | -------------------------------------------------------------------------------- /certificate_engine/ssl/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/certificate_engine/ssl/__init__.py -------------------------------------------------------------------------------- /certificate_engine/ssl/info.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | import tempfile 4 | 5 | 6 | def get_certificate_info(crt: str) -> str: 7 | """ 8 | Get Info of certificates 9 | 10 | Arguments: pem - string with certificate 11 | Returns: string 12 | """ 13 | f = tempfile.NamedTemporaryFile(delete=False) 14 | path = f.name 15 | f.write(crt.encode("utf8")) 16 | f.close() 17 | cert_txt = subprocess.check_output(["openssl", "x509", "-text", "-noout", "-in", path]) 18 | os.unlink(path) 19 | return cert_txt.decode("utf8") 20 | 21 | 22 | def get_certificate_fingerprint(crt: str) -> str: 23 | """ 24 | Get Fingerprint of certificates 25 | 26 | Arguments: pem - string with certificate 27 | Returns: string 28 | """ 29 | f = tempfile.NamedTemporaryFile(delete=False) 30 | path = f.name 31 | f.write(crt.encode("utf8")) 32 | f.close() 33 | cert_txt = subprocess.check_output(["openssl", "x509", "-fingerprint", "-sha1", "-noout", "-in", path]) 34 | os.unlink(path) 35 | fingerprint = cert_txt.decode("utf8") 36 | return fingerprint.split("=")[1].strip() 37 | -------------------------------------------------------------------------------- /certificate_engine/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/certificate_engine/tests/__init__.py -------------------------------------------------------------------------------- /certificate_engine/tests/test_ed25519_key.py: -------------------------------------------------------------------------------- 1 | from cryptography.hazmat.primitives.asymmetric import ed25519 2 | from django.test import TestCase 3 | 4 | from certificate_engine.ssl.key import Key 5 | 6 | 7 | class KeyEd25519Test(TestCase): 8 | def test_generate_private_key(self): 9 | keyhandler = Key() 10 | keyhandler.create_key("ed25519", None) 11 | data = b"testdata" 12 | signature = keyhandler.key.sign(data) 13 | pkey = keyhandler.key.public_key() 14 | self.assertIsNotNone(pkey) 15 | # would throw InvalidSignature if not correct 16 | pkey.verify(signature, data) 17 | self.assertIsNotNone(keyhandler.key) 18 | 19 | def test_serialize_keys_passphrase(self): 20 | key = Key() 21 | key.create_key("ed25519", None) 22 | pem = key.serialize("test_store_keys_passphrase") 23 | prvkey = key.load(pem, "test_store_keys_passphrase") 24 | self.assertIsInstance(prvkey.key, ed25519.Ed25519PrivateKey) 25 | 26 | def test_store_keys_no_object(self): 27 | key = Key() 28 | with self.assertRaisesMessage(RuntimeError, "No key object"): 29 | key.serialize("test_store_keys_passphrase") 30 | 31 | def test_store_keys_no_passphrase(self): 32 | key = Key() 33 | key.create_key("ed25519", None) 34 | pem = key.serialize() 35 | key = Key() 36 | prvkey = key.load(pem) 37 | self.assertIsInstance(prvkey.key, ed25519.Ed25519PrivateKey) 38 | 39 | def test_store_keys_wrong_passphrase(self): 40 | key = Key() 41 | key.create_key("ed25519", None) 42 | pem = key.serialize("test_store_keys_wrong_passphrase") 43 | with self.assertRaisesMessage(ValueError, "Bad decrypt. Incorrect password?"): 44 | key.load(pem, "test_store_keys_passphrase") 45 | 46 | def test_check_passphrase_valid(self): 47 | key = Key() 48 | key.create_key("ed25519", None) 49 | pem = key.serialize("check_passphrase") 50 | self.assertTrue(key.check_passphrase(pem, "check_passphrase")) 51 | 52 | def test_check_passphrase_invalid(self): 53 | key = Key() 54 | key.create_key("ed25519", None) 55 | pem = key.serialize("test_check_passphrase_invalid") 56 | self.assertFalse(key.check_passphrase(pem, "check_passphrase")) 57 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | db: 4 | image: postgres:16 5 | environment: 6 | - POSTGRES_DB=bounca 7 | - POSTGRES_USER=bounca 8 | - POSTGRES_PASSWORD=fsRWF2k2k 9 | ports: 10 | - "5432:5432" 11 | 12 | nginx: 13 | image: nginx:1.16.0-alpine 14 | volumes: 15 | - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro 16 | - ./nginx/certs/:/etc/nginx/certs/ 17 | - ./nginx/www/:/var/www/ 18 | 19 | ports: 20 | - "8443:443" 21 | - "8800:80" 22 | command: [nginx-debug, '-g', 'daemon off;'] 23 | 24 | 25 | -------------------------------------------------------------------------------- /docs/source/bounca/contribution.rst: -------------------------------------------------------------------------------- 1 | :header_title: Contribution 2 | 3 | 4 | Contribution 5 | ============ 6 | 7 | Bug Reports & Feature Requests 8 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 9 | 10 | Please use the `issue tracker`_ to report any bugs or file feature requests. 11 | 12 | Contributing 13 | ~~~~~~~~~~~~ 14 | 15 | 1. Create an issue and describe your idea 16 | 2. Create your feature branch (`git checkout -b my-new-feature`) 17 | 3. Commit your changes (`git commit -am 'Add some feature'`) 18 | 4. Publish the branch (`git push origin my-new-feature`) 19 | 5. Create a new Pull Request 20 | 6. Thanks! 21 | 22 | License 23 | ~~~~~~~~~~~ 24 | 25 | Apache License v2 - (c) 2016-2022, Repleo, Amstelveen 26 | 27 | 28 | Maintainers 29 | ~~~~~~~~~~~ 30 | Jeroen Arnoldus (jeroen@repleo.nl) 31 | 32 | BounCA is written and maintained by `Repleo`_, Amsterdam, Holland. 33 | 34 | .. _issue tracker: https://gitlab.com/bounca/bounca/-/issues 35 | .. _Repleo: https://www.repleo.nl 36 | -------------------------------------------------------------------------------- /docs/source/bounca/support.rst: -------------------------------------------------------------------------------- 1 | :header_title: Support 2 | 3 | Support 4 | ======= 5 | 6 | Bugs & Support Issues 7 | ~~~~~~~~~~~~~~~~~~~~~ 8 | 9 | You can file bug reports on our `GitLab issue tracker`_, 10 | 11 | 12 | Reporting Issues 13 | ~~~~~~~~~~~~~~~~ 14 | 15 | When reporting a bug, 16 | please include as much information as possible that will help us solve this issue. 17 | This includes: 18 | 19 | * How to repeat 20 | * Action taken 21 | * Expected result 22 | * Actual result 23 | 24 | 25 | .. _GitLab Issue Tracker: https://gitlab.com/bounca/bounca/-/issues 26 | -------------------------------------------------------------------------------- /docs/source/demo/nginx_client_auth/certs/demo1.client_cert/demo1.key: -------------------------------------------------------------------------------- 1 | -----BEGIN ENCRYPTED PRIVATE KEY----- 2 | MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIkYVqAhozPwwCAggA 3 | MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBDW4f7NHvM5t2Zoo1blnBH2BIIE 4 | 0CZFeDrekk6HVxVWN6xL9ep1qmo8Bwv4omHq8nlIgyf8HZDnKr8jPJ8gs2BqOgzO 5 | YCZSJLPI34a+CHGwNIi9/iYiskotMZ2I88uCYY8SwJ3iVgHcU5RtISykCvleVkkP 6 | bMDzk9L42VHcTJL+APmzvlHPQcwDLGylLRL7RGhhW1clh/U1DTJZrHsJ+hmGJqho 7 | ltpzm2zuFQFFucRUpYNOhgDjXJLRmjvWL6kjqpKVn5wqtsfdPPQed22L+0eEaDFv 8 | y/klrVzmT5IG2aog7lHQt27a/txSC3GXCzxGykBpSHjqHWqDzu6WEkprJeyl1WDy 9 | CnMIE3oORFe47sUH80Zl50jFTltrqndWEC7Mm6JjuOOsHuvUv7S6Kg9+ZnfoMJRz 10 | gT0wFtYaCRrO4MWFEDrd38yJQoEtF5efUQ8fFbzY0NCWDUIooYCVPjTnWZloXdNZ 11 | NZt7eHTnSlH0IZ2lnel3Tu7947CfX8QnBZnA1EIMdqp0d9BM2pvIfH2jCoOsukCx 12 | NDjmNETLMoRt9lRdO2xesnDwo892A78iQVRGc8NgPmJODqFDcGU/PkD7Vnd2kjpK 13 | y/GmMzDt07RfNdpgzj1u3wz5mqMGY3g8AhNmPjPGvrxjasy/0x8CL8iG4mbN9waR 14 | hVQpQCPcCPkxab2lqTR6Wal80o/DgnHUFpc5ixopBmhOw0AsTde/l7gEOp8F/52s 15 | U0x5LbykwkR+K55AJYpNK3qTPnUayblq4qM1nGGlF3KHs2GDrJww/FSzMIW12Ybi 16 | lwUM9QN7a4mjzcvq3+WsQVvHFcYeK2ox0I7VVfs16pXiw950TWoHmBt7e5g/CpkR 17 | 1B+EeAoLBflL33BPmKfCH0zXXu3K3RsGPdeP7VLexuiXgA/8BD7xj3Z9d35fiQPj 18 | +sUSOSytYjOdDVO0NkhZBXr0Z2aN/+tbOaVfDELDHXPr6bq+GAe7wf7d/F4B72NQ 19 | dmiiUgfHJ5XGOpqSd/2Xs3htW5gsl3GH0SenfJYEMxgEgpXwCtPMW9nLgHJ4ZhdS 20 | U3MmNjQVTTp81tssv6kqklAdodIElnsKvO+4EbwOEArb1U2S0PNfBCv0UZPZnPo4 21 | kfBLHHyQsHL7fZ/TUsa+5LhcIOOi2ySW7mdWh0DCtxof5FaiWqglxpO+ynxEheVD 22 | ovJjO3VZxMIqkG5pd4Ayu/G4UPRAIi8lcT/qqH/FjoLwNg2vCs7ny9F18Uf6Tn8c 23 | 7ceoEq/LWGUCx1gB0KgRhrk0o9EC3irEDglVjz7chulldOGS/RupKR4s0taao9wA 24 | yV1/SEPPZsiaeVSqg92wVpL8y5JxHaGg7aZLpgRQ0/V3rMzi+PNBlxdATUhE4Y8g 25 | obsnkUBOd0vBjW+Pzj5SY4HRturLD3VNT0HDAREyP+W13oemHDCJz1z3lO900u37 26 | M2OYuRFKiOwVqH3NBO2Gc02ucO1t4kyH+v6HNxQgrpZCI4DsogcPBsvM+j4hvMCG 27 | F8DFimZzSUuagkvmTA4Jp2b/8xLH9d1BlxqHkPlGqhSVMP0FcwOHUZMTZY0xwrxJ 28 | oMcqZ9mXtQM0y8Y/D4b+YzAr87pRFwlWqva66hgQTK7kONKr56NuOtUSInwvqwpY 29 | Y8OczPVLnE2pFlc9LFWiGTEkHCRao4ckgkG7irbXdUPP 30 | -----END ENCRYPTED PRIVATE KEY----- 31 | -------------------------------------------------------------------------------- /docs/source/demo/nginx_client_auth/certs/demo1.client_cert/demo1.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/demo/nginx_client_auth/certs/demo1.client_cert/demo1.p12 -------------------------------------------------------------------------------- /docs/source/demo/nginx_client_auth/certs/demo1.client_cert/demo1.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 34 | 35xIEFcPq2a3ndt/KeLl4NKnNm7HEA== 35 | -----END CERTIFICATE----- 36 | -------------------------------------------------------------------------------- /docs/source/demo/nginx_client_auth/certs/demo1.client_cert/rootca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 35 | -----END CERTIFICATE----- 36 | -------------------------------------------------------------------------------- /docs/source/demo/nginx_client_auth/certs/demo2.client_cert/demo2.key: -------------------------------------------------------------------------------- 1 | -----BEGIN ENCRYPTED PRIVATE KEY----- 2 | MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIhXLwthICDtACAggA 3 | MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBAmLNwppVm4gJ+EwiKmgBo5BIIE 4 | 0JsK0lnl/3eT+bRbJPbJw40iEHlPLwRhqG3OS7eBw6Cs8G9WBOr/s8JjTks0CXNK 5 | rg1o7am20BtQ+EJXipGuQrJv6JPZ8iWytQwX47VBm0LRM/Oa2kvL6I3qJHN2SYGy 6 | 6aDxcPZHv9K60N964H0yU95CJ7P/e5Qw90BlItyOufYaV0uXWX7ylvJq0KbmYfeH 7 | 2m4ETvTkUVwhsDsLlwtCrZwdg5vVfZF3aHRJ0q1LYbn2aPlhBMj2zvt/LlPB4DDv 8 | 2v8BZNlxDRyKbVC9vAJIfznJiYnV2mCZIVQad982nKPRmrNugGLl/cR/tc4q1F0Q 9 | Do6KRrLOZV2S4f+fZ11CRmMIbPPgcBNIyfOSXLUrcAugbxUBFsRX8qIUGF8V8ehn 10 | iv8pMYa1mwBGrS42srqZjpMlBCQi/XyrubtMdoq2CVZX2GvnxQ85uqUO1qVhZEbI 11 | A5ufEqiGxAW68SK7asa5ir7+wvxDDFbwGPYj8XZ38mvqMjeFpWWEFxIWvx5Rqc89 12 | VOytlHG14LTmh5gT+VmKSCUaL4ImxcmiNzhoeD5L45u+TfUCLV0gr9ES5xq2eGYX 13 | bR3//yAGtKjUTyfFYsDCy00k7ij+uI16zGBTpom5fY6nu0gssf9Vto5pJLFUQ1Uz 14 | cPpUhVPHq7HlKst978tzPUrQAfHA1a7ZbP6sLJhcQEzFRL53pTwHCMuKMMgS4tw6 15 | cuxivaz47OPBKLtxr6ElZtwCtlEn4tKNp5nXyAH3JmByDcHu7EgfUsmnhBI/2Udn 16 | xjO4BWziAeyOekewxJ9cq4njGPaTxQKVEeTsB4aw4T/4mIoihuvsDSP4IyoiSvCo 17 | FvF6ZEpsY2RXutYHAeL0krq0UUugmWciWBC7hVJna0WeO6MYtLv82dkOATwlT0CA 18 | UVJwcwJoqfNVuwkiVNSdSGpirVV/tNBoa7HLCCJ2mNE0oegC3fxm7OJuL5bH3r1t 19 | G5cU91aYl7aIt0x0fydbIYAJ9+t+rGlFnPgE0AaygykDulfqdZigHxXRkKoDs7n3 20 | CcP+8EEC9kclOCVruRgi4V+zkwAXam4ANbLkUwidvjdAUELRnojLM/0D8ghqplId 21 | TssgGg57HgYOMEG/6Q1mOptZXyJFI8A1zn2svm9/f3AkhTqkJP3JoaaXkJeNXsI8 22 | 64DbVHGRFT9RI/00SwAw+bmkqZaUZLzlwEBAE+Lx/cSyWUK/NYsWmm+WFYybX+54 23 | ReK7QEQO7+pPXIOoTcpFGL3Csg4X4bqdqjQU9nx34ZTJ/D9IJ9lW/m+bRthoty2z 24 | pIDb1vIPnsT0abponp7WPlJDe8fccZE3YEDwnu5U8x3vNLKvTI0no/7+o5B7a6z4 25 | /cJFEwRH0n9eJ/riuykQCYon8f4UNRg4RlxPXoG/RXiZ39YndGbWPa2/KZWJmviB 26 | 92jCaB6cy06VYJs6pW/S3C5wEsFVO85pK7ZqWrhGLcVb57y0OvDhrNjQkvIYFXp2 27 | TV1FEN1H2M36iDTFdsJvs0SV8Jf6w+aErm2zEKInSdBVyQEtDyugwaH9Wpd1LF5g 28 | zXxmzfoazmQ7/too4GXW3sYKkAew2UqbICe/OpxKf16sdnQNnu/xpolQlLsbWwv+ 29 | visB0D1qQLy2tEAUXk9UYMcGoFUm5un39ZJI5PWmCJ5o 30 | -----END ENCRYPTED PRIVATE KEY----- 31 | -------------------------------------------------------------------------------- /docs/source/demo/nginx_client_auth/certs/demo2.client_cert/demo2.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/demo/nginx_client_auth/certs/demo2.client_cert/demo2.p12 -------------------------------------------------------------------------------- /docs/source/demo/nginx_client_auth/certs/demo2.client_cert/demo2.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 34 | VJhAWAW2zZ26Z3//Uwmgo79DYxa53w== 35 | -----END CERTIFICATE----- 36 | -------------------------------------------------------------------------------- /docs/source/demo/nginx_client_auth/certs/demo2.client_cert/rootca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 35 | -----END CERTIFICATE----- 36 | -------------------------------------------------------------------------------- /docs/source/demo/nginx_client_auth/certs/int.crl.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN X509 CRL----- 2 | MIIDBjCB7wIBATANBgkqhkiG9w0BAQsFADCBljELMAkGA1UEBhMCTkwxFjAUBgNV 3 | BAgMDU5vb3JkIEhvbGxhbmQxEjAQBgNVBAcMCUFtc3RlcmRhbTEPMA0GA1UECgwG 4 | Qm91bkNBMQswCQYDVQQLDAJJVDEfMB0GA1UEAwwWQm91bkNBIEludGVybWVkaWF0 5 | ZSBDQTEcMBoGCSqGSIb3DQEJARYNY2FAYm91bmNhLm9yZxcNMjExMjI4MTIwMDI0 6 | WhcNMjExMjI5MTMxMjI3WjAkMCICEQCQJoYwx3RDBKri9mPaRLAZFw0yMTEyMjgx 7 | MzEyMjdaMA0GCSqGSIb3DQEBCwUAA4ICAQCgU621d5MxCg92ic3h4DX6///36YA3 8 | ytBtggaS507vK8ejzjWb6D7l9X1iPRwuthpWvThzn4x3QNzoIctt8y+isn2UiBcV 9 | GHMcvyeMXwLcAKaeK61fA3aWn+81qs3K8gew0UdB5HeQK3I/8Yvr+FoF+K4wNIrX 10 | eEgaWE898P33psum96/t9CNZymMBTK4tQlM0pQ6JlC2/gtFCQG4MFYqjjqJqsp/q 11 | LW/ZH5yqCxbjEysf42uAYRG+vdFZuRVYwWYdRj47F+LZLlGCkxaCcKuT2hSQ+CJr 12 | U3QzJuO0cpP+GtGljunERNPutNktCGWx3AHoGOVwvpSkTvSpqHOWCZWMje+X04Vm 13 | vnaAiFltG/KYQwEKugp+R+3lv9khN4cTm503AXJfmun52bQ+Oj/2fSAQZK3u/TIn 14 | 6xJInkEDyoap3+poj4OY2xUgNezBzGMUmmtRCd/yiS4YCD4PBp5qMdzVWtYXSJvi 15 | 9opTWJEMMJp+VOBu3M5CFIzUe7J9ZhOuuUEMZ31fOaeceARt+EtO5jiiP/4dqgm+ 16 | uCjy9btvk03FZKeZFQImU3rBLxdoZB7ZwWYMkAY0lMz5gzcA69lJuPI4BmhrfZeG 17 | EcXNAD0PfniNIXtTPOgwcQDHwe+KkyUdkM2lzssUEBeIWNDAMT3uSSGz6LTK9Hfr 18 | jtjO1tOMK9Fm6g== 19 | -----END X509 CRL----- 20 | -------------------------------------------------------------------------------- /docs/source/demo/nginx_client_auth/certs/localhost.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDyiSV8zlryxBHZ 3 | y5CI3TXOeXxvSLI7pmbsqmha5KPwjB/N4PH1Vfq4mdS6WaqhGoFPan9GZ8okH7AV 4 | 08ALlrifAz6XMLk3qZpYeSJzmz+Ydl3P8Ay82yr9B4SNL+Ze/rIv6MyzIH9iZHnd 5 | a6iqUlL6JSovE6SeqPgheguk2N44lSZq5YOIfN4tUX2oW4GOkPufciMfxXVOb7NM 6 | D8/8bFyibNrZK2PGdGNQs+nFQBVyVLd7zr8thdVAoL3Sm4tzoyYKecz4kpAEXfOz 7 | Wxb2gMYjUL7+EpKdlmRnBm207PiaJ5rONF2D682lnURKraFYWmAdcoFLQB1rqwVN 8 | P4OO2XFTAgMBAAECggEBAKni60FbAlXehWp7rshPuyrf6gvBbideTeYlD2frk/Ih 9 | FP4PPSzOhwrbpijKOj0S5dUNEg3tEajwEVWYt4Lmlne7vBIHbRXSVWz3nOxBqPBQ 10 | qTHIQgPfuWL36x9CmCmeWo44kXo/nzr6impQyRpVBA54De5f4gXI8dXxOUrFJhOW 11 | +PVMAEca/cb3aMZLJrA0s0+zN1BuFAHMsf3uGG6dOApnHoE2VqaHwzRa/kERRFjL 12 | omhQ8E/vh9wROzeFIitpvyFD4EdJx68j+3gi4715ZWh7+HTRhhYjbj5SwJA5UIOw 13 | 2arQFOf3NR4hOJAiZ5cmgBqiarOj1lEI3HRRhZrUdyECgYEA+sROAe5+RGa9TFv4 14 | rlZTTJ9MfohBga9uUppWwtOV0kaaN3fU+3JgBUKLqhfpZl76cpMIFYmxkxRpsfZY 15 | mrHNgmExaTU3rfmxa0UIoCNqllnqwBFp9ENaWjJsLxsRbvIStuLxIAJNpBGB32iW 16 | 56Up2UB/CEcWPqIfU+QZoDYOjqkCgYEA95jeNXxadCf2VMz+intgKTFuIhy7oyPe 17 | rmJVbcPKsSyMiP1mYTU0gzHkHDtYGoaCgNjUn3xTRccG4SliU85QwbmHBIIQTpz7 18 | 3Mg57YEGquhoaSpqCGNZcuQaqGf9/0Al8nnQPaxg77JuRRPno1Q92+wji/zSXL84 19 | 7YJGvvOwKZsCgYBRWg/ohoOGE0KEHC4v+Kdrax54yiFePhhvScytxdCL+AWdyw1Y 20 | SYGnEzCWDM3WPSfItbRgsFvgWDX12vJhtR7zli5ecDpRAXkyUKH8uaChiCglCUEz 21 | UgpkyojYO1LLiFLT7AnHlZe0i01zuc2C9sz9wvOzLsSjqxq4r340wHS2iQKBgQDq 22 | 6Cwajqq6/ZcmCX+OH1OygWU+FAip1URWKpFmnJXX1q5W4iOaIoJ53oHPjzYdpHR4 23 | jj/cOHZBA30xbrQNUvcndT/2NPgHvcTvSUA8Z2fOCsXU0RrcbnXVHTl1gYRoAZJ/ 24 | JLc/bCZkA+O+wg3I1goCd12aWPm0aPA31pwMWuNN9QKBgC476ygz9uoACtEGSa4Q 25 | uarDu292UpBzO/g1ebtsWCUCWCYIrX3KHEFVjJdVuyYcp3f+TAdG/o77DVDAStPT 26 | MwieYxh47waXTgN6R78tRNTTbEeC7A7915w1Lm6ZDDlr8fzy1QQguBfKgf8OqNzd 27 | AkJZvU/SifJP6Zltv8tv/by7 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /docs/source/demo/nginx_client_auth/certs/root.crl.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN X509 CRL----- 2 | MIIDBzCB8AIBATANBgkqhkiG9w0BAQsFADCBlzELMAkGA1UEBhMCTkwxFjAUBgNV 3 | BAgMDU5vb3JkIEhvbGxhbmQxEjAQBgNVBAcMCUFtc3RlcmRhbTEPMA0GA1UECgwG 4 | Qm91bkNBMRcwFQYDVQQLDA5Sb290IEF1dGhvcml0eTEUMBIGA1UEAwwLQm91bkNB 5 | IFJvb3QxHDAaBgkqhkiG9w0BCQEWDWNhQGJvdW5jYS5vcmcXDTIxMTIyNzE3MDg1 6 | M1oXDTIxMTIyOTE1NDUzOVowJDAiAhEA7tEHOpEaTzCK0X7PflUWOBcNMjExMjI4 7 | MTU0NTM5WjANBgkqhkiG9w0BAQsFAAOCAgEAI6Z0D5J/Yae+adtfwwOYG4bYRLv5 8 | dOPjvvrCGmL6xD/9B/EXdEeXcjXrYp+jKwOO7jvJOJwBuuJUvvzILC3Jh/E7bx88 9 | ORauVSIbpqL9OeOdR7doHCX1UudyH7QhLcLsUFr12G7PTGomYC7CHtHg4o0DUmZh 10 | gNRth9yNxsfbfBwAC+PsLQSUULeIz78TwC0O4KO3NnNBgr5iMNbbT+oe+ulx0dJ5 11 | YDFe2C0ilSFue5mvAjSV8UCrAPJdoSElBRluFkadYac02T5vBe/Gm6MQHeA42Fca 12 | 0M7H1X/fnQvc3v8mssHLTr6VaVgY5sAJ02cCbOuKmLLAME9khb3JtVlfeXiEMbRt 13 | d7L/dfMubTSPaud+/zpXIpJfrGi2gI4jg/eOIBihceN3CRNh3qr5i+VhenXD+tsi 14 | Z6Y8EoZvFNBMpCZMqLTl0T0m9CGC/eUSim9Oa+PAHt7brucMzIY9y6jtrt91GifI 15 | wf4vavNTozgwmztfoULhKRkNMIZwWEFU09BvEs05HwQo8SAD++eLQaj1lPJtVQbA 16 | f4AToQo/e9iUnRFk7ki/mQY7mZsAckV2tMxpRC2dbrngC1YlcFDnyxxJYndAh1dL 17 | y/pWRS2cz1yscn7D6RGyT9QKrsGHTe2n7P9AAEnC2jNTe+YpQr82Bq7kNuc82ELz 18 | TjAyCUwArDI3Hm8= 19 | -----END X509 CRL----- 20 | -------------------------------------------------------------------------------- /docs/source/demo/nginx_client_auth/certs/rootca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 35 | -----END CERTIFICATE----- 36 | -------------------------------------------------------------------------------- /docs/source/demo/nginx_client_auth/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | nginx: 4 | image: nginx:1.16.0-alpine 5 | volumes: 6 | - ./nginx.conf:/etc/nginx/nginx.conf:ro 7 | - ./certs/:/etc/nginx/certs/ 8 | - ./www/:/var/www/ 9 | 10 | ports: 11 | - "8443:443" 12 | - "8800:80" 13 | # Run nginx in debug mode to debug SSL issues: 14 | # command: [nginx-debug, '-g', 'daemon off;'] 15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/source/demo/nginx_client_auth/nginx.conf: -------------------------------------------------------------------------------- 1 | events {} 2 | 3 | http{ 4 | server { 5 | listen 80; 6 | server_name localhost; 7 | return 301 https://$server_name:8443$request_uri; 8 | } 9 | 10 | server { 11 | listen 443 ssl; 12 | server_name localhost; 13 | ssl_certificate /etc/nginx/certs/localhost-chain.pem; 14 | ssl_certificate_key /etc/nginx/certs/localhost.key; 15 | 16 | access_log /var/log/nginx/access.log; 17 | error_log /var/log/nginx/error.log debug; 18 | 19 | # curl --cacert rootca.pem --cert demo1.pem --key demo1.key --pass demo1Demo1 https://localhost:8443 20 | # curl --cacert rootca.pem --cert demo2.pem --key demo2.key --pass demo2Demo2 https://localhost:8443 21 | 22 | ssl_client_certificate /etc/nginx/certs/BounCA_Int_Root.intermediate-chain.pem; 23 | ssl_verify_depth 2; 24 | # make verification optional, so we can display a (custom) 403 message to those 25 | # who fail authentication. Option can also be 'on', in that case nging will drop a default error. 26 | ssl_verify_client optional; 27 | 28 | # Concatenate all crls of the chain to one file, in this case the root and intermediate crl 29 | ssl_crl /etc/nginx/certs/root_int.crl; 30 | 31 | # Nginx doesn't check the intermediate certificate, add the following rule to check for the correct intermediate chain 32 | # you can fetch the subject by the following command: openssl x509 -in intermediate.pem -noout -subject 33 | # you can expose the value of $ssl_client_i_dn by adding a header in the location scope: add_header X-debug-message "$ssl_client_i_dn" always; 34 | 35 | if ($ssl_client_i_dn != "emailAddress=ca@bounca.org,CN=BounCA Intermediate CA,OU=IT,O=BounCA,L=Amsterdam,ST=Noord Holland,C=NL") { 36 | return 403; 37 | } 38 | 39 | location / { 40 | 41 | if ($ssl_client_verify != SUCCESS) { 42 | return 403; 43 | } 44 | root /var/www; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /docs/source/demo/nginx_client_auth/www/index.html: -------------------------------------------------------------------------------- 1 |

Hello World - Your Client Certificate is working!!

2 | -------------------------------------------------------------------------------- /docs/source/demo/nginx_ssl/certs/localhost.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDyiSV8zlryxBHZ 3 | y5CI3TXOeXxvSLI7pmbsqmha5KPwjB/N4PH1Vfq4mdS6WaqhGoFPan9GZ8okH7AV 4 | 08ALlrifAz6XMLk3qZpYeSJzmz+Ydl3P8Ay82yr9B4SNL+Ze/rIv6MyzIH9iZHnd 5 | a6iqUlL6JSovE6SeqPgheguk2N44lSZq5YOIfN4tUX2oW4GOkPufciMfxXVOb7NM 6 | D8/8bFyibNrZK2PGdGNQs+nFQBVyVLd7zr8thdVAoL3Sm4tzoyYKecz4kpAEXfOz 7 | Wxb2gMYjUL7+EpKdlmRnBm207PiaJ5rONF2D682lnURKraFYWmAdcoFLQB1rqwVN 8 | P4OO2XFTAgMBAAECggEBAKni60FbAlXehWp7rshPuyrf6gvBbideTeYlD2frk/Ih 9 | FP4PPSzOhwrbpijKOj0S5dUNEg3tEajwEVWYt4Lmlne7vBIHbRXSVWz3nOxBqPBQ 10 | qTHIQgPfuWL36x9CmCmeWo44kXo/nzr6impQyRpVBA54De5f4gXI8dXxOUrFJhOW 11 | +PVMAEca/cb3aMZLJrA0s0+zN1BuFAHMsf3uGG6dOApnHoE2VqaHwzRa/kERRFjL 12 | omhQ8E/vh9wROzeFIitpvyFD4EdJx68j+3gi4715ZWh7+HTRhhYjbj5SwJA5UIOw 13 | 2arQFOf3NR4hOJAiZ5cmgBqiarOj1lEI3HRRhZrUdyECgYEA+sROAe5+RGa9TFv4 14 | rlZTTJ9MfohBga9uUppWwtOV0kaaN3fU+3JgBUKLqhfpZl76cpMIFYmxkxRpsfZY 15 | mrHNgmExaTU3rfmxa0UIoCNqllnqwBFp9ENaWjJsLxsRbvIStuLxIAJNpBGB32iW 16 | 56Up2UB/CEcWPqIfU+QZoDYOjqkCgYEA95jeNXxadCf2VMz+intgKTFuIhy7oyPe 17 | rmJVbcPKsSyMiP1mYTU0gzHkHDtYGoaCgNjUn3xTRccG4SliU85QwbmHBIIQTpz7 18 | 3Mg57YEGquhoaSpqCGNZcuQaqGf9/0Al8nnQPaxg77JuRRPno1Q92+wji/zSXL84 19 | 7YJGvvOwKZsCgYBRWg/ohoOGE0KEHC4v+Kdrax54yiFePhhvScytxdCL+AWdyw1Y 20 | SYGnEzCWDM3WPSfItbRgsFvgWDX12vJhtR7zli5ecDpRAXkyUKH8uaChiCglCUEz 21 | UgpkyojYO1LLiFLT7AnHlZe0i01zuc2C9sz9wvOzLsSjqxq4r340wHS2iQKBgQDq 22 | 6Cwajqq6/ZcmCX+OH1OygWU+FAip1URWKpFmnJXX1q5W4iOaIoJ53oHPjzYdpHR4 23 | jj/cOHZBA30xbrQNUvcndT/2NPgHvcTvSUA8Z2fOCsXU0RrcbnXVHTl1gYRoAZJ/ 24 | JLc/bCZkA+O+wg3I1goCd12aWPm0aPA31pwMWuNN9QKBgC476ygz9uoACtEGSa4Q 25 | uarDu292UpBzO/g1ebtsWCUCWCYIrX3KHEFVjJdVuyYcp3f+TAdG/o77DVDAStPT 26 | MwieYxh47waXTgN6R78tRNTTbEeC7A7915w1Lm6ZDDlr8fzy1QQguBfKgf8OqNzd 27 | AkJZvU/SifJP6Zltv8tv/by7 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /docs/source/demo/nginx_ssl/certs/rootca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 35 | -----END CERTIFICATE----- 36 | -------------------------------------------------------------------------------- /docs/source/demo/nginx_ssl/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | nginx: 4 | image: nginx:1.16.0-alpine 5 | volumes: 6 | - ./nginx.conf:/etc/nginx/nginx.conf:ro 7 | - ./certs/:/etc/nginx/certs/ 8 | - ./www/:/var/www/ 9 | 10 | ports: 11 | - "8443:443" 12 | - "8800:80" 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/source/demo/nginx_ssl/nginx.conf: -------------------------------------------------------------------------------- 1 | events {} 2 | 3 | http{ 4 | server { 5 | listen 80; 6 | server_name localhost; 7 | return 301 https://$server_name:8443$request_uri; 8 | } 9 | 10 | server { 11 | listen 443 ssl; 12 | server_name localhost; 13 | ssl_certificate /etc/nginx/certs/localhost-chain.pem; 14 | ssl_certificate_key /etc/nginx/certs/localhost.key; 15 | 16 | access_log /var/log/nginx/access.log; 17 | error_log /var/log/nginx/error.log info; 18 | 19 | location / { 20 | root /var/www; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /docs/source/demo/nginx_ssl/www/index.html: -------------------------------------------------------------------------------- 1 |

Hello World - SSL connection via BounCA generated certificate

2 | -------------------------------------------------------------------------------- /docs/source/images/BounCA-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/BounCA-logo.png -------------------------------------------------------------------------------- /docs/source/images/generate-ca-certificates/1-empty-root-dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-ca-certificates/1-empty-root-dashboard.png -------------------------------------------------------------------------------- /docs/source/images/generate-ca-certificates/10-inspect-intermediate-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-ca-certificates/10-inspect-intermediate-certificate.png -------------------------------------------------------------------------------- /docs/source/images/generate-ca-certificates/11-inspect-intermediate-certificate-crl-ocsp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-ca-certificates/11-inspect-intermediate-certificate-crl-ocsp.png -------------------------------------------------------------------------------- /docs/source/images/generate-ca-certificates/2-create-root-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-ca-certificates/2-create-root-certificate.png -------------------------------------------------------------------------------- /docs/source/images/generate-ca-certificates/20-install-root-pem-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-ca-certificates/20-install-root-pem-certificate.png -------------------------------------------------------------------------------- /docs/source/images/generate-ca-certificates/20-listed-root-pem-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-ca-certificates/20-listed-root-pem-certificate.png -------------------------------------------------------------------------------- /docs/source/images/generate-ca-certificates/21-inspect-root-pem-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-ca-certificates/21-inspect-root-pem-certificate.png -------------------------------------------------------------------------------- /docs/source/images/generate-ca-certificates/22-trust-root-ca-pem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-ca-certificates/22-trust-root-ca-pem.png -------------------------------------------------------------------------------- /docs/source/images/generate-ca-certificates/24-trusted-self-signed-root-ca-pem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-ca-certificates/24-trusted-self-signed-root-ca-pem.png -------------------------------------------------------------------------------- /docs/source/images/generate-ca-certificates/26-root-ca-is-trusted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-ca-certificates/26-root-ca-is-trusted.png -------------------------------------------------------------------------------- /docs/source/images/generate-ca-certificates/27-generate-app-token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-ca-certificates/27-generate-app-token.png -------------------------------------------------------------------------------- /docs/source/images/generate-ca-certificates/3-create-root-certificate-crl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-ca-certificates/3-create-root-certificate-crl.png -------------------------------------------------------------------------------- /docs/source/images/generate-ca-certificates/4-root-certificate-generated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-ca-certificates/4-root-certificate-generated.png -------------------------------------------------------------------------------- /docs/source/images/generate-ca-certificates/5-inspect-root-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-ca-certificates/5-inspect-root-certificate.png -------------------------------------------------------------------------------- /docs/source/images/generate-ca-certificates/6-inspect-root-certificate-X.509v3-extensions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-ca-certificates/6-inspect-root-certificate-X.509v3-extensions.png -------------------------------------------------------------------------------- /docs/source/images/generate-ca-certificates/7-enter-root-ca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-ca-certificates/7-enter-root-ca.png -------------------------------------------------------------------------------- /docs/source/images/generate-ca-certificates/8-generate-intermediate-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-ca-certificates/8-generate-intermediate-certificate.png -------------------------------------------------------------------------------- /docs/source/images/generate-ca-certificates/9-generate-intermediate-certificate-enter-passphrases.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-ca-certificates/9-generate-intermediate-certificate-enter-passphrases.png -------------------------------------------------------------------------------- /docs/source/images/generate-ca-certificates/9-generated-intermediate-ca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-ca-certificates/9-generated-intermediate-ca.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/12-enter-int-ca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/12-enter-int-ca.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/13-open-client-certificate-create-form.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/13-open-client-certificate-create-form.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/14-fill-in-the-data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/14-fill-in-the-data.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/15-enter-the-passphrase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/15-enter-the-passphrase.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/16-create-a-second-client-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/16-create-a-second-client-certificate.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/17-enter-passphrase-of-second-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/17-enter-passphrase-of-second-certificate.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/18-overview-generated-certificates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/18-overview-generated-certificates.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/20-enter-passphrase-of-intermediate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/20-enter-passphrase-of-intermediate.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/21-revoked-demo2-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/21-revoked-demo2-certificate.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/22-download-intermediate-chain-and-crl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/22-download-intermediate-chain-and-crl.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/31-verify-demo1-2-certificates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/31-verify-demo1-2-certificates.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/32-content-of-intermediate-crl-file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/32-content-of-intermediate-crl-file.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/33-check-revoked-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/33-check-revoked-certificate.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/34-no-client-cert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/34-no-client-cert.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/35-valid-client-cert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/35-valid-client-cert.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/36-revoked-client-cert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/36-revoked-client-cert.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/40-adding-client-certificate-to-keychain-of-macOS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/40-adding-client-certificate-to-keychain-of-macOS.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/41-added-client-certificate-to-keychain-of-macOS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/41-added-client-certificate-to-keychain-of-macOS.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/42-inspect-client-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/42-inspect-client-certificate.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/43-visit-mTLS-site-safari.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/43-visit-mTLS-site-safari.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/44-granted-mTLS-safari.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/44-granted-mTLS-safari.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/45-visit-mTLS-chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/45-visit-mTLS-chrome.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/46-granted-mTLS-chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/46-granted-mTLS-chrome.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/47-certificate-management-firefox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/47-certificate-management-firefox.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/48-import-pkcs12-in-firefox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/48-import-pkcs12-in-firefox.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/49-client-certificate-added-in-firefox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/49-client-certificate-added-in-firefox.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/50-visit-mTLS-firefox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/50-visit-mTLS-firefox.png -------------------------------------------------------------------------------- /docs/source/images/generate-client-certificate/51-granted-mTLS-firefox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-client-certificate/51-granted-mTLS-firefox.png -------------------------------------------------------------------------------- /docs/source/images/generate-mail-certificate/12-enter-int-ca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-mail-certificate/12-enter-int-ca.png -------------------------------------------------------------------------------- /docs/source/images/generate-mail-certificate/14-fill-in-the-data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-mail-certificate/14-fill-in-the-data.png -------------------------------------------------------------------------------- /docs/source/images/generate-mail-certificate/15-enter-the-passphrase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-mail-certificate/15-enter-the-passphrase.png -------------------------------------------------------------------------------- /docs/source/images/generate-mail-certificate/16-generated-smime-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-mail-certificate/16-generated-smime-certificate.png -------------------------------------------------------------------------------- /docs/source/images/generate-mail-certificate/17-inspect-subject-client-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-mail-certificate/17-inspect-subject-client-certificate.png -------------------------------------------------------------------------------- /docs/source/images/generate-mail-certificate/18-inspect-subject-alt-names-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-mail-certificate/18-inspect-subject-alt-names-certificate.png -------------------------------------------------------------------------------- /docs/source/images/generate-mail-certificate/19-install-client-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-mail-certificate/19-install-client-certificate.png -------------------------------------------------------------------------------- /docs/source/images/generate-mail-certificate/20-create-signed-mail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-mail-certificate/20-create-signed-mail.png -------------------------------------------------------------------------------- /docs/source/images/generate-mail-certificate/21-received-signed-mail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-mail-certificate/21-received-signed-mail.png -------------------------------------------------------------------------------- /docs/source/images/generate-mail-certificate/22-received-signed-mail-thunderbird-not-trusted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-mail-certificate/22-received-signed-mail-thunderbird-not-trusted.png -------------------------------------------------------------------------------- /docs/source/images/generate-mail-certificate/23-add-root-certificate-thunderbird.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-mail-certificate/23-add-root-certificate-thunderbird.png -------------------------------------------------------------------------------- /docs/source/images/generate-mail-certificate/24-trust-root-certificate-thunderbird.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-mail-certificate/24-trust-root-certificate-thunderbird.png -------------------------------------------------------------------------------- /docs/source/images/generate-mail-certificate/25-received-signed-mail-trusted-thunderbird.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-mail-certificate/25-received-signed-mail-trusted-thunderbird.png -------------------------------------------------------------------------------- /docs/source/images/generate-mail-certificate/26-add-client-certificate-to-thunderbird.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-mail-certificate/26-add-client-certificate-to-thunderbird.png -------------------------------------------------------------------------------- /docs/source/images/generate-mail-certificate/27-select-p12-file-thunderbird.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-mail-certificate/27-select-p12-file-thunderbird.png -------------------------------------------------------------------------------- /docs/source/images/generate-mail-certificate/28-client-certificate-added-thunderbird.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-mail-certificate/28-client-certificate-added-thunderbird.png -------------------------------------------------------------------------------- /docs/source/images/generate-mail-certificate/29-select-client-certificate-to-sign-and-encrypt-mail-thunderbird.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-mail-certificate/29-select-client-certificate-to-sign-and-encrypt-mail-thunderbird.png -------------------------------------------------------------------------------- /docs/source/images/generate-mail-certificate/30-client-certificate-configured-thunderbird.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-mail-certificate/30-client-certificate-configured-thunderbird.png -------------------------------------------------------------------------------- /docs/source/images/generate-mail-certificate/31-send-signed-mail-thunderbird.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-mail-certificate/31-send-signed-mail-thunderbird.png -------------------------------------------------------------------------------- /docs/source/images/generate-mail-certificate/32-send-encrypted-mail-Mail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-mail-certificate/32-send-encrypted-mail-Mail.png -------------------------------------------------------------------------------- /docs/source/images/generate-mail-certificate/33-received-encrypted-mail-Firefox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-mail-certificate/33-received-encrypted-mail-Firefox.png -------------------------------------------------------------------------------- /docs/source/images/generate-server-certificate/12-enter-int-ca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-server-certificate/12-enter-int-ca.png -------------------------------------------------------------------------------- /docs/source/images/generate-server-certificate/13-copy-data-from-intermediate-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-server-certificate/13-copy-data-from-intermediate-certificate.png -------------------------------------------------------------------------------- /docs/source/images/generate-server-certificate/13-create-ssl-server-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-server-certificate/13-create-ssl-server-certificate.png -------------------------------------------------------------------------------- /docs/source/images/generate-server-certificate/14-enter-passphrase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-server-certificate/14-enter-passphrase.png -------------------------------------------------------------------------------- /docs/source/images/generate-server-certificate/14-enter-subject-alternative-names.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-server-certificate/14-enter-subject-alternative-names.png -------------------------------------------------------------------------------- /docs/source/images/generate-server-certificate/15-inspect-server-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-server-certificate/15-inspect-server-certificate.png -------------------------------------------------------------------------------- /docs/source/images/generate-server-certificate/15-server-certificate-generated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-server-certificate/15-server-certificate-generated.png -------------------------------------------------------------------------------- /docs/source/images/generate-server-certificate/16-inspect-server-certificate-crl-ocsp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-server-certificate/16-inspect-server-certificate-crl-ocsp.png -------------------------------------------------------------------------------- /docs/source/images/generate-server-certificate/18-ssl-certificate-zip-package.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-server-certificate/18-ssl-certificate-zip-package.png -------------------------------------------------------------------------------- /docs/source/images/generate-server-certificate/19-check-ssl-certificate-chain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-server-certificate/19-check-ssl-certificate-chain.png -------------------------------------------------------------------------------- /docs/source/images/generate-server-certificate/26-root-ca-is-trusted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-server-certificate/26-root-ca-is-trusted.png -------------------------------------------------------------------------------- /docs/source/images/generate-server-certificate/28-visit-website-trusted-ssl-connection-https.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-server-certificate/28-visit-website-trusted-ssl-connection-https.png -------------------------------------------------------------------------------- /docs/source/images/generate-server-certificate/30-renew-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-server-certificate/30-renew-certificate.png -------------------------------------------------------------------------------- /docs/source/images/generate-server-certificate/31-renew-certificate-form.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-server-certificate/31-renew-certificate-form.png -------------------------------------------------------------------------------- /docs/source/images/generate-server-certificate/32-certificate-renewed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/generate-server-certificate/32-certificate-renewed.png -------------------------------------------------------------------------------- /docs/source/images/hex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/hex.png -------------------------------------------------------------------------------- /docs/source/images/hexa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/hexa.png -------------------------------------------------------------------------------- /docs/source/images/ico/android-chrome-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/android-chrome-144x144.png -------------------------------------------------------------------------------- /docs/source/images/ico/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/android-chrome-192x192.png -------------------------------------------------------------------------------- /docs/source/images/ico/android-chrome-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/android-chrome-36x36.png -------------------------------------------------------------------------------- /docs/source/images/ico/android-chrome-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/android-chrome-48x48.png -------------------------------------------------------------------------------- /docs/source/images/ico/android-chrome-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/android-chrome-72x72.png -------------------------------------------------------------------------------- /docs/source/images/ico/android-chrome-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/android-chrome-96x96.png -------------------------------------------------------------------------------- /docs/source/images/ico/apple-touch-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/apple-touch-icon-114x114.png -------------------------------------------------------------------------------- /docs/source/images/ico/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /docs/source/images/ico/apple-touch-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/apple-touch-icon-144x144.png -------------------------------------------------------------------------------- /docs/source/images/ico/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /docs/source/images/ico/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /docs/source/images/ico/apple-touch-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/apple-touch-icon-57x57.png -------------------------------------------------------------------------------- /docs/source/images/ico/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /docs/source/images/ico/apple-touch-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/apple-touch-icon-72x72.png -------------------------------------------------------------------------------- /docs/source/images/ico/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /docs/source/images/ico/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /docs/source/images/ico/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/apple-touch-icon.png -------------------------------------------------------------------------------- /docs/source/images/ico/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | #da532c 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/source/images/ico/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/favicon-16x16.png -------------------------------------------------------------------------------- /docs/source/images/ico/favicon-194x194.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/favicon-194x194.png -------------------------------------------------------------------------------- /docs/source/images/ico/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/favicon-32x32.png -------------------------------------------------------------------------------- /docs/source/images/ico/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/favicon-96x96.png -------------------------------------------------------------------------------- /docs/source/images/ico/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/favicon.ico -------------------------------------------------------------------------------- /docs/source/images/ico/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "BounCA", 3 | "icons": [ 4 | { 5 | "src": "\/static\/bounca\/img\/ico\/android-chrome-36x36.png", 6 | "sizes": "36x36", 7 | "type": "image\/png", 8 | "density": 0.75 9 | }, 10 | { 11 | "src": "\/static\/bounca\/img\/ico\/android-chrome-48x48.png", 12 | "sizes": "48x48", 13 | "type": "image\/png", 14 | "density": 1 15 | }, 16 | { 17 | "src": "\/static\/bounca\/img\/ico\/android-chrome-72x72.png", 18 | "sizes": "72x72", 19 | "type": "image\/png", 20 | "density": 1.5 21 | }, 22 | { 23 | "src": "\/static\/bounca\/img\/ico\/android-chrome-96x96.png", 24 | "sizes": "96x96", 25 | "type": "image\/png", 26 | "density": 2 27 | }, 28 | { 29 | "src": "\/static\/bounca\/img\/ico\/android-chrome-144x144.png", 30 | "sizes": "144x144", 31 | "type": "image\/png", 32 | "density": 3 33 | }, 34 | { 35 | "src": "\/static\/bounca\/img\/ico\/android-chrome-192x192.png", 36 | "sizes": "192x192", 37 | "type": "image\/png", 38 | "density": 4 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /docs/source/images/ico/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/mstile-144x144.png -------------------------------------------------------------------------------- /docs/source/images/ico/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/mstile-150x150.png -------------------------------------------------------------------------------- /docs/source/images/ico/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/mstile-310x150.png -------------------------------------------------------------------------------- /docs/source/images/ico/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/mstile-310x310.png -------------------------------------------------------------------------------- /docs/source/images/ico/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/ico/mstile-70x70.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/1_chrome_open_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/1_chrome_open_settings.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/1_firefox_open_settings_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/1_firefox_open_settings_page.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/20-install-root-pem-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/20-install-root-pem-certificate.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/20-listed-root-pem-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/20-listed-root-pem-certificate.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/21-inspect-root-pem-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/21-inspect-root-pem-certificate.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/22-trust-root-ca-pem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/22-trust-root-ca-pem.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/24-trusted-self-signed-root-ca-pem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/24-trusted-self-signed-root-ca-pem.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/26-root-ca-is-trusted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/26-root-ca-is-trusted.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/2_chrome_click_on_advanced_settings_and_go_to_certificates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/2_chrome_click_on_advanced_settings_and_go_to_certificates.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/2_firefox_click_on_advanced_settings_and_go_to_certificates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/2_firefox_click_on_advanced_settings_and_go_to_certificates.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/3_chrome_click_on_authorities_and_press_import_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/3_chrome_click_on_authorities_and_press_import_button.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/3_firefox_import_the_root_certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/3_firefox_import_the_root_certificate.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/4_chrome_select_the_root_certificate_file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/4_chrome_select_the_root_certificate_file.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/4_firefox_select_the_root_certificate_file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/4_firefox_select_the_root_certificate_file.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/5_chrome_add_the_certificate_and_select_trust_rules.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/5_chrome_add_the_certificate_and_select_trust_rules.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/5_firefox_select_the_trust_rules.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/5_firefox_select_the_trust_rules.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/6_chrome_certificate_is_added_to_authorities_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/6_chrome_certificate_is_added_to_authorities_list.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/6_firefox_the_root_certificate_has_been_added.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/6_firefox_the_root_certificate_has_been_added.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/7_chrome_inspect_the_certificate_by_clicking_on_view_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/7_chrome_inspect_the_certificate_by_clicking_on_view_button.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/7_firefox_inspect_the_root_certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/7_firefox_inspect_the_root_certificate.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/8_chrome_visit_self-signed_website_and_verify_it_is_trusted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/8_chrome_visit_self-signed_website_and_verify_it_is_trusted.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/8_firefox_visit_self-signed_website_and_verify_it_is_trusted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/8_firefox_visit_self-signed_website_and_verify_it_is_trusted.png -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/ios_certificate_installed.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/ios_certificate_installed.jpg -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/ios_open_certificate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/ios_open_certificate.jpg -------------------------------------------------------------------------------- /docs/source/images/install_root_certificate/ios_trust_new_certificate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/install_root_certificate/ios_trust_new_certificate.jpg -------------------------------------------------------------------------------- /docs/source/images/main/bounca/adding_new_intermediate_certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/main/bounca/adding_new_intermediate_certificate.png -------------------------------------------------------------------------------- /docs/source/images/main/bounca/client_server_certificate_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/main/bounca/client_server_certificate_overview.png -------------------------------------------------------------------------------- /docs/source/images/main/bounca/intermediate_certificate_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/main/bounca/intermediate_certificate_overview.png -------------------------------------------------------------------------------- /docs/source/images/main/bounca/revoke_certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/main/bounca/revoke_certificate.png -------------------------------------------------------------------------------- /docs/source/images/main/bounca/revoked_certificate_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/main/bounca/revoked_certificate_overview.png -------------------------------------------------------------------------------- /docs/source/images/main/bounca/root_ca_dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/main/bounca/root_ca_dashboard.png -------------------------------------------------------------------------------- /docs/source/images/main/bounca/root_certificate_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/main/bounca/root_certificate_info.png -------------------------------------------------------------------------------- /docs/source/images/main/bounca/ssl_dashboard_bounca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/main/bounca/ssl_dashboard_bounca.png -------------------------------------------------------------------------------- /docs/source/images/main/bounca/validated_certificate_chain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/main/bounca/validated_certificate_chain.png -------------------------------------------------------------------------------- /docs/source/images/main/create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/main/create.png -------------------------------------------------------------------------------- /docs/source/images/main/easy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/main/easy.png -------------------------------------------------------------------------------- /docs/source/images/main/integrate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/main/integrate.png -------------------------------------------------------------------------------- /docs/source/images/main/manage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/main/manage.png -------------------------------------------------------------------------------- /docs/source/images/main/private.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/main/private.png -------------------------------------------------------------------------------- /docs/source/images/main/triangulated_grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/main/triangulated_grid.png -------------------------------------------------------------------------------- /docs/source/images/main/world.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/main/world.png -------------------------------------------------------------------------------- /docs/source/images/readme/ssl_dashboard_bounca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/readme/ssl_dashboard_bounca.png -------------------------------------------------------------------------------- /docs/source/images/vpn-configuration/12-enter-int-ca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/vpn-configuration/12-enter-int-ca.png -------------------------------------------------------------------------------- /docs/source/images/vpn-configuration/13-create-openvpn-server-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/vpn-configuration/13-create-openvpn-server-certificate.png -------------------------------------------------------------------------------- /docs/source/images/vpn-configuration/14-passphrase-openvpn-server-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/vpn-configuration/14-passphrase-openvpn-server-certificate.png -------------------------------------------------------------------------------- /docs/source/images/vpn-configuration/15-generate-dh-params.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/vpn-configuration/15-generate-dh-params.png -------------------------------------------------------------------------------- /docs/source/images/vpn-configuration/20-create-openvpn-client-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/vpn-configuration/20-create-openvpn-client-certificate.png -------------------------------------------------------------------------------- /docs/source/images/vpn-configuration/20-passphrase-openvpn-client-certificate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/vpn-configuration/20-passphrase-openvpn-client-certificate.png -------------------------------------------------------------------------------- /docs/source/images/vpn-configuration/31-OpenVPN-dashboard-OpenWRT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/vpn-configuration/31-OpenVPN-dashboard-OpenWRT.png -------------------------------------------------------------------------------- /docs/source/images/vpn-configuration/32-Demo-VPN-uploaded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/vpn-configuration/32-Demo-VPN-uploaded.png -------------------------------------------------------------------------------- /docs/source/images/vpn-configuration/33-Inspect-config-Demo-VPN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/vpn-configuration/33-Inspect-config-Demo-VPN.png -------------------------------------------------------------------------------- /docs/source/images/vpn-configuration/34-Save-Apply-and-start-Demo-VPN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/vpn-configuration/34-Save-Apply-and-start-Demo-VPN.png -------------------------------------------------------------------------------- /docs/source/images/vpn-configuration/35-Add-firewall-rule-accepting-UDP-OpenVPN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/vpn-configuration/35-Add-firewall-rule-accepting-UDP-OpenVPN.png -------------------------------------------------------------------------------- /docs/source/images/vpn-configuration/36-Allow-tun-interface-in-local-LAN-zone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/vpn-configuration/36-Allow-tun-interface-in-local-LAN-zone.png -------------------------------------------------------------------------------- /docs/source/images/vpn-configuration/36a-Allow-tun-interface-in-local-LAN-zone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/vpn-configuration/36a-Allow-tun-interface-in-local-LAN-zone.png -------------------------------------------------------------------------------- /docs/source/images/vpn-configuration/40-import-ovpn-file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/vpn-configuration/40-import-ovpn-file.png -------------------------------------------------------------------------------- /docs/source/images/vpn-configuration/41-imported-profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/vpn-configuration/41-imported-profile.png -------------------------------------------------------------------------------- /docs/source/images/vpn-configuration/42-disconnected-profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/vpn-configuration/42-disconnected-profile.png -------------------------------------------------------------------------------- /docs/source/images/vpn-configuration/43-enter-passphrase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/vpn-configuration/43-enter-passphrase.png -------------------------------------------------------------------------------- /docs/source/images/vpn-configuration/44-connected-vpn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/vpn-configuration/44-connected-vpn.png -------------------------------------------------------------------------------- /docs/source/images/vpn-configuration/45-browse-to-internal-network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/docs/source/images/vpn-configuration/45-browse-to-internal-network.png -------------------------------------------------------------------------------- /docs/source/include_files.rst: -------------------------------------------------------------------------------- 1 | :header_title: Include files 2 | 3 | .. image:: images/main/bounca/revoked_certificate_overview.png 4 | 5 | .. image:: images/main/bounca/client_server_certificate_overview.png 6 | 7 | .. image:: images/main/bounca/adding_new_intermediate_certificate.png 8 | 9 | .. image:: images/main/bounca/intermediate_certificate_overview.png 10 | 11 | .. image:: images/main/bounca/validated_certificate_chain.png 12 | 13 | .. image:: images/main/bounca/root_certificate_info.png 14 | 15 | .. image:: images/main/bounca/root_ca_dashboard.png 16 | 17 | .. image:: images/main/integrate.png 18 | 19 | .. image:: images/main/manage.png 20 | 21 | .. image:: images/main/create.png 22 | 23 | .. image:: images/readme/ssl_dashboard_bounca.png 24 | 25 | .. image:: images/BounCA-logo.png 26 | 27 | .. image:: images/hex.png 28 | 29 | 30 | .. image:: images/ico/apple-touch-icon-57x57.png 31 | 32 | .. image:: images/ico/apple-touch-icon-60x60.png 33 | 34 | .. image:: images/ico/apple-touch-icon-72x72.png 35 | 36 | .. image:: images/ico/apple-touch-icon-76x76.png 37 | 38 | .. image:: images/ico/apple-touch-icon-114x114.png 39 | 40 | .. image:: images/ico/apple-touch-icon-120x120.png 41 | 42 | .. image:: images/ico/apple-touch-icon-144x144.png 43 | 44 | .. image:: images/ico/apple-touch-icon-152x152.png 45 | 46 | .. image:: images/ico/apple-touch-icon-180x180.png 47 | 48 | .. image:: images/ico/favicon-32x32.png 49 | 50 | .. image:: images/ico/android-chrome-192x192.png 51 | 52 | .. image:: images/ico/favicon-96x96.png 53 | 54 | .. image:: images/ico/favicon-16x16.png 55 | 56 | .. image:: images/ico/manifest.json 57 | 58 | .. image:: images/ico/safari-pinned-tab.svg 59 | 60 | .. image:: images/ico/favicon.ico 61 | 62 | .. image:: images/ico/mstile-144x144.png 63 | 64 | .. image:: images/ico/browserconfig.xml 65 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | :launchpage: 2 | 3 | 4 | Site structure 5 | ============== 6 | 7 | 8 | .. _install-docs: 9 | 10 | .. toctree:: 11 | :maxdepth: 2 12 | :caption: Getting Started 13 | 14 | getting_started 15 | 16 | 17 | .. _tutorial-docs: 18 | 19 | .. toctree:: 20 | :maxdepth: 2 21 | :glob: 22 | :caption: Tutorials 23 | 24 | tutorials/create_certificate_authority 25 | tutorials/install_root_certificate 26 | tutorials/create_server_certificate_webserver 27 | tutorials/create_client_certificate_browser 28 | tutorials/create_mail_certificate 29 | tutorials/vpn_configuration 30 | 31 | .. _about-docs: 32 | 33 | .. toctree:: 34 | :maxdepth: 2 35 | :glob: 36 | :caption: About 37 | 38 | bounca/features 39 | bounca/contribution 40 | bounca/support 41 | 42 | 43 | -------------------------------------------------------------------------------- /etc/bounca/services.yaml.example: -------------------------------------------------------------------------------- 1 | psql: 2 | dbname: bounca 3 | username: bounca 4 | # CHANGE: replace this value with your secret 5 | password: changeit 6 | host: postgres 7 | port: 5432 8 | 9 | admin: 10 | enabled: True 11 | superuser_signup: True 12 | 13 | django: 14 | debug: False 15 | # CHANGE: replace this value with your secret 16 | secret_key: '' 17 | hosts: 18 | # CHANGE: add your hosts here 19 | # - my_ca.my_domain.tld 20 | - localhost 21 | - 127.0.0.1 22 | 23 | mail: 24 | host: localhost 25 | # port: 587 optionally, only for tls and ssl 26 | # username: 27 | # password: 28 | # connection: none # allowed values: none, tls, ssl 29 | admin: admin@example.com 30 | from: no-reply@example.com 31 | 32 | certificate-engine: 33 | # allowed values: ed25519, rsa 34 | # Ed25519 is a a modern, fast and safe key algorithm, however not supported by all operating systems, like MacOS. 35 | # Keep the 'rsa' option if unsure. Root and intermediate keys are 4096 bits, client and server certificates 36 | # use 2048 bits keys. 37 | key_algorithm: rsa 38 | 39 | registration: 40 | # allowed values: mandatory, optional, off 41 | email_verification: off 42 | -------------------------------------------------------------------------------- /etc/nginx/bounca: -------------------------------------------------------------------------------- 1 | # CHANGE enable in case of SSL 2 | #server { 3 | # listen 80; 4 | # listen [::]:80; 5 | # server_name bounca; # Replace with your domain 6 | # return 301 https://$http_host$request_uri; 7 | # access_log /var/log/nginx/bounca-access.log; 8 | # error_log /var/log/nginx/bounca-error.log; 9 | #} 10 | 11 | server { 12 | 13 | access_log /var/log/nginx/bounca-access.log; 14 | error_log /var/log/nginx/bounca-error.log; 15 | 16 | # configuration for local hosting non-ssl 17 | listen 80; 18 | listen [::]:80; 19 | 20 | # CHANGE in case you want to configure SSL and disable the listen lines above 21 | # ssl enabled 22 | # listen 443 ssl; 23 | # listen [::]:443 ssl; 24 | # ssl_certificate /etc/nginx/ssl/fullchain.pem; 25 | # ssl_certificate_key /etc/nginx/ssl/privkey.pem; 26 | 27 | server_name bounca; # CHANGE Replace with your domain 28 | 29 | location /static { 30 | root /srv/www/bounca/media; 31 | include mime.types; 32 | } 33 | location /api { 34 | include uwsgi_params; 35 | uwsgi_read_timeout 9600; 36 | uwsgi_send_timeout 9600; 37 | uwsgi_pass unix://run/uwsgi/app/bounca/socket; 38 | } 39 | location /admin { 40 | include uwsgi_params; 41 | uwsgi_read_timeout 9600; 42 | uwsgi_send_timeout 9600; 43 | uwsgi_pass unix://run/uwsgi/app/bounca/socket; 44 | } 45 | location / { 46 | root /srv/www/bounca/front/dist; 47 | include mime.types; 48 | try_files $uri $uri/ /index.html; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /etc/uwsgi/bounca.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | thread=4 3 | master=1 4 | processes=8 5 | vacuum=true 6 | uid = www-data 7 | gid = www-data 8 | chmod-socket = 700 9 | chown-socket = www-data 10 | socket = /run/uwsgi/app/bounca/socket 11 | logto = /var/log/uwsgi/bounca.log 12 | chdir = /srv/www/bounca 13 | home = /srv/www/bounca/env 14 | module = bounca.wsgi:application 15 | plugins = python3 16 | 17 | env = DJANGO_SETTINGS_MODULE=bounca.settings 18 | -------------------------------------------------------------------------------- /front/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /front/.env: -------------------------------------------------------------------------------- 1 | VUE_APP_ROOT_API = 'http://localhost:8000' 2 | -------------------------------------------------------------------------------- /front/.env.production: -------------------------------------------------------------------------------- 1 | VUE_APP_ROOT_API = '' 2 | -------------------------------------------------------------------------------- /front/.eslintignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /config/ 3 | /dist/ 4 | /test/unit/coverage/ 5 | /src/components/forms/* 6 | -------------------------------------------------------------------------------- /front/.eslintrc.js: -------------------------------------------------------------------------------- 1 | // https://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parserOptions: { 6 | parser: 'babel-eslint', 7 | }, 8 | env: { 9 | browser: true, 10 | }, 11 | // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention 12 | // consider switching to `plugin:vue/strongly-recommended` or 13 | // `plugin:vue/recommended` for stricter rules. 14 | extends: ['plugin:vue/essential', 'airbnb-base'], 15 | // required to lint *.vue files 16 | plugins: [ 17 | 'vue', 18 | ], 19 | 20 | // add your custom rules here 21 | rules: { 22 | // In an arrow function, this does not refer to the owner of the function. 23 | // https://michaelnthiessen.com/this-is-undefined/ 24 | 'object-shorthand': 'off', 25 | // don't require .vue extension when importing 26 | 'import/extensions': ['error', 'always', { 27 | js: 'never', 28 | vue: 'never', 29 | }], 30 | // disallow reassignment of function parameters 31 | // disallow parameter object manipulation except for specific exclusions 32 | 'no-param-reassign': ['error', { 33 | props: true, 34 | ignorePropertyModificationsFor: [ 35 | 'state', // for vuex state 36 | 'acc', // for reduce accumulators 37 | 'e', // for e.returnvalue 38 | ], 39 | }], 40 | // allow optionalDependencies 41 | // 'import/no-extraneous-dependencies': ['error', { 42 | // optionalDependencies: ['test/unit/index.js'] 43 | // }], 44 | // allow debugger during development 45 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', 46 | }, 47 | }; 48 | -------------------------------------------------------------------------------- /front/.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | plugins: { 5 | 'postcss-import': {}, 6 | 'postcss-url': {}, 7 | // to edit target browsers: use "browserslist" field in package.json 8 | autoprefixer: {}, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /front/Makefile: -------------------------------------------------------------------------------- 1 | runserver: 2 | npm run serve 3 | 4 | build: 5 | npm run build 6 | 7 | production: 8 | npm run build --production 9 | -------------------------------------------------------------------------------- /front/README.md: -------------------------------------------------------------------------------- 1 | # Bounca webapp frontend 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | npm run lint 21 | ``` 22 | -------------------------------------------------------------------------------- /front/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset', 4 | ], 5 | }; 6 | -------------------------------------------------------------------------------- /front/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "front", 3 | "version": "0.0.0-dev", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "@mdi/font": "^6.5.95", 12 | "@vue/cli-service-global": "^4.5.15", 13 | "axios": "^0.25.0", 14 | "babel-preset-stage-2": "^6.24.1", 15 | "bootstrap": "^4.6.1", 16 | "bootstrap-vue": "^2.21.2", 17 | "core-js": "^3.19.1", 18 | "jquery": "^3.6.0", 19 | "lodash": "^4.17.21", 20 | "material-design-icons-iconfont": "^6.1.1", 21 | "typeface-roboto": "^1.1.13", 22 | "vee-validate": "^3.4.14", 23 | "vue": "^2.6.14", 24 | "vue-cookie": "^1.1.4", 25 | "vue-meta": "^2.4.0", 26 | "vue-router": "^3.5.3", 27 | "vuetify": "^2.6.3", 28 | "vuex": "^3.6.2" 29 | }, 30 | "devDependencies": { 31 | "@vue/cli-plugin-babel": "^5.0.0-rc.3", 32 | "@vue/cli-plugin-eslint": "~v5.0.0-alpha.7", 33 | "@vue/cli-service": "^4.5.15", 34 | "babel-core": "^6.22.1", 35 | "babel-eslint": "^8.2.1", 36 | "babel-helper-vue-jsx-merge-props": "^2.0.3", 37 | "babel-loader": "^8.2.3", 38 | "babel-plugin-istanbul": "^6.1.1", 39 | "babel-plugin-syntax-jsx": "^6.18.0", 40 | "babel-plugin-transform-runtime": "^6.22.0", 41 | "babel-plugin-transform-vue-jsx": "^3.5.0", 42 | "babel-polyfill": "^6.26.0", 43 | "babel-preset-env": "^1.3.2", 44 | "babel-register": "^6.22.0", 45 | "eslint": "7.32.0", 46 | "eslint-config-airbnb-base": "15.0.0", 47 | "eslint-friendly-formatter": "3.0.0", 48 | "eslint-import-resolver-webpack": "0.8.3", 49 | "eslint-loader": "4.0.2", 50 | "eslint-plugin-import": "2.25.3", 51 | "eslint-plugin-vue": "8.4.1", 52 | "extract-text-webpack-plugin": "^4.0.0-beta.0", 53 | "postcss": "^8.4.6", 54 | "postcss-import": "12.0.1", 55 | "postcss-loader": "^4.1.0", 56 | "postcss-url": "^9.0.0", 57 | "sass": "~1.32.13", 58 | "sass-loader": "~10.2.0", 59 | "vue-cli-plugin-vuetify": "^2.4.5", 60 | "vue-template-compiler": "^2.6.14", 61 | "vuetify-loader": "^1.7.3", 62 | "webpack": "^4.45.0" 63 | }, 64 | "browserslist": [ 65 | "> 1%", 66 | "last 2 versions", 67 | "not dead" 68 | ] 69 | } 70 | -------------------------------------------------------------------------------- /front/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/favicon.ico -------------------------------------------------------------------------------- /front/public/ico/android-chrome-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/android-chrome-144x144.png -------------------------------------------------------------------------------- /front/public/ico/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/android-chrome-192x192.png -------------------------------------------------------------------------------- /front/public/ico/android-chrome-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/android-chrome-36x36.png -------------------------------------------------------------------------------- /front/public/ico/android-chrome-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/android-chrome-48x48.png -------------------------------------------------------------------------------- /front/public/ico/android-chrome-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/android-chrome-72x72.png -------------------------------------------------------------------------------- /front/public/ico/android-chrome-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/android-chrome-96x96.png -------------------------------------------------------------------------------- /front/public/ico/apple-touch-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/apple-touch-icon-114x114.png -------------------------------------------------------------------------------- /front/public/ico/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /front/public/ico/apple-touch-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/apple-touch-icon-144x144.png -------------------------------------------------------------------------------- /front/public/ico/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /front/public/ico/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /front/public/ico/apple-touch-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/apple-touch-icon-57x57.png -------------------------------------------------------------------------------- /front/public/ico/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /front/public/ico/apple-touch-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/apple-touch-icon-72x72.png -------------------------------------------------------------------------------- /front/public/ico/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /front/public/ico/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /front/public/ico/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/apple-touch-icon.png -------------------------------------------------------------------------------- /front/public/ico/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | #da532c 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /front/public/ico/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/favicon-16x16.png -------------------------------------------------------------------------------- /front/public/ico/favicon-194x194.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/favicon-194x194.png -------------------------------------------------------------------------------- /front/public/ico/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/favicon-32x32.png -------------------------------------------------------------------------------- /front/public/ico/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/favicon-96x96.png -------------------------------------------------------------------------------- /front/public/ico/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "BounCA", 3 | "icons": [ 4 | { 5 | "src": "\/ico\/android-chrome-36x36.png", 6 | "sizes": "36x36", 7 | "type": "image\/png", 8 | "density": 0.75 9 | }, 10 | { 11 | "src": "\/ico\/android-chrome-48x48.png", 12 | "sizes": "48x48", 13 | "type": "image\/png", 14 | "density": 1 15 | }, 16 | { 17 | "src": "\/ico\/android-chrome-72x72.png", 18 | "sizes": "72x72", 19 | "type": "image\/png", 20 | "density": 1.5 21 | }, 22 | { 23 | "src": "\/ico\/android-chrome-96x96.png", 24 | "sizes": "96x96", 25 | "type": "image\/png", 26 | "density": 2 27 | }, 28 | { 29 | "src": "\/ico\/android-chrome-144x144.png", 30 | "sizes": "144x144", 31 | "type": "image\/png", 32 | "density": 3 33 | }, 34 | { 35 | "src": "\/ico\/android-chrome-192x192.png", 36 | "sizes": "192x192", 37 | "type": "image\/png", 38 | "density": 4 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /front/public/ico/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/mstile-144x144.png -------------------------------------------------------------------------------- /front/public/ico/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/mstile-150x150.png -------------------------------------------------------------------------------- /front/public/ico/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/mstile-310x150.png -------------------------------------------------------------------------------- /front/public/ico/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/mstile-310x310.png -------------------------------------------------------------------------------- /front/public/ico/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/public/ico/mstile-70x70.png -------------------------------------------------------------------------------- /front/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /front/src/api/apptokens.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import store from '../store'; 3 | 4 | export default { 5 | getAll(params) { 6 | const url = `${process.env.VUE_APP_ROOT_API}/api/v1/auth/tokens`; 7 | const headers = { Authorization: `Token ${store.getters['auth/accessToken']}` }; 8 | return axios.get(url, { params, headers: headers }).then((response) => response.data); 9 | }, 10 | get(id) { 11 | const url = `${process.env.VUE_APP_ROOT_API}/api/v1/auth/tokens/${id}`; 12 | const headers = { Authorization: `Token ${store.getters['auth/accessToken']}` }; 13 | return axios.get(url, { headers: headers }).then((response) => response.data); 14 | }, 15 | delete(id, data) { 16 | const url = `${process.env.VUE_APP_ROOT_API}/api/v1/auth/tokens/${id}`; 17 | const headers = { Authorization: `Token ${store.getters['auth/accessToken']}` }; 18 | return axios.delete(url, { data: data, headers: headers }).then((response) => response.data); 19 | }, 20 | create(data) { 21 | const url = `${process.env.VUE_APP_ROOT_API}/api/v1/auth/tokens/`; 22 | const headers = { Authorization: `Token ${store.getters['auth/accessToken']}` }; 23 | return axios.post(url, data, { headers: headers }); 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /front/src/api/auth.js: -------------------------------------------------------------------------------- 1 | import session from './session'; 2 | 3 | export default { 4 | login(data) { 5 | return session.post(`${process.env.VUE_APP_ROOT_API}/api/v1/auth/login/`, data); 6 | }, 7 | logout() { 8 | return session.post(`${process.env.VUE_APP_ROOT_API}/api/v1/auth/logout/`, {}); 9 | }, 10 | createAccount(data) { 11 | return session.post(`${process.env.VUE_APP_ROOT_API}/api/v1/auth/registration/`, data); 12 | }, 13 | sendAccountPasswordResetEmail(data) { 14 | return session.post(`${process.env.VUE_APP_ROOT_API}/api/v1/auth/password/reset/`, data); 15 | }, 16 | resetAccountPassword(data) { 17 | return session.post(`${process.env.VUE_APP_ROOT_API}/api/v1/auth/password/reset/confirm/`, data); 18 | }, 19 | verifyAccountEmail(data) { 20 | return session.post(`${process.env.VUE_APP_ROOT_API}/api/v1/auth/registration/verify-email/`, data); 21 | }, 22 | resendEmail(data) { 23 | return session.post(`${process.env.VUE_APP_ROOT_API}/api/v1/auth/registration/resend-email/`, data); 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /front/src/api/profile.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import store from '../store'; 3 | 4 | export default { 5 | changeAccountPassword(data) { 6 | const url = `${process.env.VUE_APP_ROOT_API}/api/v1/auth/password/change/`; 7 | const headers = { Authorization: `Token ${store.getters['auth/accessToken']}` }; 8 | return axios.post(url, data, { headers: headers }); 9 | }, 10 | getAccountDetails() { 11 | const url = `${process.env.VUE_APP_ROOT_API}/api/v1/auth/user/`; 12 | const headers = { Authorization: `Token ${store.getters['auth/accessToken']}` }; 13 | return axios.get(url, { headers: headers }); 14 | }, 15 | updateAccountDetails(data) { 16 | const url = `${process.env.VUE_APP_ROOT_API}/api/v1/auth/user/`; 17 | const headers = { Authorization: `Token ${store.getters['auth/accessToken']}` }; 18 | return axios.patch(url, data, { headers: headers }); 19 | }, 20 | 21 | }; 22 | -------------------------------------------------------------------------------- /front/src/api/session.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | const CSRF_COOKIE_NAME = 'csrftoken'; 4 | const CSRF_HEADER_NAME = 'X-CSRFToken'; 5 | 6 | const session = axios.create({ 7 | xsrfCookieName: CSRF_COOKIE_NAME, 8 | xsrfHeaderName: CSRF_HEADER_NAME, 9 | }); 10 | 11 | export default session; 12 | -------------------------------------------------------------------------------- /front/src/assets/img/BounCA-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/front/src/assets/img/BounCA-logo.png -------------------------------------------------------------------------------- /front/src/components/core/Footer.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | 60 | 61 | 66 | -------------------------------------------------------------------------------- /front/src/components/core/Toolbar.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 65 | -------------------------------------------------------------------------------- /front/src/components/error/NotFound.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /front/src/components/forms/EmailVerify.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 70 | -------------------------------------------------------------------------------- /front/src/components/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import upperFirst from 'lodash/upperFirst'; 3 | import camelCase from 'lodash/camelCase'; 4 | 5 | const requireComponent = require.context('@/components', true, /\.vue$/); 6 | 7 | requireComponent.keys().forEach((fileName) => { 8 | const componentConfig = requireComponent(fileName); 9 | const componentName = upperFirst( 10 | camelCase(fileName.replace(/^\.\//, '').replace(/\.\w+$/, '')), 11 | ); 12 | 13 | Vue.component(componentName, componentConfig.default || componentConfig); 14 | }); 15 | -------------------------------------------------------------------------------- /front/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Axios from 'axios'; 3 | import { 4 | ValidationObserver, 5 | ValidationProvider, 6 | localize, 7 | extend, 8 | setInteractionMode, 9 | } from 'vee-validate'; 10 | import en from 'vee-validate/dist/locale/en.json'; 11 | import * as rules from 'vee-validate/dist/rules'; 12 | 13 | import App from './App.vue'; 14 | import router from './router'; 15 | import store from './store'; 16 | 17 | // Components 18 | import './components/index'; 19 | 20 | import vuetify from './plugins/vuetify'; 21 | 22 | /* vee-validate config */ 23 | setInteractionMode('eager'); 24 | Vue.component('extendValidation', extend); 25 | Vue.component('ValidationObserver', ValidationObserver); 26 | Vue.component('ValidationProvider', ValidationProvider); 27 | 28 | // install rules and localization 29 | Object.keys(rules).forEach((rule) => { 30 | extend(rule, rules[rule]); 31 | }); 32 | extend('url', { 33 | validate(value) { 34 | const pattern = new RegExp('^(https?:\\/\\/)?' // protocol 35 | + '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' // domain name 36 | + '((\\d{1,3}\\.){3}\\d{1,3}))' // OR ip (v4) address 37 | + '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' // port and path 38 | + '(\\?[;&a-z\\d%_.~+=-]*)?' // query string 39 | + '(\\#[-a-z\\d_]*)?$', 'i'); // fragment locator 40 | return pattern.test(value); 41 | }, 42 | message: 'Please enter a valid URL', 43 | }); 44 | localize('en', en); 45 | /* vee-validate config */ 46 | 47 | Vue.config.productionTip = process.env.NODE_ENV === 'production'; 48 | 49 | Vue.prototype.$http = Axios; 50 | const key = localStorage.getItem('user-key'); 51 | if (key) { 52 | Vue.prototype.$http.defaults.headers.common.Authorization = key; 53 | } 54 | 55 | new Vue({ 56 | router, 57 | store, 58 | vuetify, 59 | render: (h) => h(App), 60 | }).$mount('#app'); 61 | -------------------------------------------------------------------------------- /front/src/plugins/vuetify.js: -------------------------------------------------------------------------------- 1 | import 'material-design-icons-iconfont/dist/material-design-icons.css'; 2 | import '@mdi/font/css/materialdesignicons.css'; 3 | import Vue from 'vue'; 4 | import Vuetify from 'vuetify/lib/framework'; 5 | import colors from 'vuetify/es5/util/colors'; 6 | 7 | Vue.use(Vuetify); 8 | 9 | export default new Vuetify({ 10 | icons: { 11 | iconFont: 'md', 12 | }, 13 | theme: { 14 | themes: { 15 | light: { 16 | primary: colors.indigo.base, 17 | secondary: colors.teal.base, 18 | accent: colors.red.base, 19 | error: colors.red.base, 20 | warning: colors.deepOrange.base, 21 | info: colors.blueGrey.base, 22 | success: colors.lightGreen.base, 23 | }, 24 | }, 25 | }, 26 | }); 27 | -------------------------------------------------------------------------------- /front/src/router/dashboard.js: -------------------------------------------------------------------------------- 1 | export default [ 2 | { 3 | path: '/dashboard', 4 | redirect: '/dashboard/overview', 5 | component: () => import('../views/Dashboard.vue'), 6 | children: [ 7 | { 8 | path: 'overview', 9 | name: 'Overview', 10 | meta: { 11 | requiresAuth: true, 12 | displayName: 'Overview', 13 | }, 14 | component: () => import('../components/dashboard/Overview.vue'), 15 | }, 16 | { 17 | path: 'root', 18 | name: 'Root', 19 | meta: { 20 | requiresAuth: true, 21 | displayName: 'Root', 22 | }, 23 | component: () => import('../components/dashboard/Root.vue'), 24 | }, 25 | { 26 | path: 'intermediate/:id', 27 | name: 'Intermediate', 28 | meta: { 29 | requiresAuth: true, 30 | displayName: 'Intermediate', 31 | }, 32 | component: () => import('../components/dashboard/Intermediate.vue'), 33 | }, 34 | { 35 | path: 'certificate/:id', 36 | name: 'Certificate', 37 | meta: { 38 | requiresAuth: true, 39 | displayName: 'Certificate', 40 | }, 41 | component: () => import('../components/dashboard/Certificate.vue'), 42 | }, 43 | { 44 | path: 'user/profile', 45 | name: 'user_profile', 46 | meta: { 47 | requiresAuth: true, 48 | displayName: 'Profile', 49 | }, 50 | component: () => import('../components/dashboard/user/UserProfile.vue'), 51 | }, 52 | ], 53 | }, 54 | ]; 55 | -------------------------------------------------------------------------------- /front/src/router/home.js: -------------------------------------------------------------------------------- 1 | import store from '../store'; 2 | 3 | export default [ 4 | { 5 | path: '*', 6 | meta: { 7 | name: '', 8 | requiresAuth: true, 9 | }, 10 | redirect: { 11 | path: '/dashboard', 12 | }, 13 | }, 14 | { 15 | path: '/', 16 | meta: { 17 | name: '', 18 | requiresAuth: false, 19 | }, 20 | component: () => import('../views/Public.vue'), 21 | // redirect if already signed in 22 | beforeEnter: (to, from, next) => { 23 | if (store.getters['auth/isLoggedIn']) { 24 | next('/dashboard'); 25 | } else { 26 | next(); 27 | } 28 | }, 29 | children: [ 30 | { 31 | path: '', 32 | redirect: '/auth/login', 33 | }, 34 | ], 35 | }, 36 | ]; 37 | -------------------------------------------------------------------------------- /front/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Router from 'vue-router'; 3 | import Meta from 'vue-meta'; 4 | import axios from 'axios'; 5 | 6 | import store from '../store'; 7 | 8 | // Routes 9 | import home from './home'; 10 | import auth from './auth'; 11 | import dashboard from './dashboard'; 12 | 13 | Vue.use(Router); 14 | 15 | // Create a new router 16 | const router = new Router({ 17 | base: '', 18 | mode: 'history', 19 | routes: home.concat(auth, dashboard), 20 | 21 | scrollBehavior(to, from, savedPosition) { 22 | if (savedPosition) { 23 | return savedPosition; 24 | } 25 | if (to.hash) { 26 | return { selector: to.hash }; 27 | } 28 | return { x: 0, y: 0 }; 29 | }, 30 | }); 31 | 32 | router.beforeEach((to, from, next) => { 33 | if (to.matched.some((record) => record.meta.requiresAuth)) { 34 | if (store.getters['auth/isLoggedIn']) { 35 | next(); 36 | return; 37 | } 38 | next('/'); 39 | } else { 40 | next(); 41 | } 42 | }); 43 | 44 | Vue.use(Meta); 45 | 46 | export default router; 47 | 48 | axios.interceptors.response.use( 49 | (response) => response, 50 | (error) => { 51 | if (error.response.status === 403 || error.response.status === 401) { 52 | store.dispatch('auth/logout').then(() => router.push('/')); 53 | } 54 | return Promise.reject(error); 55 | }, 56 | ); 57 | -------------------------------------------------------------------------------- /front/src/store/auth.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import auth from '../api/auth'; 3 | 4 | const initialState = { 5 | key: localStorage.getItem('key') || '', 6 | }; 7 | 8 | const mutations = { 9 | auth_request(state) { 10 | state.status = 'loading'; 11 | }, 12 | auth_success(state, key) { 13 | state.status = 'success'; 14 | state.key = key; 15 | }, 16 | auth_error(state) { 17 | state.status = 'error'; 18 | }, 19 | logout(state) { 20 | state.status = ''; 21 | state.key = ''; 22 | }, 23 | }; 24 | 25 | const actions = { 26 | login({ commit }, credentials) { 27 | return new Promise((resolve, reject) => { 28 | commit('auth_request'); 29 | auth.login(credentials).then((resp) => { 30 | const { key } = resp.data; 31 | localStorage.setItem('key', key); 32 | axios.defaults.headers.common.Authorization = key; 33 | commit('auth_success', key); 34 | resolve(resp); 35 | }).catch((err) => { 36 | commit('auth_error'); 37 | localStorage.removeItem('key'); 38 | reject(err); 39 | }); 40 | }); 41 | }, 42 | register({ commit }, subscription) { 43 | return new Promise((resolve, reject) => { 44 | commit('auth_request'); 45 | auth.createAccount(subscription).then((resp) => { 46 | const { key } = resp.data; 47 | localStorage.setItem('key', key); 48 | axios.defaults.headers.common.Authorization = key; 49 | commit('auth_success', key); 50 | resolve(resp); 51 | }).catch((err) => { 52 | commit('auth_error'); 53 | localStorage.removeItem('key'); 54 | reject(err); 55 | }); 56 | }); 57 | }, 58 | logout({ commit }) { 59 | return new Promise((resolve, reject) => { 60 | auth.logout().then((resp) => { 61 | commit('logout'); 62 | localStorage.removeItem('key'); 63 | delete axios.defaults.headers.common.Authorization; 64 | resolve(resp); 65 | }).catch((err) => { 66 | reject(err); 67 | }); 68 | }); 69 | }, 70 | }; 71 | 72 | const getters = { 73 | isLoggedIn: (state) => !!state.key, 74 | accessToken: (state) => state.key, 75 | }; 76 | 77 | export default { 78 | namespaced: true, 79 | state: initialState, 80 | getters, 81 | actions, 82 | mutations, 83 | }; 84 | -------------------------------------------------------------------------------- /front/src/store/dashboard.js: -------------------------------------------------------------------------------- 1 | const initialState = { 2 | navigation: { 3 | root: { 4 | id: '', 5 | name: '', 6 | active: false, 7 | }, 8 | intermediate: { 9 | id: '', 10 | name: '', 11 | active: false, 12 | }, 13 | }, 14 | }; 15 | 16 | const getters = { }; 17 | 18 | const actions = { }; 19 | 20 | const mutations = { 21 | setRoot(state, certInfo) { 22 | state.navigation.root = certInfo; 23 | }, 24 | setIntermediate(state, certInfo) { 25 | state.navigation.intermediate = certInfo; 26 | }, 27 | }; 28 | 29 | export default { 30 | namespaced: true, 31 | state: initialState, 32 | getters, 33 | actions, 34 | mutations, 35 | }; 36 | -------------------------------------------------------------------------------- /front/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | import createLogger from 'vuex/dist/logger'; 4 | 5 | import auth from './auth'; 6 | import dashboard from './dashboard'; 7 | import version from './version'; 8 | 9 | const debug = process.env.NODE_ENV !== 'production'; 10 | 11 | Vue.use(Vuex); 12 | 13 | export default new Vuex.Store({ 14 | modules: { 15 | auth: auth, 16 | dashboard: dashboard, 17 | version: version, 18 | }, 19 | strict: debug, 20 | plugins: debug ? [createLogger()] : [], 21 | }); 22 | -------------------------------------------------------------------------------- /front/src/store/version.js: -------------------------------------------------------------------------------- 1 | const packageJson = JSON.parse(JSON.stringify(require('../../package.json'))); 2 | 3 | const initialState = { 4 | packageVersion: packageJson.version, 5 | }; 6 | 7 | const getters = { 8 | appVersion: (state) => state.packageVersion, 9 | }; 10 | 11 | const actions = { }; 12 | 13 | const mutations = { }; 14 | 15 | export default { 16 | namespaced: true, 17 | state: initialState, 18 | getters, 19 | actions, 20 | mutations, 21 | }; 22 | -------------------------------------------------------------------------------- /front/src/views/Auth.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /front/src/views/Dashboard.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 24 | 25 | 27 | -------------------------------------------------------------------------------- /front/src/views/Public.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /front/vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transpileDependencies: [ 3 | 'vuetify', 4 | ], 5 | pages: { 6 | index: { 7 | // entry for the page 8 | entry: 'src/main.js', 9 | title: 'BounCA PKI', 10 | }, 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /graphics/logo/BounCA-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/graphics/logo/BounCA-icon.png -------------------------------------------------------------------------------- /graphics/logo/BounCA.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/graphics/logo/BounCA.pdf -------------------------------------------------------------------------------- /graphics/logo/BounCA.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/graphics/logo/BounCA.sketch -------------------------------------------------------------------------------- /logs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /make-docs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash -e 2 | 3 | WORKDIR=`dirname "$0"` 4 | PYTHON=`which python3` 5 | 6 | virtualenv -p "$PYTHON" env 7 | . env/bin/activate 8 | cd "$WORKDIR" 9 | 10 | pip install -r requirements.docs.txt 11 | 12 | cd docs 13 | make html 14 | cd .. 15 | rm -rf ./bounca/static/docs/* || true 16 | cp -r ./docs/build/html/ ./bounca/static/docs/ 17 | -------------------------------------------------------------------------------- /make-package.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash -ex 2 | 3 | 4 | BASEDIR=$(dirname "$0") 5 | WORKDIR="$BASEDIR/out/bounca" 6 | VERSION=$(awk '{ sub(/.*\//, ""); print }' <<< $(git rev-parse --abbrev-ref HEAD)) 7 | 8 | 9 | if [ "$VERSION" == "master" ]; then 10 | VERSION="0.0.0-$VERSION" 11 | fi 12 | 13 | cd $BASEDIR 14 | ./run-checks.sh 15 | ./run-tests.sh 16 | 17 | 18 | echo "Archive will be created ./out" 19 | rm -rf $WORKDIR | true 20 | mkdir -p $WORKDIR 21 | git archive master | tar -x -C $WORKDIR 22 | 23 | cd $WORKDIR 24 | rm -rf ./vuetifyforms 25 | cd front 26 | 27 | sed -i '' -e s/\"version\":\ \"0.0.0-dev\"/\"version\":\ \"$VERSION\"/g package.json 28 | npm install 29 | npm run build --production 30 | rm -rf node_modules public src 31 | rm .babelrc .env .env.production .eslintignore .eslintrc.js .postcssrc.js 32 | rm Makefile README.md babel.config.js package-lock.json package.json vue.config.js 33 | 34 | cd "../.." 35 | tar -czvf "bounca-$VERSION.tar.gz" --owner=0 --group=0 bounca/ 36 | rm -rf $WORKDIR | true 37 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | 6 | def main(): 7 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "bounca.settings") 8 | try: 9 | from django.core.management import execute_from_command_line 10 | except ImportError as exc: 11 | raise ImportError( 12 | "Couldn't import Django. Are you sure it's installed and " 13 | "available on your PYTHONPATH environment variable? Did you " 14 | "forget to activate a virtual environment?" 15 | ) from exc 16 | execute_from_command_line(sys.argv) 17 | 18 | 19 | if __name__ == "__main__": 20 | main() 21 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | line-length = 120 3 | target-version = ['py37', 'py38'] 4 | exclude = ''' 5 | ( 6 | /( 7 | | env 8 | | venv 9 | | out 10 | | .+/migrations 11 | )/ 12 | ) 13 | ''' 14 | 15 | 16 | 17 | [tool.isort] 18 | profile = "black" 19 | multi_line_output = 3 20 | line_length = 120 21 | 22 | 23 | [tool.mypy] 24 | python_version = "3.7" 25 | exclude = "(env|venv|out|migrations|tests|docs)" 26 | 27 | disallow_untyped_calls = false 28 | disallow_untyped_defs = false 29 | disallow_incomplete_defs = false 30 | disallow_untyped_decorators = false 31 | 32 | warn_redundant_casts = true 33 | warn_unused_ignores = true 34 | warn_no_return = true 35 | warn_return_any = true 36 | warn_unreachable = true 37 | 38 | strict_equality = true 39 | 40 | show_error_codes = true 41 | pretty = true 42 | 43 | warn_unused_configs = true 44 | ignore_missing_imports = true 45 | -------------------------------------------------------------------------------- /requirements.docs.txt: -------------------------------------------------------------------------------- 1 | # Docs 2 | sphinx==5.3.0 3 | sphinx_rtd_theme==1.2.0 4 | sphinx_bootstrap_theme==0.8.1 5 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # Framework 2 | Django==4.2.9 3 | psycopg2-binary==2.9.9 4 | pytz==2023.3.post1 5 | requests==2.31.0 6 | djangorestframework==3.14.0 7 | django-grappelli==3.0.8 8 | django-countries==7.5.1 9 | django-rest-swagger==2.2.0 10 | django-filter==23.5 11 | django-allauth==0.60.1 12 | dj-rest-auth==5.0.2 13 | django-ical==1.9.2 14 | django-cors-headers==4.3.1 15 | django-property-filter==1.2.0 16 | 17 | 18 | # Date 19 | arrow==1.3.0 20 | 21 | # SSL 22 | cryptography==41.0.7 23 | bcrypt==4.1.2 24 | 25 | # Parsers 26 | yamlreader==3.0.4 27 | 28 | # Testing 29 | coverage==7.4.0 30 | factory-boy==3.3.0 31 | Faker==22.2.0 32 | mock==5.1.0 33 | requests-mock==1.11.0 34 | 35 | # Code Quality 36 | flake8==7.0.0 37 | isort==5.13.2 38 | autopep8==2.0.4 39 | mypy==1.8.0 40 | types-pytz==2023.3.1.1 41 | pur==7.3.1 42 | black==23.12.1 43 | typing_extensions==4.9.0 44 | 45 | # Development 46 | beautifulsoup4==4.12.2 47 | django-crispy-forms==2.1 48 | codacy-coverage==1.3.11 49 | -------------------------------------------------------------------------------- /run-checks-node.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash -xe 2 | 3 | BASEDIR=`dirname "$0"` 4 | cd $BASEDIR 5 | 6 | BLUE='\033[1;34m' 7 | BRIGHT_RED='\033[1;31m' 8 | DARK_GRAY='\033[0;37m' 9 | RESET='\033[m' 10 | INFO="${BLUE}[INFO]${RESET}" 11 | 12 | function task() { 13 | if [ "$3" != "" ]; then 14 | printf "$2\n" 15 | 16 | $1 $3 & 17 | pid=$! 18 | wait $pid 19 | 20 | if [ $? == 0 ]; then 21 | echo -ne "\033[0K\r" 22 | else 23 | printf "${BRIGHT_RED}Please fix the above errors ${RESET}\n" 24 | exit 1 25 | fi 26 | fi 27 | } 28 | 29 | PY_MESSAGE="${INFO} Linting javascript files ${DARK_GRAY}[*.js]${RESET}" 30 | cd front 31 | npm install --legacy-peer-deps 32 | task "npm run lint" "$PY_MESSAGE" . 33 | -------------------------------------------------------------------------------- /run-checks-python.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash -x 2 | 3 | PYTHON_FOLDERS='api bounca certificate_engine vuetifyforms x509_pki superuser_signup' 4 | BASEDIR=`dirname "$0"` 5 | cd $BASEDIR 6 | 7 | BLUE='\033[1;34m' 8 | BRIGHT_RED='\033[1;31m' 9 | DARK_GRAY='\033[0;37m' 10 | RESET='\033[m' 11 | INFO="${BLUE}[INFO]${RESET}" 12 | 13 | function task() { 14 | if [ "$3" != "" ]; then 15 | printf "$2\n" 16 | 17 | $1 $3 & 18 | pid=$! 19 | wait $pid 20 | 21 | if [ $? == 0 ]; then 22 | echo -ne "\033[0K\r" 23 | else 24 | printf "${BRIGHT_RED}Please fix the above errors ${RESET}\n" 25 | exit 1 26 | fi 27 | fi 28 | } 29 | 30 | py_files=$(find $PYTHON_FOLDERS -path '**/migrations' -prune -o -name '*.py' -print) 31 | PY_MESSAGE="${INFO} Check import order on python files ${DARK_GRAY}[*.py]${RESET}" 32 | task "isort --check-only" "$PY_MESSAGE" "$py_files" 33 | PY_MESSAGE="${INFO} Linting python files ${DARK_GRAY}[*.py]${RESET}" 34 | task flake8 "$PY_MESSAGE" . 35 | PY_MESSAGE="${INFO} Black python files ${DARK_GRAY}[*.py]${RESET}" 36 | task "black --check" "$PY_MESSAGE" . 37 | -------------------------------------------------------------------------------- /run-checks.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash -x 2 | 3 | ./run-checks-python.sh 4 | ./run-checks-node.sh 5 | -------------------------------------------------------------------------------- /run-dev-server.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | WORKDIR=`dirname "$0"` 4 | PYTHON=`which python3.4` 5 | 6 | virtualenv -p "$PYTHON" env 7 | . env/bin/activate 8 | cd "$WORKDIR" 9 | 10 | pip3.4 install -r requirements.txt 11 | 12 | python manage.py migrate 13 | python manage.py collectstatic --noinput 14 | python manage.py runserver -------------------------------------------------------------------------------- /run-tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash -x 2 | 3 | PYTHON_FOLDERS='api bounca certificate_engine vuetifyforms x509_pki superuser_signup' 4 | BASEDIR=`dirname "$0"`/ 5 | cd $BASEDIR 6 | 7 | . ./env/bin/activate 8 | 9 | BLUE='\033[1;34m' 10 | BRIGHT_RED='\033[1;31m' 11 | DARK_GRAY='\033[0;37m' 12 | RESET='\033[m' 13 | INFO="${BLUE}[INFO]${RESET}" 14 | 15 | function task() { 16 | printf "$2\n" 17 | # docker-compose start 18 | $1 & 19 | pid=$! 20 | wait $pid 21 | 22 | if [ $? == 0 ]; then 23 | echo -ne "\033[0K\r" 24 | # docker-compose stop 25 | else 26 | printf "${BRIGHT_RED}Please fix the above errors ${RESET}\n" 27 | # docker-compose stop 28 | exit 1 29 | fi 30 | } 31 | 32 | mypy . 33 | 34 | PY_MESSAGE="${INFO} Running unit tests${RESET}" 35 | task "coverage run --include bounca/\* --omit */env/*,*/venv/*,*/migrations/*,*/tests/* manage.py test" "$PY_MESSAGE" 36 | coverage report 37 | coverage xml 38 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = F405, W503 3 | max-line-length = 120 4 | exclude = */migrations/*.py,docs,env,out 5 | max-complexity = 10 6 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | from setuptools import Command, find_packages, setup 4 | from setuptools.command.install import install as _install 5 | from setuptools.command.sdist import sdist as _sdist 6 | 7 | src_dir = "." 8 | packages = find_packages(src_dir) 9 | 10 | 11 | class FrontendBuilder(Command): 12 | user_options: List[str] = [] 13 | description = "builds the frontend assets using NPM" 14 | 15 | def run(self): 16 | self.spawn(["npm", "install"]) 17 | 18 | def initialize_options(self): 19 | pass 20 | 21 | def finalize_options(self): 22 | pass 23 | 24 | 25 | class sdist(_sdist): 26 | def run(self): 27 | """ 28 | Runs the frontend command *before* packaging everything. 29 | """ 30 | self.run_command("frontend") 31 | _sdist.run(self) 32 | 33 | 34 | class install(_install): 35 | def run(self): 36 | """ 37 | Runs the frontend command *after* installing the python package(s). 38 | """ 39 | _install.run(self) 40 | self.run_command("frontend") 41 | 42 | 43 | cmdclass = { 44 | "sdist": sdist, 45 | "install": install, 46 | "frontend": FrontendBuilder, 47 | } 48 | 49 | setup( 50 | name="bounca", 51 | version="0.4.5", 52 | cmdclass=cmdclass, 53 | entry_points={"console_scripts": ["djadmin = manage:main"]}, 54 | scripts=["manage.py"], 55 | packages=packages, 56 | include_package_data=True, 57 | license="proprietary", 58 | classifiers=[ 59 | "Private :: Do Not Upload", 60 | "License :: Other/Proprietary License", 61 | ], 62 | zip_safe=False, 63 | ) 64 | -------------------------------------------------------------------------------- /superuser_signup/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/superuser_signup/__init__.py -------------------------------------------------------------------------------- /superuser_signup/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class SuperuserSignupConfig(AppConfig): 5 | default_auto_field = "django.db.models.BigAutoField" 6 | name = "superuser_signup" 7 | -------------------------------------------------------------------------------- /superuser_signup/forms.py: -------------------------------------------------------------------------------- 1 | from allauth.account.forms import SignupForm 2 | 3 | 4 | class SuperUserSignupForm(SignupForm): 5 | def save(self, request): 6 | user = super(SuperUserSignupForm, self).save(request) 7 | user.is_staff = True 8 | user.is_superuser = True 9 | user.save() 10 | return user 11 | -------------------------------------------------------------------------------- /superuser_signup/views.py: -------------------------------------------------------------------------------- 1 | from allauth.account.utils import complete_signup 2 | from allauth.account.views import SignupView 3 | from allauth.core.exceptions import ImmediateHttpResponse 4 | from django.contrib.auth.models import User 5 | from django.http import HttpResponseNotFound 6 | from django.urls import reverse_lazy 7 | from django.utils.translation import gettext_lazy as _ 8 | 9 | from superuser_signup.forms import SuperUserSignupForm 10 | 11 | 12 | class CreateSuperUserView(SignupView): 13 | form_class = SuperUserSignupForm 14 | success_url = reverse_lazy("admin:index") 15 | 16 | def dispatch(self, request, *args, **kwargs): 17 | if User.objects.exists(): 18 | return HttpResponseNotFound() 19 | return super(SignupView, self).dispatch(request, args, kwargs) 20 | 21 | def get_context_data(self, **kwargs): 22 | ret = super(CreateSuperUserView, self).get_context_data(**kwargs) 23 | ret.update({"title": _("Register Super User")}) 24 | return ret 25 | 26 | def form_valid(self, form): 27 | # no email verification required 28 | self.user = form.save(self.request) 29 | try: 30 | return complete_signup( 31 | self.request, 32 | self.user, 33 | "none", 34 | self.get_success_url(), 35 | ) 36 | except ImmediateHttpResponse as e: 37 | return e.response 38 | -------------------------------------------------------------------------------- /vuetifyforms/README.md: -------------------------------------------------------------------------------- 1 | vee-validate3 does not implement all the rules offered by vee-validate2. 2 | You can add these rules after importing ValidationProvider: 3 | 4 | ```angular2html 5 | /* vee-validate config */ 6 | setInteractionMode('eager'); 7 | Vue.component('extend', extend); 8 | Vue.component('ValidationObserver', ValidationObserver); 9 | Vue.component('ValidationProvider', ValidationProvider); 10 | 11 | // install rules and localization 12 | Object.keys(rules).forEach((rule) => { 13 | extend(rule, rules[rule]); 14 | }); 15 | extend('url', { 16 | validate(value) { 17 | const pattern = new RegExp('^(https?:\\/\\/)?' + // protocol 18 | '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name 19 | '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address 20 | '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path 21 | '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string 22 | '(\\#[-a-z\\d_]*)?$', 'i'); // fragment locator 23 | return pattern.test(value); 24 | }, 25 | message: 'Please enter a valid URL', 26 | }); 27 | localize('en', en); 28 | /* vee-validate config */ 29 | ``` 30 | -------------------------------------------------------------------------------- /vuetifyforms/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/vuetifyforms/__init__.py -------------------------------------------------------------------------------- /vuetifyforms/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class VuetifyformsConfig(AppConfig): 5 | name = "vuetifyforms" 6 | -------------------------------------------------------------------------------- /vuetifyforms/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/vuetifyforms/management/commands/__init__.py -------------------------------------------------------------------------------- /vuetifyforms/management/commands/generate_forms.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from crispy_forms.utils import render_crispy_form 4 | from django.conf import settings 5 | from django.core.management.base import BaseCommand 6 | 7 | from vuetifyforms.vue import VuetifyFormMixin 8 | 9 | 10 | class Command(BaseCommand): 11 | help = "Generate vuetify forms " 12 | 13 | def generate_form(self, form): 14 | self.stdout.write(f"Generating form {form.__name__}, writing to file {form.vue_file}") 15 | html_form = render_crispy_form(form, context={"form": form}) 16 | full_path = os.path.join(settings.BASE_DIR, form.vue_file) 17 | with open(full_path, "w") as f: 18 | f.write(html_form) 19 | 20 | def generate_forms(self): 21 | forms = VuetifyFormMixin.get_subclasses() 22 | for form in forms: 23 | self.generate_form(form) 24 | 25 | def handle(self, *args, **options): 26 | self.stdout.write("Generating vuetify forms") 27 | self.generate_forms() 28 | self.stdout.write(self.style.SUCCESS("Successfully generated forms")) 29 | -------------------------------------------------------------------------------- /vuetifyforms/templates/vuetify/display_form.html: -------------------------------------------------------------------------------- 1 | {% if form.form_html %} 2 | {% if include_media %}{{ form.media }}{% endif %} 3 | {{ form.form_html }} 4 | {% else %} 5 | {% include "vuetify/uni_form.html" %} 6 | {% endif %} 7 | -------------------------------------------------------------------------------- /vuetifyforms/templates/vuetify/field.html: -------------------------------------------------------------------------------- 1 | {% load crispy_forms_vuetify %} 2 | {% load crispy_forms_field %} 3 | 4 | {% if field.is_hidden %} 5 | {{ field }} 6 | {% else %} 7 | {% if field.help_text %} 8 | 9 | 53 | {{ field.help_text|safe }} 54 | 55 | {% endif %} 56 | 57 | {% endif %} 58 | -------------------------------------------------------------------------------- /vuetifyforms/templates/vuetify/layout/baseinput.html: -------------------------------------------------------------------------------- 1 | 4 | {{ input.value }} 5 | 6 | -------------------------------------------------------------------------------- /vuetifyforms/templates/vuetify/layout/buttonholder.html: -------------------------------------------------------------------------------- 1 | 2 | {{ fields_output|safe }} 3 | 4 | -------------------------------------------------------------------------------- /vuetifyforms/templates/vuetify/layout/column.html: -------------------------------------------------------------------------------- 1 | 2 | {{ fields|safe }} 3 | 4 | -------------------------------------------------------------------------------- /vuetifyforms/templates/vuetify/layout/fieldset.html: -------------------------------------------------------------------------------- 1 | 2 | {% if legend %}{{ legend|safe }}{% endif %} 3 | {{ fields|safe }} 4 | 5 | -------------------------------------------------------------------------------- /vuetifyforms/templates/vuetify/layout/flex.html: -------------------------------------------------------------------------------- 1 | 2 | {{ fields|safe }} 3 | 4 | -------------------------------------------------------------------------------- /vuetifyforms/templates/vuetify/layout/row.html: -------------------------------------------------------------------------------- 1 | 2 | {{ fields|safe }} 3 | 4 | -------------------------------------------------------------------------------- /vuetifyforms/templates/vuetify/layout/spacer.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /vuetifyforms/templates/vuetify/script/default.js: -------------------------------------------------------------------------------- 1 | {% load crispy_forms_vuetify %} 2 | {% include "vuetify/script/imports.js" %} 3 | 4 | function initialState (){ 5 | const data = {% make_data_object form %}; 6 | {{ form.vue_extra_initial_statements|safe }} 7 | return data; 8 | } 9 | 10 | export default { 11 | name: '{{ form.form_component_name }}', 12 | props: [{% for prop in form.vue_props %}'{{ prop }}'{% if not forloop.last %},{% endif %}{% endfor %}], 13 | data() { 14 | return initialState(); 15 | }, 16 | watch: { 17 | {% for watch in form.vue_watchers %} 18 | {{ watch|safe }}, 19 | {% endfor %} 20 | }, 21 | mounted() { 22 | {{ form.vue_mounted|safe }} 23 | }, 24 | {% include "vuetify/script/methods.js" %} 25 | }; 26 | -------------------------------------------------------------------------------- /vuetifyforms/templates/vuetify/script/imports.js: -------------------------------------------------------------------------------- 1 | {% for name, path in form.vue_imports %} 2 | import {{ name|safe }} from '{{ path|safe }}'; 3 | {% endfor %} 4 | -------------------------------------------------------------------------------- /vuetifyforms/templates/vuetify/script/methods.js: -------------------------------------------------------------------------------- 1 | methods: { 2 | resetForm: function (){ 3 | Object.assign(this.$data, initialState()); 4 | this.$refs.form.reset(); 5 | {{ form.vue_extra_init_rules|safe }} 6 | }, 7 | {% for method in form.vue_methods %} 8 | {{ method|safe }}, 9 | {% endfor %} 10 | }, 11 | -------------------------------------------------------------------------------- /vuetifyforms/templates/vuetify/uni_form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 14 |
{% verbatim %}{{error}}{% endverbatim %}
15 |
16 |
17 | {% for field in form %} 18 | {% include field_template %} 19 | {% endfor %} 20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /vuetifyforms/templates/vuetify/whole_uni_form.html: -------------------------------------------------------------------------------- 1 | 33 | 34 | 35 | 38 | -------------------------------------------------------------------------------- /vuetifyforms/templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/vuetifyforms/templatetags/__init__.py -------------------------------------------------------------------------------- /vuetifyforms/views.py: -------------------------------------------------------------------------------- 1 | from rest_framework import exceptions 2 | from rest_framework.views import exception_handler as drf_exception_handler 3 | 4 | 5 | def _flatten_vue_validation(val, key_prefix=""): 6 | if isinstance(val, list): 7 | return [_flatten_vue_validation(x) for x in val] 8 | elif isinstance(val, dict): 9 | res = {} 10 | for k in val: 11 | v = _flatten_vue_validation(val[k], key_prefix=f"{k}__") 12 | if isinstance(v, dict): 13 | res.update(v) 14 | else: 15 | res[f"{key_prefix}{k}"] = val[k] 16 | return res 17 | else: 18 | return val 19 | 20 | 21 | def vue_exception_handler(exc, context): 22 | """ 23 | Flattens the 400 validation responses so it can be handled by vue. 24 | 25 | Other error are processed by the default rest_framework.views.exception_handler 26 | """ 27 | if isinstance(exc, exceptions.APIException) and isinstance(exc.detail, (list, dict)): 28 | exc.detail = _flatten_vue_validation(exc.detail) 29 | 30 | return drf_exception_handler(exc, context) 31 | -------------------------------------------------------------------------------- /vuetifyforms/vue.py: -------------------------------------------------------------------------------- 1 | class VuetifyFormMixin(object): 2 | field_css_classes = "form-group has-feedback" 3 | widget_css_classes = "form-control" 4 | form_error_css_classes = "djng-form-errors" 5 | field_error_css_classes = "djng-form-control-feedback djng-field-errors" 6 | label_css_classes = "control-label" 7 | 8 | @classmethod 9 | def get_subclasses(cls): 10 | for subclass in cls.__subclasses__(): 11 | yield from subclass.get_subclasses() 12 | yield subclass 13 | 14 | def as_vuetify(self): 15 | """ 16 | Returns this form rendered as HTML with
s for each form field. 17 | """ 18 | # wrap non-field-errors into
-element to prevent re-boxing 19 | error_row = '
%s
' 20 | div_element = self._html_output( 21 | normal_row="%(label)s%(field)s%(help_text)s%(errors)s
", 22 | error_row=error_row, 23 | row_ender="
", 24 | help_text_html='%s', 25 | errors_on_separate_row=False, 26 | ) 27 | return div_element 28 | -------------------------------------------------------------------------------- /x509_pki/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/x509_pki/__init__.py -------------------------------------------------------------------------------- /x509_pki/apps.py: -------------------------------------------------------------------------------- 1 | """App name""" 2 | 3 | from django.apps import AppConfig 4 | 5 | 6 | class X509PkiConfig(AppConfig): 7 | name = "x509_pki" 8 | -------------------------------------------------------------------------------- /x509_pki/management/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/x509_pki/management/__init__.py -------------------------------------------------------------------------------- /x509_pki/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/x509_pki/management/commands/__init__.py -------------------------------------------------------------------------------- /x509_pki/migrations/0002_keystore_fingerprint.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.0.4 on 2022-04-18 08:22 2 | 3 | from django.db import migrations, models 4 | 5 | from certificate_engine.ssl.info import get_certificate_fingerprint 6 | 7 | 8 | def set_my_defaults(apps, schema_editor): 9 | Keystore = apps.get_model('x509_pki', 'keystore') 10 | for keystore in Keystore.objects.all().iterator(): 11 | keystore.fingerprint = get_certificate_fingerprint(keystore.crt) 12 | keystore.save() 13 | 14 | 15 | def reverse_func(apps, schema_editor): 16 | pass # code for reverting migration, if any 17 | 18 | 19 | class Migration(migrations.Migration): 20 | 21 | dependencies = [ 22 | ('x509_pki', '0001_squashed_0015_keystore_p12'), 23 | ] 24 | 25 | operations = [ 26 | migrations.AddField( 27 | model_name='keystore', 28 | name='fingerprint', 29 | field=models.TextField(null=True, verbose_name='SHA1 Fingerprint of Certificate'), 30 | preserve_default=False, 31 | ), 32 | migrations.RunPython(set_my_defaults, reverse_func), 33 | migrations.AlterField( 34 | model_name='keystore', 35 | name='fingerprint', 36 | field=models.TextField(), 37 | ), 38 | ] 39 | 40 | -------------------------------------------------------------------------------- /x509_pki/migrations/0003_alter_keystore_fingerprint.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.0.4 on 2022-05-03 20:49 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('x509_pki', '0002_keystore_fingerprint'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='keystore', 15 | name='fingerprint', 16 | field=models.TextField(verbose_name='SHA1 Fingerprint of Certificate'), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /x509_pki/migrations/0004_alter_certificate_type.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.0.4 on 2022-05-03 20:53 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('x509_pki', '0003_alter_keystore_fingerprint'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='certificate', 15 | name='type', 16 | field=models.CharField(choices=[('R', 'Root CA Certificate'), ('I', 'Intermediate CA Certificate'), ('S', 'Server Certificate'), ('C', 'Client Certificate'), ('D', 'Code Signing Certificate'), ('O', 'OCSP Signing Certificate')], max_length=1), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /x509_pki/migrations/0005_alter_certificate_crl_distribution_url.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.1.5 on 2023-02-05 14:38 2 | 3 | import django.core.validators 4 | from django.db import migrations, models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ("x509_pki", "0004_alter_certificate_type"), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name="certificate", 16 | name="crl_distribution_url", 17 | field=models.URLField( 18 | blank=True, 19 | help_text="Base URL for certificate revocation list (CRL)", 20 | null=True, 21 | validators=[ 22 | django.core.validators.RegexValidator("[^\\/]\\.crl$", "CRL url should end with .crl") 23 | ], 24 | verbose_name="CRL distribution url", 25 | ), 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /x509_pki/migrations/0006_keystore_p12_legacy.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.9 on 2024-01-26 08:58 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | dependencies = [ 8 | ("x509_pki", "0005_alter_certificate_crl_distribution_url"), 9 | ] 10 | 11 | operations = [ 12 | migrations.AddField( 13 | model_name="keystore", 14 | name="p12_legacy", 15 | field=models.BinaryField( 16 | blank=True, 17 | default=None, 18 | null=True, 19 | verbose_name="Serialized PKCS 12 package with key and certificate sha1 for legacy support", 20 | ), 21 | ), 22 | ] 23 | -------------------------------------------------------------------------------- /x509_pki/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/x509_pki/migrations/__init__.py -------------------------------------------------------------------------------- /x509_pki/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/repleo/bounca/fdd52ea3d16173040152a19a0dd61287c01ee674/x509_pki/tests/__init__.py -------------------------------------------------------------------------------- /x509_pki/tests/test_factories.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from django.test import TestCase 3 | 4 | from x509_pki.tests.factories import CertificateFactory, DistinguishedNameFactory, UserFactory 5 | 6 | 7 | class FactoriesTest(TestCase): 8 | """ 9 | Very simple tests to ensure the factories work as expected. 10 | """ 11 | 12 | def test_user_factory(self): 13 | user = UserFactory() 14 | self.assertIsNotNone(user.username) 15 | self.assertIsNotNone(user.password) 16 | self.assertIsNotNone(user.first_name) 17 | self.assertIsNotNone(user.last_name) 18 | self.assertFalse(user.is_superuser) 19 | self.assertFalse(user.is_staff) 20 | self.assertTrue(user.is_active) 21 | 22 | def test_distinguished_name_factory(self): 23 | dn = DistinguishedNameFactory() 24 | self.assertIsNotNone(dn.countryName) 25 | self.assertIsNotNone(dn.stateOrProvinceName) 26 | self.assertIsNotNone(dn.localityName) 27 | self.assertIsNotNone(dn.organizationName) 28 | self.assertIsNotNone(dn.organizationalUnitName) 29 | self.assertIsNotNone(dn.emailAddress) 30 | self.assertIsNotNone(dn.commonName) 31 | self.assertIsNotNone(dn.subjectAltNames) 32 | 33 | def test_certificate_factory(self): 34 | cert = CertificateFactory() 35 | self.assertIsNotNone(cert.type) 36 | self.assertIsNotNone(cert.name) 37 | self.assertIsNotNone(cert.dn) 38 | self.assertIsNone(cert.parent) 39 | self.assertIsNotNone(cert.crl_distribution_url) 40 | self.assertIsNotNone(cert.ocsp_distribution_host) 41 | self.assertIsNotNone(cert.owner) 42 | self.assertIsNotNone(cert.serial) 43 | self.assertIsNotNone(cert.created_at) 44 | self.assertIsNotNone(cert.expires_at) 45 | self.assertIsNone(cert.revoked_at) 46 | self.assertIsNotNone(cert.revoked_uuid) 47 | --------------------------------------------------------------------------------