├── .gitignore ├── CHANGES ├── LICENSE ├── README.md ├── data ├── etc │ └── pritunl.conf ├── init.d.sysvinit │ └── pritunl ├── init.d.upstart │ └── pritunl ├── init │ └── pritunl.conf ├── systemd │ ├── pritunl-web.service │ └── pritunl.service └── var │ ├── pritunl.log │ └── pritunl.log.1 ├── pritunl ├── __init__.py ├── __main__.py ├── acme.py ├── acmetiny.py ├── app.py ├── auth │ ├── __init__.py │ ├── administrator.py │ ├── app.py │ ├── csrf.py │ └── utils.py ├── authorizer │ ├── __init__.py │ └── authorizer.py ├── cache.py ├── cachelocal │ ├── __init__.py │ └── cache_trie.py ├── callbacks │ ├── __init__.py │ └── callbacks.py ├── callqueue.py ├── clients │ ├── __init__.py │ └── clients.py ├── constants.py ├── database │ ├── __init__.py │ └── utils.py ├── docdb.py ├── event.py ├── exceptions.py ├── firewall │ ├── __init__.py │ └── firewall.py ├── handlers │ ├── __init__.py │ ├── admin.py │ ├── auth.py │ ├── before_request.py │ ├── device.py │ ├── errors.py │ ├── event.py │ ├── host.py │ ├── key.py │ ├── link.py │ ├── log.py │ ├── logs.py │ ├── org.py │ ├── ping.py │ ├── robots.py │ ├── server.py │ ├── settings.py │ ├── sso.py │ ├── static.py │ ├── status.py │ ├── subscription.py │ └── user.py ├── helpers.py ├── host │ ├── __init__.py │ ├── host.py │ ├── usage.py │ ├── usage_utils.py │ └── utils.py ├── ipaddress.py ├── iptables.py ├── journal │ ├── __init__.py │ └── events.py ├── limiter.py ├── link │ ├── __init__.py │ ├── link.py │ └── utils.py ├── listener.py ├── logger │ ├── __init__.py │ ├── entry.py │ ├── filter.py │ ├── formatter.py │ ├── handler.py │ └── view.py ├── messenger.py ├── mongo │ ├── __init__.py │ ├── dict.py │ ├── list.py │ └── object.py ├── monitoring │ ├── __init__.py │ └── utils.py ├── ntplib.py ├── objcache.py ├── organization │ ├── __init__.py │ ├── organization.py │ └── utils.py ├── patches.py ├── plugins │ ├── __init__.py │ ├── example.py │ ├── plugins.py │ └── utils.py ├── pooler.py ├── poolers │ ├── __init__.py │ ├── dh_params.py │ ├── org.py │ └── user.py ├── pyrad │ ├── __init__.py │ ├── bidict.py │ ├── client.py │ ├── curved.py │ ├── dictfile.py │ ├── dictionary.py │ ├── host.py │ ├── packet.py │ ├── proxy.py │ ├── server.py │ └── tools.py ├── queue │ ├── __init__.py │ ├── com.py │ ├── queue.py │ └── utils.py ├── queues │ ├── __init__.py │ ├── assign_ip_addr.py │ ├── assign_ip_pool.py │ ├── dh_params.py │ ├── init_org_pooled.py │ ├── init_user.py │ ├── init_user_pooled.py │ └── unassign_ip_addr.py ├── radius.py ├── runners │ ├── __init__.py │ ├── event.py │ ├── firewall.py │ ├── host.py │ ├── instance.py │ ├── journal.py │ ├── limiter.py │ ├── listener.py │ ├── logger.py │ ├── queue.py │ ├── server.py │ ├── settings.py │ ├── subscription.py │ ├── task.py │ ├── time_sync.py │ ├── tokens.py │ ├── transaction.py │ ├── update_server.py │ └── updates.py ├── server │ ├── __init__.py │ ├── bandwidth.py │ ├── bridge.py │ ├── instance.py │ ├── instance_com.py │ ├── instance_link.py │ ├── ip_pool.py │ ├── listener.py │ ├── output.py │ ├── output_link.py │ ├── server.py │ └── utils.py ├── settings │ ├── __init__.py │ ├── app.py │ ├── conf.py │ ├── group_base.py │ ├── group_file.py │ ├── group_local.py │ ├── group_mongo.py │ ├── local.py │ ├── mongo.py │ ├── settings.py │ ├── user.py │ └── vpn.py ├── setup │ ├── __init__.py │ ├── boto_conf.py │ ├── cache.py │ ├── check.py │ ├── clean.py │ ├── demo.py │ ├── dns.py │ ├── handlers.py │ ├── host.py │ ├── host_fix.py │ ├── local.py │ ├── logger.py │ ├── mongo.py │ ├── monitoring.py │ ├── ndppd.py │ ├── plugins.py │ ├── poolers.py │ ├── public_ip.py │ ├── runners.py │ ├── server.py │ ├── server_fix.py │ ├── server_listeners.py │ ├── settings.py │ ├── signal_handler.py │ ├── subscription.py │ ├── temp_path.py │ ├── token.py │ └── vault.py ├── sso │ ├── __init__.py │ ├── authzero.py │ ├── azure.py │ ├── duo.py │ ├── google.py │ ├── jumpcloud.py │ ├── okta.py │ ├── onelogin.py │ ├── radius.py │ ├── token.py │ ├── utils.py │ └── yubico.py ├── static │ ├── __init__.py │ ├── static.py │ └── utils.py ├── subscription.py ├── system │ ├── __init__.py │ └── sysctl.py ├── task.py ├── tasks │ ├── __init__.py │ ├── acme_update.py │ ├── clean_client_pool.py │ ├── clean_ip_pool.py │ ├── clean_network_links.py │ ├── clean_network_lock.py │ ├── clean_servers.py │ ├── clean_users.py │ ├── clean_vxlans.py │ ├── host.py │ ├── link.py │ ├── pooler.py │ ├── route.py │ ├── server.py │ └── sync_ip_pool.py ├── transaction │ ├── __init__.py │ ├── action.py │ ├── collection.py │ └── transaction.py ├── tunldb.py ├── upgrade │ ├── __init__.py │ ├── upgrade_1_17.py │ ├── upgrade_1_18.py │ ├── upgrade_1_24.py │ ├── upgrade_1_4.py │ ├── upgrade_1_5.py │ └── utils.py ├── user │ ├── __init__.py │ ├── user.py │ └── utils.py ├── utils │ ├── __init__.py │ ├── auth.py │ ├── aws.py │ ├── cert.py │ ├── filter.py │ ├── json_helpers.py │ ├── least_common_counter.py │ ├── mail.py │ ├── md5_hash.py │ ├── misc.py │ ├── network.py │ ├── none_queue.py │ ├── oracle.py │ ├── proc.py │ └── sig.py ├── vault │ ├── __init__.py │ ├── batch.py │ ├── item.py │ ├── nonces.py │ ├── utils.py │ └── vault.py └── vxlan │ ├── __init__.py │ └── vxlan.py ├── requirements.txt ├── selinux ├── pritunl.fc ├── pritunl.te ├── pritunl_dns.fc ├── pritunl_dns.te ├── pritunl_web.fc └── pritunl_web.te ├── selinux8 ├── pritunl.fc ├── pritunl.te ├── pritunl_dns.fc ├── pritunl_dns.te ├── pritunl_web.fc └── pritunl_web.te ├── selinux9 ├── pritunl.fc ├── pritunl.te ├── pritunl_dns.fc ├── pritunl_dns.te ├── pritunl_web.fc └── pritunl_web.te ├── server.py ├── setup.py ├── tools ├── add_aws_ranges.py ├── ami_init.sh ├── ami_mongo_init.sh ├── aws │ ├── pritunl-db.template │ └── pritunl.template ├── build.sh ├── builder.py ├── clean_capitalization.py ├── development_pritunl.conf ├── devices_sync.py ├── grafana.json ├── stress_testing │ ├── README.md │ ├── add_test_users.py │ ├── connect_all.go │ ├── download_all_users.py │ ├── find_missing.py │ ├── get_test_names.py │ ├── names │ ├── terraform │ │ └── pritunl.tf │ └── test_client │ │ ├── Dockerfile │ │ ├── client.go │ │ ├── commander.go │ │ └── controller.go ├── test_pritunl.py └── vagrant_provision.sh └── www ├── Gruntfile.js ├── collections ├── admin.js ├── adminAudit.js ├── device.js ├── event.js ├── host.js ├── link.js ├── linkLocation.js ├── log.js ├── org.js ├── server.js ├── serverHost.js ├── serverLink.js ├── serverOrg.js ├── serverRoute.js ├── user.js ├── userAudit.js ├── userDevice.js └── userServer.js ├── dart ├── lib │ ├── alert.dart │ ├── all_aware.dart │ ├── bases │ │ ├── form_control │ │ │ └── form_control.dart │ │ └── modal_content │ │ │ └── modal_content.dart │ ├── collection.dart │ ├── collections │ │ ├── collections.dart │ │ ├── events.dart │ │ ├── log_entries.dart │ │ ├── organizations.dart │ │ ├── server_hosts.dart │ │ ├── server_orgs.dart │ │ ├── servers.dart │ │ └── users.dart │ ├── components │ │ ├── alert │ │ │ ├── alert.dart │ │ │ └── alert.scss │ │ ├── alert_global │ │ │ └── alert_global.dart │ │ ├── boilerplate │ │ │ ├── boilerplate.dart │ │ │ ├── boilerplate.html │ │ │ └── boilerplate.scss │ │ ├── box_label │ │ │ ├── box_label.dart │ │ │ └── box_label.scss │ │ ├── btn │ │ │ ├── btn.dart │ │ │ └── btn.scss │ │ ├── checkbox │ │ │ ├── checkbox.dart │ │ │ └── checkbox.scss │ │ ├── components.dart │ │ ├── container │ │ │ ├── container.dart │ │ │ └── container.scss │ │ ├── editor │ │ │ ├── editor.dart │ │ │ └── editor.scss │ │ ├── form_group │ │ │ ├── form_group.dart │ │ │ └── form_group.scss │ │ ├── form_input │ │ │ ├── form_input.dart │ │ │ └── form_input.scss │ │ ├── form_select │ │ │ ├── form_select.dart │ │ │ └── form_select.scss │ │ ├── form_textarea │ │ │ ├── form_textarea.dart │ │ │ └── form_textarea.scss │ │ ├── fraction │ │ │ ├── fraction.dart │ │ │ └── fraction.scss │ │ ├── glyphicon │ │ │ ├── glyphicon.dart │ │ │ └── glyphicon.scss │ │ ├── log_entries │ │ │ ├── log_entries.dart │ │ │ ├── log_entries.html │ │ │ └── log_entries.scss │ │ ├── modal │ │ │ ├── modal.dart │ │ │ ├── modal.html │ │ │ └── modal.scss │ │ ├── navbar │ │ │ ├── navbar.dart │ │ │ ├── navbar.html │ │ │ └── navbar.scss │ │ ├── org_add │ │ │ ├── org_add.dart │ │ │ └── org_add.html │ │ ├── org_del │ │ │ ├── org_del.dart │ │ │ └── org_del.html │ │ ├── org_modify │ │ │ ├── org_modify.dart │ │ │ └── org_modify.html │ │ ├── organization │ │ │ ├── organization.dart │ │ │ ├── organization.html │ │ │ └── organization.scss │ │ ├── organizations │ │ │ ├── organizations.dart │ │ │ ├── organizations.html │ │ │ └── organizations.scss │ │ ├── qrcode │ │ │ ├── qrcode.dart │ │ │ └── qrcode.html │ │ ├── server │ │ │ ├── server.dart │ │ │ ├── server.html │ │ │ └── server.scss │ │ ├── server_del │ │ │ ├── server_del.dart │ │ │ └── server_del.html │ │ ├── servers │ │ │ ├── servers.dart │ │ │ ├── servers.html │ │ │ └── servers.scss │ │ ├── status │ │ │ ├── status.dart │ │ │ ├── status.html │ │ │ └── status.scss │ │ ├── user │ │ │ ├── user.dart │ │ │ ├── user.html │ │ │ └── user.scss │ │ ├── user_add │ │ │ ├── user_add.dart │ │ │ └── user_add.html │ │ ├── user_add_bulk │ │ │ ├── user_add_bulk.dart │ │ │ └── user_add_bulk.html │ │ ├── user_del │ │ │ ├── user_del.dart │ │ │ ├── user_del.html │ │ │ └── user_del.scss │ │ ├── user_email │ │ │ ├── user_email.dart │ │ │ ├── user_email.html │ │ │ └── user_email.scss │ │ ├── user_key_links │ │ │ ├── user_key_links.dart │ │ │ ├── user_key_links.html │ │ │ └── user_key_links.scss │ │ ├── user_modify │ │ │ ├── user_modify.dart │ │ │ └── user_modify.html │ │ └── user_otp │ │ │ ├── user_otp.dart │ │ │ ├── user_otp.html │ │ │ └── user_otp.scss │ ├── decorators │ │ ├── autofocus.dart │ │ ├── conditional.dart │ │ ├── decorators.dart │ │ ├── modal.dart │ │ ├── modal_attach.dart │ │ ├── noselect.dart │ │ ├── shift_click.dart │ │ └── tooltip.dart │ ├── exceptions.dart │ ├── fonts │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ ├── fredoka-one.eot │ │ ├── fredoka-one.woff │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ ├── ubuntu-bold.eot │ │ ├── ubuntu-bold.woff │ │ ├── ubuntu.eot │ │ └── ubuntu.woff │ ├── formatters │ │ ├── capitalize.dart │ │ ├── datetime.dart │ │ ├── formatters.dart │ │ ├── fraction.dart │ │ ├── slash.dart │ │ └── timer.dart │ ├── logger.dart │ ├── model.dart │ ├── models │ │ ├── event.dart │ │ ├── key.dart │ │ ├── log_entry.dart │ │ ├── models.dart │ │ ├── organization.dart │ │ ├── server.dart │ │ ├── server_host.dart │ │ ├── server_link_output.dart │ │ ├── server_org.dart │ │ ├── server_output.dart │ │ ├── status.dart │ │ └── user.dart │ ├── pritunl.dart │ ├── remote.dart │ ├── routers │ │ ├── main.dart │ │ └── routers.dart │ ├── settings │ │ └── settings.dart │ ├── styles │ │ ├── base.scss │ │ ├── colors.scss │ │ ├── globals.scss │ │ ├── mixins.scss │ │ ├── variables.scss │ │ └── vendor │ │ │ └── bootstrap.scss │ ├── transformers │ │ └── sass.dart │ ├── utils │ │ └── utils.dart │ └── views │ │ ├── dashboard.html │ │ ├── servers.html │ │ └── users.html ├── pubspec.lock ├── pubspec.yaml └── web │ ├── index.html │ ├── main.dart │ └── vendor │ ├── ace │ ├── ace.js │ ├── mode-log.js │ ├── mode-sh.js │ ├── mode-text.js │ ├── theme-chrome.js │ ├── theme-github.js │ └── theme-pritunl.js │ ├── qrcode.js │ └── qrcode.min.js ├── dbconf.html ├── demo ├── ajax.js ├── data.js ├── demo.html ├── demo.ovpn └── demo.tar ├── duo.html ├── fonts ├── FontAwesome.otf ├── fontawesome-webfont.eot ├── fontawesome-webfont.svg ├── fontawesome-webfont.ttf ├── fontawesome-webfont.woff ├── fontawesome-webfont.woff2 ├── fredoka-one.eot ├── fredoka-one.woff ├── glyphicons-halflings-regular.eot ├── glyphicons-halflings-regular.svg ├── glyphicons-halflings-regular.ttf ├── glyphicons-halflings-regular.woff ├── ubuntu-bold.eot ├── ubuntu-bold.woff ├── ubuntu.eot └── ubuntu.woff ├── img ├── favicon.ico ├── header_logo.png ├── header_logo.xcf ├── logo.svg ├── logo100.png ├── logo14.png ├── logo140.png ├── logo16.png ├── logo192.png ├── logo256.png ├── logo32.png ├── logo512.png ├── logo64.png ├── logo_code.png ├── logo_full.png ├── logo_full.xcf ├── logo_full2.png ├── logo_full2.xcf ├── logo_full3.png ├── logo_full3.xcf ├── logo_stripe.png └── logo_stripe.svg ├── index.html ├── init ├── demo.js ├── production.js └── testing.js ├── key_view.html ├── key_view_dark.html ├── login.html ├── logo.png ├── main.js ├── models ├── admin.js ├── authSession.js ├── device.js ├── event.js ├── host.js ├── hostUsage.js ├── key.js ├── link.js ├── linkHost.js ├── linkHostConf.js ├── linkHostUri.js ├── linkLocation.js ├── linkPeer.js ├── linkRoute.js ├── linkRouteExclude.js ├── linkTransit.js ├── log.js ├── logs.js ├── org.js ├── server.js ├── serverBandwidth.js ├── serverHost.js ├── serverLink.js ├── serverOrg.js ├── serverOutput.js ├── serverOutputLink.js ├── serverRoute.js ├── settings.js ├── state.js ├── status.js ├── subscription.js ├── user.js ├── userAudit.js ├── userBulk.js ├── userDevice.js ├── userServer.js └── zones.js ├── package-lock.json ├── package.json ├── root ├── demo_index.html ├── index.html └── robots.txt ├── routers └── main.js ├── styles └── vendor │ ├── bootstrap.less │ ├── fontawesome.less │ ├── main.css │ ├── rickshaw.less │ └── select2.less ├── success.html ├── templates ├── admins.html ├── adminsList.html ├── adminsListItem.html ├── alert.html ├── dashboard.html ├── dashboardLog.html ├── dashboardLogItem.html ├── dashboardStatus.html ├── devicesList.html ├── devicesListItem.html ├── header.html ├── hostUsage.html ├── hostsList.html ├── hostsListItem.html ├── linkLocationsList.html ├── linkLocationsListItem.html ├── linksList.html ├── linksListItem.html ├── login.html ├── modal.html ├── modalAddAdmin.html ├── modalAddLink.html ├── modalAddLocHost.html ├── modalAddLocPeer.html ├── modalAddLocRoute.html ├── modalAddLocTransit.html ├── modalAddLocation.html ├── modalAddOrg.html ├── modalAddRoute.html ├── modalAddUser.html ├── modalAddUserBulk.html ├── modalAttachHost.html ├── modalAttachLink.html ├── modalAttachOrg.html ├── modalAuditUser.html ├── modalDeleteAdmins.html ├── modalDeleteHost.html ├── modalDeleteLink.html ├── modalDeleteLocHost.html ├── modalDeleteLocPeer.html ├── modalDeleteLocRoute.html ├── modalDeleteLocTransit.html ├── modalDeleteLocation.html ├── modalDeleteOrg.html ├── modalDeleteServer.html ├── modalDeleteUserDevice.html ├── modalDeleteUsers.html ├── modalDetachHost.html ├── modalDetachLink.html ├── modalDetachOrg.html ├── modalDeviceRegister.html ├── modalEmailUsers.html ├── modalEnterprise.html ├── modalHostSettings.html ├── modalKeyLink.html ├── modalLocHostConf.html ├── modalLocHostUri.html ├── modalModifyAdmin.html ├── modalModifyLink.html ├── modalModifyLocHost.html ├── modalModifyLocation.html ├── modalModifyRoute.html ├── modalNotification.html ├── modalOtpAuth.html ├── modalRekeyLink.html ├── modalRemoveRoute.html ├── modalRenameOrg.html ├── modalRenameUser.html ├── modalServerSettings.html ├── modalSettings.html ├── modalSubscribe.html ├── orgsList.html ├── orgsListItem.html ├── serverBandwidth.html ├── serverHostsList.html ├── serverHostsListItem.html ├── serverLinksList.html ├── serverLinksListItem.html ├── serverOrgsList.html ├── serverOrgsListItem.html ├── serverRoutesList.html ├── serverRoutesListItem.html ├── serversList.html ├── serversListItem.html ├── userDevicesList.html ├── userDevicesListItem.html ├── userServersList.html ├── userServersListItem.html ├── usersList.html └── usersListItem.html ├── upgrade.html ├── vendor ├── ace │ ├── ace.js │ ├── mode-log.js │ ├── mode-sh.js │ ├── mode-text.js │ ├── theme-chrome.js │ ├── theme-github.js │ └── theme-pritunl.js ├── backbone │ ├── backbone.js │ └── backbone.min.js ├── bootstrap │ ├── bootstrap.js │ └── bootstrap.min.js ├── d3 │ ├── d3.js │ └── d3.min.js ├── dist │ ├── css │ │ └── main.ba2871d7609300bffd5be71db89cfb10.css │ ├── fonts │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ ├── fontawesome-webfont.woff2 │ │ ├── fredoka-one.eot │ │ ├── fredoka-one.woff │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ ├── ubuntu-bold.eot │ │ ├── ubuntu-bold.woff │ │ ├── ubuntu.eot │ │ └── ubuntu.woff │ ├── index.html │ ├── js │ │ ├── main.85e69cf5c29607b79a29cc9a230bae78.js │ │ └── require.min.js │ └── robots.txt ├── jquery │ ├── jquery.js │ └── jquery.min.js ├── less │ ├── less.js │ └── less.min.js ├── qrcode │ ├── qrcode.js │ └── qrcode.min.js ├── require │ ├── require.js │ └── require.min.js ├── requireText │ └── text.js ├── rickshaw │ ├── rickshaw.js │ └── rickshaw.min.js ├── select │ ├── select.js │ └── select.min.js └── underscore │ ├── underscore.js │ └── underscore.min.js ├── views ├── admins.js ├── adminsList.js ├── adminsListItem.js ├── alert.js ├── dashboard.js ├── dashboardLog.js ├── dashboardLogItem.js ├── dashboardStatus.js ├── devices.js ├── devicesList.js ├── devicesListItem.js ├── header.js ├── hostUsage.js ├── hosts.js ├── hostsList.js ├── hostsListItem.js ├── linkLocationsList.js ├── linkLocationsListItem.js ├── links.js ├── linksList.js ├── linksListItem.js ├── list.js ├── login.js ├── loginBackdrop.js ├── logs.js ├── modal.js ├── modalAddAdmin.js ├── modalAddLink.js ├── modalAddLocHost.js ├── modalAddLocPeer.js ├── modalAddLocRoute.js ├── modalAddLocTransit.js ├── modalAddLocation.js ├── modalAddOrg.js ├── modalAddRoute.js ├── modalAddServer.js ├── modalAddUser.js ├── modalAddUserBulk.js ├── modalAttachHost.js ├── modalAttachLink.js ├── modalAttachOrg.js ├── modalAuditUser.js ├── modalDeleteAdmins.js ├── modalDeleteHost.js ├── modalDeleteLink.js ├── modalDeleteLocHost.js ├── modalDeleteLocPeer.js ├── modalDeleteLocRoute.js ├── modalDeleteLocTransit.js ├── modalDeleteLocation.js ├── modalDeleteOrg.js ├── modalDeleteServer.js ├── modalDeleteUserDevice.js ├── modalDeleteUsers.js ├── modalDetachHost.js ├── modalDetachLink.js ├── modalDetachOrg.js ├── modalDeviceRegister.js ├── modalEmailUsers.js ├── modalEnterprise.js ├── modalHostSettings.js ├── modalKeyLink.js ├── modalLocHostConf.js ├── modalLocHostUbntConf.js ├── modalLocHostUri.js ├── modalLogs.js ├── modalModifyAdmin.js ├── modalModifyLink.js ├── modalModifyLocHost.js ├── modalModifyLocation.js ├── modalModifyRoute.js ├── modalNotification.js ├── modalOtpAuth.js ├── modalRekeyLink.js ├── modalRemoveRoute.js ├── modalRenameOrg.js ├── modalRenameUser.js ├── modalServerSettings.js ├── modalSettings.js ├── modalSubscribe.js ├── orgsList.js ├── orgsListItem.js ├── serverBandwidth.js ├── serverHostsList.js ├── serverHostsListItem.js ├── serverLinksList.js ├── serverLinksListItem.js ├── serverOrgsList.js ├── serverOrgsListItem.js ├── serverOutput.js ├── serverOutputLink.js ├── serverRoutesList.js ├── serverRoutesListItem.js ├── servers.js ├── serversList.js ├── serversListItem.js ├── text.js ├── userDevicesList.js ├── userDevicesListItem.js ├── userServersList.js ├── userServersListItem.js ├── users.js ├── usersList.js └── usersListItem.js └── yubico.html /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .DS_Store? 3 | ._* 4 | .Spotlight-V100 5 | .Trashes 6 | Icon? 7 | ehthumbs.db 8 | Thumbs.db 9 | *.pyc 10 | *.egg 11 | *.egg-info 12 | *.tfstate 13 | *.tfstate.backup 14 | .sass-cache 15 | /.vagrant 16 | /build 17 | /dist 18 | /var 19 | /pritunl.egg-info 20 | /pritunl.db 21 | /www/node_modules 22 | /www/styles/* 23 | !/www/styles/vendor 24 | /tools/build_keys.json 25 | /tools/development_pritunl.conf 26 | -------------------------------------------------------------------------------- /data/etc/pritunl.conf: -------------------------------------------------------------------------------- 1 | { 2 | "debug": false, 3 | "bind_addr": "0.0.0.0", 4 | "port": 443, 5 | "log_path": "/var/log/pritunl.log", 6 | "temp_path": "/tmp/pritunl_%r", 7 | "local_address_interface": "auto", 8 | "mongodb_uri": "" 9 | } 10 | -------------------------------------------------------------------------------- /data/init.d.sysvinit/pritunl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: pritunl 4 | # Required-Start: $local_fs $network $named $time $syslog 5 | # Required-Stop: $local_fs $network $named $time $syslog 6 | # Default-Start: 2 3 4 5 7 | # Default-Stop: 0 1 6 8 | # Description: Pritunl Daemon 9 | ### END INIT INFO 10 | 11 | PIDFILE=/var/run/pritunl.pid 12 | 13 | start() { 14 | if [ -f $PIDFILE ] && kill -0 $(cat $PIDFILE); then 15 | echo 'Service already running' >&2 16 | return 1 17 | fi 18 | ulimit -n 50000 19 | echo 'Starting service...' >&2 20 | pritunl start --daemon --pidfile $PIDFILE > /dev/null 21 | echo 'Service started' >&2 22 | } 23 | 24 | stop() { 25 | if [ ! -f "$PIDFILE" ] || ! kill -0 $(cat "$PIDFILE"); then 26 | echo 'Service not running' >&2 27 | return 1 28 | fi 29 | echo 'Stopping service...' >&2 30 | kill -15 $(cat "$PIDFILE") && rm -f "$PIDFILE" 31 | echo 'Service stopped' >&2 32 | } 33 | 34 | case "$1" in 35 | start) 36 | start 37 | ;; 38 | stop) 39 | stop 40 | ;; 41 | restart) 42 | stop 43 | start 44 | ;; 45 | *) 46 | echo "Usage: $0 {start|stop|restart}" 47 | esac 48 | -------------------------------------------------------------------------------- /data/init/pritunl.conf: -------------------------------------------------------------------------------- 1 | description "Pritunl Daemon" 2 | limit nofile 50000 50000 3 | 4 | start on runlevel [2345] 5 | stop on runlevel [!2345] 6 | 7 | exec pritunl start 8 | -------------------------------------------------------------------------------- /data/systemd/pritunl-web.service: -------------------------------------------------------------------------------- 1 | [Service] 2 | User=pritunl-web 3 | Group=pritunl-web 4 | EnvironmentFile=/var/lib/pritunl/pritunl_web_env 5 | ExecStart=/usr/bin/pritunl-web 6 | TimeoutStopSec=5s 7 | LimitNOFILE=500000 8 | LimitNPROC=512 9 | PrivateTmp=true 10 | ProtectSystem=full 11 | ProtectHostname=true 12 | ProtectKernelTunables=true 13 | AmbientCapabilities=CAP_NET_BIND_SERVICE 14 | -------------------------------------------------------------------------------- /data/systemd/pritunl.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Pritunl Daemon 3 | 4 | [Service] 5 | LimitNOFILE=500000 6 | ExecStart=%PREFIX%/bin/pritunl start 7 | SuccessExitStatus=SIGALRM 8 | TimeoutStopSec=20 9 | 10 | [Install] 11 | WantedBy=multi-user.target 12 | -------------------------------------------------------------------------------- /data/var/pritunl.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/data/var/pritunl.log -------------------------------------------------------------------------------- /data/var/pritunl.log.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/data/var/pritunl.log.1 -------------------------------------------------------------------------------- /pritunl/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl import patches 2 | from pritunl.constants import * 3 | 4 | __title__ = 'pritunl' 5 | __version__ = '1.32.4278.46' 6 | __author__ = 'Pritunl' 7 | __email__ = 'contact@pritunl.com' 8 | __license__ = 'Custom' 9 | __copyright__ = 'Copyright 2013-2021 Pritunl <contact@pritunl.com>' 10 | conf_path = DEFAULT_CONF_PATH 11 | 12 | def set_conf_path(path=None): 13 | if path: 14 | global conf_path 15 | conf_path = path 16 | 17 | def init_server(): 18 | from pritunl import app 19 | from pritunl import setup 20 | setup.setup_all() 21 | app.run_server() 22 | -------------------------------------------------------------------------------- /pritunl/auth/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.auth.administrator import * 2 | from pritunl.auth.app import * 3 | from pritunl.auth.csrf import * 4 | from pritunl.auth.utils import * 5 | -------------------------------------------------------------------------------- /pritunl/auth/app.py: -------------------------------------------------------------------------------- 1 | from pritunl.auth.administrator import check_session 2 | 3 | import flask 4 | 5 | def session_auth(call): 6 | def _wrapped(*args, **kwargs): 7 | if not check_session(True): 8 | return flask.abort(401) 9 | flask.g.valid = True 10 | return call(*args, **kwargs) 11 | _wrapped.__name__ = '%s_session_auth' % call.__name__ 12 | return _wrapped 13 | 14 | def session_light_auth(call): 15 | def _wrapped(*args, **kwargs): 16 | if not check_session(False): 17 | return flask.abort(401) 18 | flask.g.valid = True 19 | return call(*args, **kwargs) 20 | _wrapped.__name__ = '%s_session_light_auth' % call.__name__ 21 | return _wrapped 22 | 23 | def open_auth(call): 24 | def _wrapped(*args, **kwargs): 25 | flask.g.valid = True 26 | return call(*args, **kwargs) 27 | _wrapped.__name__ = '%s_open_auth' % call.__name__ 28 | return _wrapped 29 | -------------------------------------------------------------------------------- /pritunl/auth/csrf.py: -------------------------------------------------------------------------------- 1 | from pritunl import utils 2 | from pritunl import mongo 3 | 4 | def get_token(admin_id): 5 | coll = mongo.get_collection('auth_csrf_tokens') 6 | token = utils.generate_secret() 7 | 8 | coll.insert_one({ 9 | '_id': token, 10 | 'admin_id': admin_id, 11 | 'timestamp': utils.now(), 12 | }) 13 | 14 | return token 15 | 16 | def validate_token(admin_id, token): 17 | coll = mongo.get_collection('auth_csrf_tokens') 18 | 19 | return bool(coll.find_one({ 20 | '_id': token, 21 | 'admin_id': admin_id, 22 | })) 23 | -------------------------------------------------------------------------------- /pritunl/authorizer/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.authorizer.authorizer import Authorizer 2 | -------------------------------------------------------------------------------- /pritunl/cachelocal/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.cachelocal.cache_trie import * 2 | 3 | from pritunl import tunldb 4 | 5 | cache_db = tunldb.TunlDB(strict=False) 6 | -------------------------------------------------------------------------------- /pritunl/callbacks/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.callbacks.callbacks import * 2 | -------------------------------------------------------------------------------- /pritunl/clients/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.clients.clients import Clients 2 | -------------------------------------------------------------------------------- /pritunl/database/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.database.utils import * 2 | -------------------------------------------------------------------------------- /pritunl/database/utils.py: -------------------------------------------------------------------------------- 1 | from pritunl.constants import * 2 | from pritunl import logger 3 | 4 | import bson 5 | import time 6 | 7 | start = time.time() 8 | 9 | def ObjectId(oid=None): 10 | if oid is not None: 11 | oid = str(oid) 12 | if oid is None or len(oid) != 32: 13 | try: 14 | return bson.ObjectId(oid) 15 | except: 16 | logger.exception('Failed to convert object id', 'utils', 17 | object_id=oid, 18 | ) 19 | return oid 20 | 21 | def ObjectIdSilent(oid=None): 22 | if oid is not None: 23 | oid = str(oid) 24 | if oid is None or len(oid) != 32: 25 | return bson.ObjectId(oid) 26 | return oid 27 | 28 | def ParseObjectId(oid): 29 | if oid: 30 | return bson.ObjectId(str(oid)) 31 | -------------------------------------------------------------------------------- /pritunl/firewall/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.firewall.firewall import * 2 | -------------------------------------------------------------------------------- /pritunl/handlers/__init__.py: -------------------------------------------------------------------------------- 1 | import pritunl.handlers.errors 2 | import pritunl.handlers.auth 3 | import pritunl.handlers.before_request 4 | import pritunl.handlers.device 5 | import pritunl.handlers.event 6 | import pritunl.handlers.host 7 | import pritunl.handlers.key 8 | import pritunl.handlers.link 9 | import pritunl.handlers.log 10 | import pritunl.handlers.logs 11 | import pritunl.handlers.org 12 | import pritunl.handlers.ping 13 | import pritunl.handlers.robots 14 | import pritunl.handlers.server 15 | import pritunl.handlers.settings 16 | import pritunl.handlers.static 17 | import pritunl.handlers.status 18 | import pritunl.handlers.sso 19 | import pritunl.handlers.subscription 20 | import pritunl.handlers.user 21 | import pritunl.handlers.admin 22 | -------------------------------------------------------------------------------- /pritunl/handlers/before_request.py: -------------------------------------------------------------------------------- 1 | from pritunl.constants import * 2 | from pritunl import settings 3 | from pritunl import app 4 | from pritunl import database 5 | 6 | import flask 7 | 8 | @app.app.before_request 9 | def before_request(): 10 | if settings.local.www_state == DISABLED: 11 | raise flask.abort(401, settings.local.notification) 12 | 13 | @app.app.url_value_preprocessor 14 | def parse_object_id(_, values): 15 | if values: 16 | for key in values: 17 | if key.endswith('_id'): 18 | val = values[key] 19 | if len(val) > 10: 20 | try: 21 | values[key] = database.ObjectIdSilent(val) 22 | except: 23 | values[key] = None 24 | -------------------------------------------------------------------------------- /pritunl/handlers/event.py: -------------------------------------------------------------------------------- 1 | from pritunl.helpers import * 2 | from pritunl import utils 3 | from pritunl import event 4 | from pritunl import app 5 | from pritunl import auth 6 | from pritunl import settings 7 | from pritunl import database 8 | 9 | import flask 10 | import time 11 | 12 | @app.app.route('/event', methods=['GET']) 13 | @app.app.route('/event/<cursor>', methods=['GET']) 14 | @auth.session_auth 15 | def event_get(cursor=None): 16 | if settings.app.demo_mode: 17 | time.sleep(0.1) 18 | return utils.jsonify([{ 19 | 'id': 'demo', 20 | }]) 21 | 22 | if check_global_interrupt(): 23 | raise flask.abort(500) 24 | 25 | if cursor is not None: 26 | cursor = database.ParseObjectId(cursor) 27 | 28 | return utils.jsonify(event.get_events( 29 | cursor=cursor, yield_app_server=True)) 30 | -------------------------------------------------------------------------------- /pritunl/handlers/log.py: -------------------------------------------------------------------------------- 1 | from pritunl.constants import * 2 | from pritunl import utils 3 | from pritunl import app 4 | from pritunl import auth 5 | from pritunl import logger 6 | from pritunl import settings 7 | 8 | @app.app.route('/log', methods=['GET']) 9 | @auth.session_auth 10 | def log_get(): 11 | if settings.app.demo_mode: 12 | return utils.jsonify(DEMO_LOG_ENTRIES) 13 | 14 | log_entries = [] 15 | 16 | for log_entry in logger.iter_log_entries(): 17 | log_entries.append(log_entry.dict()) 18 | 19 | return utils.jsonify(log_entries) 20 | -------------------------------------------------------------------------------- /pritunl/handlers/logs.py: -------------------------------------------------------------------------------- 1 | from pritunl.constants import * 2 | 3 | from pritunl import app 4 | from pritunl import logger 5 | from pritunl import utils 6 | from pritunl import auth 7 | from pritunl import settings 8 | 9 | @app.app.route('/logs', methods=['GET']) 10 | @auth.session_auth 11 | def logs_get(): 12 | if settings.app.demo_mode: 13 | return utils.jsonify({ 14 | 'output': DEMO_LOGS, 15 | }) 16 | 17 | log_view = logger.LogView() 18 | return utils.jsonify({ 19 | 'output': log_view.get_log_lines( 20 | natural=True, 21 | formatted=False, 22 | reverse=True, 23 | ).split('\n'), 24 | }) 25 | -------------------------------------------------------------------------------- /pritunl/handlers/ping.py: -------------------------------------------------------------------------------- 1 | from pritunl import settings 2 | from pritunl import utils 3 | from pritunl import app 4 | from pritunl import auth 5 | 6 | import flask 7 | import datetime 8 | 9 | @app.app.route('/ping', methods=['GET']) 10 | @app.app.route('/check', methods=['GET']) 11 | @auth.open_auth 12 | def ping_get(): 13 | ping_timestamp = settings.local.host_ping_timestamp 14 | host_ping_ttl = datetime.timedelta(seconds=settings.app.host_ping_ttl) 15 | 16 | if ping_timestamp and utils.now() > ping_timestamp + host_ping_ttl: 17 | raise flask.abort(504) 18 | else: 19 | return utils.response(data='OK') 20 | -------------------------------------------------------------------------------- /pritunl/handlers/robots.py: -------------------------------------------------------------------------------- 1 | from pritunl.constants import * 2 | from pritunl import utils 3 | from pritunl import app 4 | from pritunl import auth 5 | 6 | @app.app.route('/robots.txt', methods=['GET']) 7 | @auth.open_auth 8 | def robots_get(): 9 | return utils.response(data=ROBOTS) 10 | -------------------------------------------------------------------------------- /pritunl/host/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.host.host import Host 2 | from pritunl.host.usage import HostUsage 3 | from pritunl.host.utils import * 4 | 5 | from pritunl import docdb 6 | 7 | global_clients = docdb.DocDb( 8 | 'instance_id', 9 | 'client_id', 10 | ) 11 | 12 | global_servers = set() 13 | dns_mapping_servers = set() 14 | -------------------------------------------------------------------------------- /pritunl/journal/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.journal.events import * 2 | 3 | from pritunl.constants import * 4 | from pritunl import settings 5 | from pritunl import utils 6 | 7 | import collections 8 | import bson 9 | 10 | journal_queue = collections.deque() 11 | 12 | def get_base_entry(event): 13 | data = { 14 | 'id': bson.ObjectId(), 15 | 'event': event, 16 | 'timestamp': int(utils.time_now()), 17 | } 18 | 19 | data.update(settings.local.host.journal_data) 20 | 21 | return data 22 | 23 | def entry(event, *args, **kwargs): 24 | if settings.app.auditing != ALL: 25 | return 26 | 27 | event = get_base_entry(event) 28 | for arg in args: 29 | event.update(arg) 30 | event.update(kwargs) 31 | journal_queue.append(event) 32 | -------------------------------------------------------------------------------- /pritunl/link/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.link.link import * 2 | from pritunl.link.utils import * 3 | -------------------------------------------------------------------------------- /pritunl/listener.py: -------------------------------------------------------------------------------- 1 | import collections 2 | 3 | channels = collections.defaultdict(set) 4 | 5 | def add_listener(channel, callback): 6 | channels[channel].add(callback) 7 | -------------------------------------------------------------------------------- /pritunl/logger/filter.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | class LogFilter(logging.Filter): 4 | def filter(self, record): 5 | return 1 6 | -------------------------------------------------------------------------------- /pritunl/mongo/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.mongo.dict import MongoDict 2 | from pritunl.mongo.list import MongoList 3 | from pritunl.mongo.object import MongoObject 4 | 5 | database = None 6 | secondary_database = None 7 | prefix = '' 8 | collection_types = {} 9 | 10 | def get_collection(name): 11 | coll_type = collection_types.get(name) 12 | if coll_type == 1: 13 | coll = getattr(database, prefix + name) 14 | elif coll_type == 2: 15 | coll = getattr(secondary_database, prefix + name) 16 | else: 17 | raise TypeError('Invalid collection name') 18 | 19 | coll.name_str = name 20 | return coll 21 | -------------------------------------------------------------------------------- /pritunl/monitoring/utils.py: -------------------------------------------------------------------------------- 1 | import urllib.parse 2 | 3 | def get_servers(uri): 4 | uri = urllib.parse.urlparse(uri) 5 | 6 | netloc = uri.netloc.split('@', 1) 7 | if len(netloc) == 2: 8 | username, password = netloc[0].split(':', 1) 9 | netloc = netloc[1] 10 | else: 11 | username = None 12 | password = None 13 | netloc = netloc[0] 14 | 15 | hosts = [] 16 | netloc = netloc.split(',') 17 | for host in netloc: 18 | host, port = host.split(':', 1) 19 | try: 20 | port = int(port) 21 | except: 22 | port = 0 23 | 24 | hosts.append((host, port)) 25 | 26 | if uri.path: 27 | database = uri.path.replace('/', '', 1) 28 | else: 29 | database = None 30 | 31 | return hosts, username, password, database 32 | -------------------------------------------------------------------------------- /pritunl/objcache.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | class ObjCache(object): 4 | def __init__(self, ttl=60): 5 | self._ttl = ttl 6 | self._data = {} 7 | self._timers = {} 8 | 9 | def remove(self, key): 10 | self._data.pop(key, None) 11 | 12 | def set(self, key, val): 13 | cur_timer = self._timers.pop(key, None) 14 | if cur_timer: 15 | cur_timer.cancel() 16 | 17 | timer = threading.Timer(self._ttl, self.remove, (key,)) 18 | timer.daemon = True 19 | self._timers[key] = timer 20 | timer.start() 21 | 22 | self._data[key] = val 23 | 24 | def get(self, key): 25 | return self._data.get(key) 26 | -------------------------------------------------------------------------------- /pritunl/organization/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.organization.organization import Organization 2 | from pritunl.organization.utils import * 3 | -------------------------------------------------------------------------------- /pritunl/patches.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import os 3 | 4 | os.environ['BOTO_CONFIG'] = '' 5 | 6 | try: 7 | requests.packages.urllib3.disable_warnings() 8 | except: 9 | pass 10 | -------------------------------------------------------------------------------- /pritunl/plugins/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.plugins.plugins import * 2 | -------------------------------------------------------------------------------- /pritunl/plugins/utils.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | 3 | def get_functions(module): 4 | funcs = {} 5 | for x in inspect.getmembers(module): 6 | if inspect.isfunction(x[1]): 7 | funcs[x[0]] = x[1] 8 | return funcs 9 | -------------------------------------------------------------------------------- /pritunl/pooler.py: -------------------------------------------------------------------------------- 1 | pooler_types = {} 2 | 3 | def add_pooler(fill_type): 4 | def add_pooler_wrap(func): 5 | pooler_types[fill_type] = func 6 | return func 7 | return add_pooler_wrap 8 | 9 | def fill(fill_type, *args, **kwargs): 10 | pooler_types[fill_type](*args, **kwargs) 11 | -------------------------------------------------------------------------------- /pritunl/poolers/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.poolers import dh_params 2 | from pritunl.poolers import org 3 | from pritunl.poolers import user 4 | -------------------------------------------------------------------------------- /pritunl/poolers/org.py: -------------------------------------------------------------------------------- 1 | from pritunl.constants import * 2 | from pritunl import settings 3 | from pritunl import pooler 4 | from pritunl import mongo 5 | from pritunl import organization 6 | 7 | @pooler.add_pooler('org') 8 | def fill_org(): 9 | collection = mongo.get_collection('organizations') 10 | queue_collection = mongo.get_collection('queue') 11 | 12 | org_pool_count = collection.count_documents({ 13 | 'type': ORG_POOL, 14 | }) 15 | 16 | org_pool_count += queue_collection.count_documents({ 17 | 'type': 'init_org_pooled', 18 | }) 19 | 20 | for _ in range(settings.app.org_pool_size - org_pool_count): 21 | org = organization.new_org(type=ORG_POOL, block=False) 22 | -------------------------------------------------------------------------------- /pritunl/queue/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.queue.com import QueueCom 2 | from pritunl.queue.queue import Queue 3 | from pritunl.queue.utils import * 4 | -------------------------------------------------------------------------------- /pritunl/queues/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.queues.assign_ip_addr import QueueAssignIpAddr 2 | from pritunl.queues.assign_ip_pool import QueueAssignIpPool 3 | from pritunl.queues.dh_params import QueueDhParams 4 | from pritunl.queues.init_org_pooled import QueueInitOrgPooled 5 | from pritunl.queues.init_user import QueueInitUser 6 | from pritunl.queues.init_user_pooled import QueueInitUserPooled 7 | from pritunl.queues.unassign_ip_addr import QueueUnassignIpAddr 8 | -------------------------------------------------------------------------------- /pritunl/runners/firewall.py: -------------------------------------------------------------------------------- 1 | from pritunl.constants import * 2 | from pritunl.helpers import * 3 | from pritunl import logger 4 | from pritunl import settings 5 | from pritunl import firewall 6 | 7 | import threading 8 | import time 9 | 10 | @interrupter 11 | def _keep_alive_thread(): 12 | while True: 13 | try: 14 | time.sleep(1) 15 | firewall.update() 16 | except: 17 | logger.exception('Error in firewall update', 'runners', 18 | host_id=settings.local.host_id, 19 | host_name=settings.local.host.name, 20 | ) 21 | time.sleep(0.5) 22 | 23 | def start_firewall(): 24 | threading.Thread(name="FirewallKeepAlive", 25 | target=_keep_alive_thread).start() 26 | -------------------------------------------------------------------------------- /pritunl/runners/instance.py: -------------------------------------------------------------------------------- 1 | from pritunl import server 2 | from pritunl import listener 3 | 4 | def start_instance(): 5 | listener.add_listener('instance', server.on_msg) 6 | -------------------------------------------------------------------------------- /pritunl/runners/limiter.py: -------------------------------------------------------------------------------- 1 | from pritunl.helpers import * 2 | from pritunl import logger 3 | from pritunl import settings 4 | from pritunl import limiter 5 | 6 | import time 7 | import threading 8 | 9 | @interrupter 10 | def _limiter_runner_thread(): 11 | while True: 12 | try: 13 | for limtr in limiter.limiters: 14 | cur_time = time.time() 15 | for peer, (expire, count) in list(limtr.peers_expire_count.items()): 16 | if cur_time > expire: 17 | limtr.peers_expire_count.pop(peer, None) 18 | 19 | yield interrupter_sleep(settings.app.peer_limit_timeout * 2) 20 | 21 | except GeneratorExit: 22 | raise 23 | except: 24 | logger.exception('Error in limiter runner thread', 'runners') 25 | time.sleep(0.5) 26 | 27 | def start_limiter(): 28 | threading.Thread(name="LimiterRunner", 29 | target=_limiter_runner_thread).start() 30 | -------------------------------------------------------------------------------- /pritunl/runners/server.py: -------------------------------------------------------------------------------- 1 | from pritunl import settings 2 | from pritunl import logger 3 | from pritunl import server 4 | from pritunl import listener 5 | 6 | import time 7 | 8 | def _on_msg(msg): 9 | if msg['message'] != 'start': 10 | return 11 | 12 | try: 13 | svr = server.get_by_id(msg['server_id']) 14 | if settings.local.host_id not in svr.hosts: 15 | return 16 | 17 | for instance in svr.instances: 18 | if instance['host_id'] == settings.local.host_id: 19 | return 20 | 21 | prefered_hosts = msg.get('prefered_hosts') 22 | 23 | if prefered_hosts and settings.local.host_id not in prefered_hosts: 24 | time.sleep(0.1) 25 | 26 | svr.run(send_events=msg.get('send_events')) 27 | except: 28 | logger.exception('Failed to run server', 'runners') 29 | 30 | def start_server(): 31 | listener.add_listener('servers', _on_msg) 32 | -------------------------------------------------------------------------------- /pritunl/runners/settings.py: -------------------------------------------------------------------------------- 1 | from pritunl.helpers import * 2 | from pritunl import settings 3 | from pritunl import listener 4 | from pritunl import logger 5 | 6 | import threading 7 | 8 | @interrupter 9 | def _check(): 10 | yield 11 | 12 | try: 13 | settings.reload_mongo() 14 | except: 15 | logger.exception('Settings check failed', 'runners') 16 | 17 | _start_check_timer() 18 | 19 | def _start_check_timer(): 20 | thread = threading.Timer(settings.app.settings_check_interval, _check) 21 | thread.daemon = True 22 | thread.start() 23 | 24 | def start_settings(): 25 | listener.add_listener('setting', settings.on_msg) 26 | _start_check_timer() 27 | -------------------------------------------------------------------------------- /pritunl/runners/subscription.py: -------------------------------------------------------------------------------- 1 | from pritunl.constants import * 2 | from pritunl.helpers import * 3 | from pritunl import settings 4 | from pritunl import subscription 5 | from pritunl import logger 6 | 7 | import threading 8 | 9 | @interrupter 10 | def _subscription_thread(): 11 | while True: 12 | try: 13 | yield interrupter_sleep(SUBSCRIPTION_UPDATE_RATE) 14 | subscription.update() 15 | except GeneratorExit: 16 | raise 17 | except: 18 | logger.exception('Error in subscription thread', 'runners') 19 | 20 | def start_subscription(): 21 | settings.local.sub_active = None 22 | subscription.update() 23 | threading.Thread(name="SubRunner", target=_subscription_thread).start() 24 | -------------------------------------------------------------------------------- /pritunl/runners/time_sync.py: -------------------------------------------------------------------------------- 1 | from pritunl.helpers import * 2 | from pritunl import utils 3 | from pritunl import logger 4 | 5 | import threading 6 | 7 | @interrupter 8 | def _time_sync_thread(): 9 | while True: 10 | try: 11 | utils.sync_time() 12 | except: 13 | logger.exception('Failed to sync time', 'runners') 14 | yield interrupter_sleep(300) 15 | continue 16 | yield interrupter_sleep(1800) 17 | 18 | def start_time_sync(): 19 | threading.Thread(name="TimeSync", target=_time_sync_thread).start() 20 | -------------------------------------------------------------------------------- /pritunl/runners/tokens.py: -------------------------------------------------------------------------------- 1 | from pritunl.helpers import * 2 | from pritunl import logger 3 | from pritunl import sso 4 | 5 | import threading 6 | import time 7 | 8 | @interrupter 9 | def tokens_thread(): 10 | while True: 11 | try: 12 | time.sleep(3) 13 | sso.sync_tokens() 14 | except GeneratorExit: 15 | raise 16 | except: 17 | logger.exception('Error in token sync thread', 'runners') 18 | time.sleep(1) 19 | 20 | yield 21 | 22 | def start_tokens(): 23 | threading.Thread(name="TokensRunner", target=tokens_thread).start() 24 | -------------------------------------------------------------------------------- /pritunl/runners/update_server.py: -------------------------------------------------------------------------------- 1 | from pritunl.helpers import * 2 | from pritunl import app 3 | 4 | import threading 5 | 6 | @interrupter 7 | def _update_server_thread(): 8 | while True: 9 | app.update_server() 10 | yield interrupter_sleep(3) 11 | 12 | def start_update_server(): 13 | threading.Thread(name="UpdateServer", target=_update_server_thread).start() 14 | -------------------------------------------------------------------------------- /pritunl/server/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.server.server import Server, dict_fields, operation_fields 2 | from pritunl.server.instance import get_instance 3 | from pritunl.server.bandwidth import ServerBandwidth 4 | from pritunl.server.listener import on_msg 5 | from pritunl.server.ip_pool import * 6 | from pritunl.server.utils import * 7 | -------------------------------------------------------------------------------- /pritunl/server/listener.py: -------------------------------------------------------------------------------- 1 | _channels = {} 2 | 3 | def add_listener(instance_id, callback): 4 | _channels[instance_id] = callback 5 | 6 | def remove_listener(instance_id): 7 | _channels.pop(instance_id, None) 8 | 9 | def on_msg(msg): 10 | for callback in list(_channels.values()): 11 | callback(msg) 12 | -------------------------------------------------------------------------------- /pritunl/settings/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.settings.settings import Settings 2 | 3 | from pritunl.settings.app import SettingsApp 4 | from pritunl.settings.conf import SettingsConf 5 | from pritunl.settings.local import SettingsLocal 6 | from pritunl.settings.mongo import SettingsMongo 7 | from pritunl.settings.user import SettingsUser 8 | from pritunl.settings.vpn import SettingsVpn 9 | 10 | import sys 11 | 12 | app = SettingsApp 13 | conf = SettingsConf 14 | local = SettingsLocal 15 | mongo = SettingsMongo 16 | user = SettingsUser 17 | vpn = SettingsVpn 18 | 19 | def commit(): 20 | pass 21 | 22 | sys.modules[__name__] = Settings() 23 | -------------------------------------------------------------------------------- /pritunl/settings/group_base.py: -------------------------------------------------------------------------------- 1 | class SettingsGroupBase(object): 2 | group = None 3 | fields = {} 4 | 5 | def __getattr__(self, name): 6 | if name in self.fields: 7 | return self.fields[name] 8 | raise AttributeError('%s instance has no attribute %r' % ( 9 | self.__class__.__name__, name)) 10 | -------------------------------------------------------------------------------- /pritunl/settings/group_file.py: -------------------------------------------------------------------------------- 1 | from pritunl.settings.group_base import SettingsGroupBase 2 | 3 | from pritunl.constants import * 4 | 5 | import json 6 | import os 7 | 8 | class SettingsGroupFile(SettingsGroupBase): 9 | type = GROUP_FILE 10 | path = None 11 | commit_fields = set() 12 | 13 | def load(self): 14 | if not os.path.isfile(self.path): 15 | return 16 | 17 | os.chmod(self.path, 0o600) 18 | with open(self.path, 'r') as settings_file: 19 | doc = json.loads(settings_file.read()) 20 | 21 | for field, value in list(doc.items()): 22 | setattr(self, field, value) 23 | 24 | def commit(self): 25 | doc = {} 26 | 27 | for field, default in self.fields.items(): 28 | if hasattr(self, field): 29 | value = getattr(self, field) 30 | if field in self.commit_fields or value != default: 31 | doc[field] = getattr(self, field) 32 | 33 | with open(self.path, 'w') as settings_file: 34 | os.chmod(self.path, 0o600) 35 | settings_file.write(json.dumps(doc, indent=4)) 36 | -------------------------------------------------------------------------------- /pritunl/settings/group_local.py: -------------------------------------------------------------------------------- 1 | from pritunl.settings.group_base import SettingsGroupBase 2 | 3 | from pritunl.constants import * 4 | 5 | class SettingsGroupLocal(SettingsGroupBase): 6 | type = GROUP_LOCAL 7 | -------------------------------------------------------------------------------- /pritunl/settings/local.py: -------------------------------------------------------------------------------- 1 | from pritunl.settings.group_local import SettingsGroupLocal 2 | 3 | import threading 4 | 5 | server_start = threading.Event() 6 | server_start.set() 7 | 8 | class SettingsLocal(SettingsGroupLocal): 9 | group = 'local' 10 | fields = { 11 | 'se_host_key': None, 12 | 'se_authorize_key': None, 13 | 'se_encryption_key': None, 14 | 'se_client_key': None, 15 | 'se_client_pub_key': None, 16 | 'quiet': False, 17 | 'public_ip': None, 18 | 'public_ip6': None, 19 | 'server_ready': threading.Event(), 20 | 'server_start': server_start, 21 | 'host_ping_timestamp': None, 22 | 'ntp_time': None, 23 | 'sub_active': False, 24 | 'sub_status': None, 25 | 'sub_plan': None, 26 | 'sub_amount': None, 27 | 'sub_period_end': None, 28 | 'sub_trial_end': None, 29 | 'sub_cancel_at_period_end': None, 30 | 'sub_balance': None, 31 | 'sub_premium_buy_url': False, 32 | 'sub_enterprise_buy_url': False, 33 | 'sub_portal_url': False, 34 | 'sub_url_key': False, 35 | 'sub_styles': {}, 36 | } 37 | -------------------------------------------------------------------------------- /pritunl/settings/mongo.py: -------------------------------------------------------------------------------- 1 | from pritunl.settings.group_mongo import SettingsGroupMongo 2 | 3 | class SettingsMongo(SettingsGroupMongo): 4 | group = 'mongo' 5 | fields = { 6 | 'tran_max_attempts': 6, 7 | 'tran_ttl': 10, 8 | 'queue_max_attempts': 3, 9 | 'queue_ttl': 15, 10 | 'task_max_attempts': 3, 11 | 'task_ttl': 30, 12 | } 13 | -------------------------------------------------------------------------------- /pritunl/settings/user.py: -------------------------------------------------------------------------------- 1 | from pritunl.constants import * 2 | from pritunl.settings.group_mongo import SettingsGroupMongo 3 | 4 | class SettingsUser(SettingsGroupMongo): 5 | group = 'user' 6 | fields = { 7 | 'audit_limit': 2500, 8 | 'gravatar': True, 9 | 'otp_secret_len': 16, 10 | 'pin_mode': PIN_OPTIONAL, 11 | 'pin_min_length': 6, 12 | 'pin_digits_only': True, 13 | 'device_key_override': None, 14 | 'device_key_length': 4, 15 | 'device_reg_attempts': 10, 16 | 'reconnect': True, 17 | 'password_encryption': True, 18 | 'cert_key_bits': 4096, 19 | 'cert_message_digest': 'sha256', 20 | 'page_count': 10, 21 | 'skip_remote_sso_check': False, 22 | 'conf_sync': True, 23 | 'restrict_import': False, 24 | 'restrict_client': False, 25 | } 26 | -------------------------------------------------------------------------------- /pritunl/setup/boto_conf.py: -------------------------------------------------------------------------------- 1 | from pritunl import settings 2 | 3 | import boto3 4 | 5 | def setup_boto_conf(): 6 | pass 7 | # TODO 8 | # boto.config.add_section('Boto') 9 | # boto.config.set('Boto', 'num_retries', '2') 10 | # boto.config.set('Boto', 'http_socket_timeout', 11 | # str(int(settings.app.aws_timeout))) 12 | -------------------------------------------------------------------------------- /pritunl/setup/cache.py: -------------------------------------------------------------------------------- 1 | from pritunl import cache 2 | 3 | def setup_cache(): 4 | cache.init() 5 | -------------------------------------------------------------------------------- /pritunl/setup/check.py: -------------------------------------------------------------------------------- 1 | from pritunl import logger 2 | 3 | import pymongo 4 | import bson 5 | 6 | def setup_check(): 7 | if not pymongo.has_c(): 8 | logger.warning('Failed to load pymongo c bindings') 9 | 10 | if not bson.has_c(): 11 | logger.warning('Failed to load bson c bindings') 12 | -------------------------------------------------------------------------------- /pritunl/setup/handlers.py: -------------------------------------------------------------------------------- 1 | def setup_handlers(): 2 | from pritunl import handlers 3 | -------------------------------------------------------------------------------- /pritunl/setup/host.py: -------------------------------------------------------------------------------- 1 | from pritunl import mongo 2 | from pritunl import listener 3 | from pritunl import settings 4 | 5 | def _on_msg(msg): 6 | if msg['message'] != 'updated': 7 | return 8 | settings.local.host.load() 9 | 10 | def setup_host(): 11 | from pritunl import host 12 | collection = mongo.get_collection('settings') 13 | 14 | collection.update_one({ 15 | '_id': 'subscription', 16 | }, {'$setOnInsert': { 17 | 'active': None, 18 | 'plan': None, 19 | }}, upsert=True) 20 | 21 | host.init() 22 | 23 | listener.add_listener('hosts', _on_msg) 24 | -------------------------------------------------------------------------------- /pritunl/setup/host_fix.py: -------------------------------------------------------------------------------- 1 | from pritunl import settings 2 | from pritunl import subscription 3 | 4 | def setup_host_fix(): 5 | subscription.update() 6 | 7 | if settings.app.license and settings.app.license_plan != 'premium': 8 | return 9 | 10 | from pritunl import server 11 | host_id = settings.local.host_id 12 | 13 | for svr in server.iter_servers(fields=['hosts']): 14 | if svr.hosts != [host_id]: 15 | svr.hosts = [host_id] 16 | svr.commit('hosts') 17 | -------------------------------------------------------------------------------- /pritunl/setup/logger.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | def setup_logger(): 4 | from pritunl.app import app 5 | from pritunl import logger 6 | 7 | logger.log_handler = logger.LogHandler() 8 | 9 | logger.log_filter = logger.LogFilter() 10 | logger.logger.addFilter(logger.log_filter) 11 | 12 | logger.logger.setLevel(logging.DEBUG) 13 | logger.log_handler.setLevel(logging.DEBUG) 14 | 15 | logger.log_handler.setFormatter(logger.LogFormatter( 16 | '[%(asctime)s][%(levelname)s] %(message)s')) 17 | 18 | logger.logger.addHandler(logger.log_handler) 19 | 20 | app.logger.setLevel(logging.DEBUG) 21 | app.logger.addFilter(logger.log_filter) 22 | app.logger.addHandler(logger.log_handler) 23 | -------------------------------------------------------------------------------- /pritunl/setup/monitoring.py: -------------------------------------------------------------------------------- 1 | from pritunl.helpers import * 2 | from pritunl import settings 3 | from pritunl import logger 4 | from pritunl import monitoring 5 | 6 | import threading 7 | 8 | @interrupter 9 | def _monitoring_thread(): 10 | while True: 11 | yield interrupter_sleep(settings.app.influxdb_interval) 12 | try: 13 | monitoring.connect() 14 | except: 15 | logger.exception('InfluxDB connection error', 16 | 'monitoring', 17 | influxdb_uri=settings.app.influxdb_uri, 18 | ) 19 | yield interrupter_sleep(5) 20 | continue 21 | 22 | try: 23 | monitoring.write_queue() 24 | except: 25 | logger.exception('InfluxDB write queue error', 26 | 'monitoring', 27 | influxdb_uri=settings.app.influxdb_uri, 28 | ) 29 | yield interrupter_sleep(5) 30 | 31 | def setup_monitoring(): 32 | monitoring.init() 33 | thread = threading.Thread(name="SetupMonitoring", 34 | target=_monitoring_thread) 35 | thread.daemon = True 36 | thread.start() 37 | -------------------------------------------------------------------------------- /pritunl/setup/plugins.py: -------------------------------------------------------------------------------- 1 | from pritunl import plugins 2 | 3 | def setup_plugins(): 4 | plugins.init() 5 | -------------------------------------------------------------------------------- /pritunl/setup/poolers.py: -------------------------------------------------------------------------------- 1 | def setup_poolers(): 2 | from pritunl import poolers 3 | -------------------------------------------------------------------------------- /pritunl/setup/public_ip.py: -------------------------------------------------------------------------------- 1 | from pritunl import settings 2 | from pritunl import utils 3 | 4 | import threading 5 | 6 | def setup_public_ip(): 7 | utils.sync_public_ip() 8 | if not settings.local.public_ip: 9 | thread = threading.Thread(name="SetupPublicIp", 10 | target=utils.sync_public_ip, 11 | kwargs={'attempts': 5}) 12 | thread.daemon = True 13 | thread.start() 14 | -------------------------------------------------------------------------------- /pritunl/setup/runners.py: -------------------------------------------------------------------------------- 1 | def setup_runners(): 2 | from pritunl import runners 3 | runners.start_all() 4 | -------------------------------------------------------------------------------- /pritunl/setup/server_fix.py: -------------------------------------------------------------------------------- 1 | from pritunl import mongo 2 | 3 | def setup_server_fix(): 4 | servers_collection = mongo.get_collection('servers') 5 | 6 | servers_collection.update_one({}, {'$set': { 7 | 'pool_cursor': None, 8 | }}) 9 | -------------------------------------------------------------------------------- /pritunl/setup/server_listeners.py: -------------------------------------------------------------------------------- 1 | from pritunl import listener 2 | from pritunl import callbacks 3 | 4 | def setup_server_listeners(): 5 | from pritunl import vxlan 6 | listener.add_listener('port_forwarding', callbacks.on_port_forwarding) 7 | listener.add_listener('client', callbacks.on_client) 8 | listener.add_listener('client_links', callbacks.on_client_link) 9 | listener.add_listener('vxlan', vxlan.on_vxlan) 10 | -------------------------------------------------------------------------------- /pritunl/setup/settings.py: -------------------------------------------------------------------------------- 1 | from pritunl.helpers import * 2 | from pritunl import settings 3 | from pritunl import utils 4 | 5 | def setup_settings(): 6 | if not settings.app.oracle_private_key or \ 7 | not settings.app.oracle_public_key: 8 | private_key, public_key = utils.generate_rsa_key() 9 | settings.app.oracle_private_key = private_key 10 | settings.app.oracle_public_key = public_key 11 | settings.commit() 12 | -------------------------------------------------------------------------------- /pritunl/setup/signal_handler.py: -------------------------------------------------------------------------------- 1 | from pritunl.helpers import * 2 | 3 | import signal 4 | 5 | def handle_exit(signum, frame): 6 | set_global_interrupt() 7 | 8 | def setup_signal_handler(): 9 | signal.signal(signal.SIGINT, handle_exit) 10 | signal.signal(signal.SIGTERM, handle_exit) 11 | -------------------------------------------------------------------------------- /pritunl/setup/subscription.py: -------------------------------------------------------------------------------- 1 | from pritunl import listener 2 | from pritunl import subscription 3 | 4 | def _on_msg(msg): 5 | if msg['message'] != 'updated': 6 | return 7 | subscription.update() 8 | 9 | def setup_subscription(): 10 | listener.add_listener('subscription', _on_msg) 11 | -------------------------------------------------------------------------------- /pritunl/setup/temp_path.py: -------------------------------------------------------------------------------- 1 | from pritunl import settings 2 | 3 | import os 4 | import uuid 5 | 6 | def setup_temp_path(): 7 | settings.conf.temp_path = settings.conf.temp_path.replace( 8 | '%r', uuid.uuid4().hex) 9 | if not os.path.isdir(settings.conf.temp_path): 10 | os.makedirs(settings.conf.temp_path) 11 | -------------------------------------------------------------------------------- /pritunl/setup/token.py: -------------------------------------------------------------------------------- 1 | from pritunl import sso 2 | 3 | def setup_token(): 4 | sso.init_token() 5 | -------------------------------------------------------------------------------- /pritunl/sso/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.sso.duo import Duo 2 | from pritunl.sso.yubico import auth_yubico 3 | from pritunl.sso.azure import verify_azure 4 | from pritunl.sso.authzero import verify_authzero 5 | from pritunl.sso.google import verify_google 6 | from pritunl.sso.jumpcloud import auth_jumpcloud 7 | from pritunl.sso.radius import verify_radius 8 | from pritunl.sso.okta import auth_okta, auth_okta_secondary 9 | from pritunl.sso.onelogin import auth_onelogin, auth_onelogin_secondary 10 | from pritunl.sso.token import * 11 | from pritunl.sso.utils import * 12 | -------------------------------------------------------------------------------- /pritunl/static/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.static.static import * 2 | from pritunl.static.utils import * 3 | -------------------------------------------------------------------------------- /pritunl/static/utils.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import zlib 3 | import time 4 | 5 | def generate_etag(file_name, file_size, mtime): 6 | file_name = file_name.encode(sys.getfilesystemencoding()) 7 | return 'wzsdm-%d-%s-%s' % ( 8 | time.mktime(mtime.timetuple()), 9 | file_size, 10 | zlib.adler32(file_name) & 0xffffffff, 11 | ) 12 | -------------------------------------------------------------------------------- /pritunl/system/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.system.sysctl import * 2 | -------------------------------------------------------------------------------- /pritunl/system/sysctl.py: -------------------------------------------------------------------------------- 1 | from pritunl.constants import * 2 | from pritunl.exceptions import * 3 | from pritunl import utils 4 | from pritunl import logger 5 | 6 | import subprocess 7 | 8 | def sysctl_upsert(key, value, required=True): 9 | try: 10 | output = utils.check_output_logged(['sysctl', key]) 11 | except subprocess.CalledProcessError: 12 | logger.exception('Failed to read sysctl value', 13 | 'server', key=key, value=value, 14 | ) 15 | output = '' 16 | 17 | for line in output.split('\n'): 18 | if ('%s =' % key) in line: 19 | if line.split('=')[-1].strip() == value: 20 | return 21 | 22 | try: 23 | utils.check_output_logged( 24 | ['sysctl', '-w', '%s=%s' % (key, value)]) 25 | except subprocess.CalledProcessError: 26 | logger.exception('Failed to update sysctl value', 'server', 27 | key=key, value=value, 28 | ) 29 | if required: 30 | raise 31 | -------------------------------------------------------------------------------- /pritunl/tasks/__init__.py: -------------------------------------------------------------------------------- 1 | import pritunl.tasks.acme_update 2 | import pritunl.tasks.clean_ip_pool 3 | import pritunl.tasks.clean_client_pool 4 | import pritunl.tasks.clean_users 5 | import pritunl.tasks.clean_network_links 6 | import pritunl.tasks.clean_network_lock 7 | import pritunl.tasks.pooler 8 | import pritunl.tasks.route 9 | import pritunl.tasks.sync_ip_pool 10 | import pritunl.tasks.server 11 | import pritunl.tasks.host 12 | import pritunl.tasks.link 13 | import pritunl.tasks.clean_servers 14 | import pritunl.tasks.clean_vxlans 15 | -------------------------------------------------------------------------------- /pritunl/tasks/acme_update.py: -------------------------------------------------------------------------------- 1 | from pritunl import task 2 | from pritunl import logger 3 | from pritunl import acme 4 | from pritunl import app 5 | from pritunl import utils 6 | from pritunl import settings 7 | 8 | class AcmeUpdate(task.Task): 9 | type = 'acme_update' 10 | 11 | def task(self): 12 | acme_domain = settings.app.acme_domain 13 | 14 | if not acme_domain: 15 | return 16 | 17 | if settings.app.acme_timestamp and \ 18 | settings.app.acme_key and \ 19 | utils.time_now() - settings.app.acme_timestamp < \ 20 | settings.app.acme_renew: 21 | return 22 | 23 | logger.info( 24 | 'Updating acme certificate', 'tasks', 25 | acme_domain=acme_domain, 26 | ) 27 | 28 | acme.update_acme_cert() 29 | app.update_server() 30 | 31 | task.add_task(AcmeUpdate, hours=4, minutes=35, run_on_start=True) 32 | -------------------------------------------------------------------------------- /pritunl/tasks/clean_network_links.py: -------------------------------------------------------------------------------- 1 | from pritunl.helpers import * 2 | from pritunl import mongo 3 | from pritunl import task 4 | 5 | class TaskCleanNetworkLinks(task.Task): 6 | type = 'clean_network_links' 7 | 8 | @cached_static_property 9 | def user_collection(cls): 10 | return mongo.get_collection('users') 11 | 12 | @cached_static_property 13 | def user_net_link_collection(cls): 14 | return mongo.get_collection('users_net_link') 15 | 16 | def task(self): 17 | user_ids_link = set(self.user_net_link_collection.find({}, { 18 | '_id': True, 19 | 'user_id': True, 20 | }).distinct('user_id')) 21 | 22 | user_ids = set(self.user_collection.find({}, { 23 | '_id': True, 24 | }).distinct('_id')) 25 | 26 | self.user_net_link_collection.delete_many({ 27 | 'user_id': {'$in': list(user_ids_link - user_ids)}, 28 | }) 29 | 30 | task.add_task(TaskCleanNetworkLinks, hours=5, minutes=47) 31 | -------------------------------------------------------------------------------- /pritunl/tasks/clean_network_lock.py: -------------------------------------------------------------------------------- 1 | from pritunl.helpers import * 2 | from pritunl import mongo 3 | from pritunl import task 4 | from pritunl import utils 5 | 6 | class TaskCleanNetworkLock(task.Task): 7 | type = 'clean_network_lock' 8 | 9 | @cached_static_property 10 | def server_collection(cls): 11 | return mongo.get_collection('servers') 12 | 13 | def task(self): 14 | self.server_collection.update_many({ 15 | 'network_lock_ttl': {'$lt': utils.now()}, 16 | }, {'$unset': { 17 | 'network_lock': '', 18 | 'network_lock_ttl': '', 19 | }}) 20 | 21 | task.add_task(TaskCleanNetworkLock, 22 | minutes=range(0, 60, 8), run_on_start=True) 23 | -------------------------------------------------------------------------------- /pritunl/tasks/clean_vxlans.py: -------------------------------------------------------------------------------- 1 | from pritunl.helpers import * 2 | from pritunl import mongo 3 | from pritunl import task 4 | 5 | class TaskCleanVxlans(task.Task): 6 | type = 'clean_vxlan' 7 | 8 | @cached_static_property 9 | def server_collection(cls): 10 | return mongo.get_collection('servers') 11 | 12 | @cached_static_property 13 | def vxlan_collection(cls): 14 | return mongo.get_collection('vxlans') 15 | 16 | def task(self): 17 | server_ids = set(self.server_collection.find().distinct('_id')) 18 | vxlan_ids = set(self.vxlan_collection.find().distinct('server_id')) 19 | 20 | self.vxlan_collection.delete_many({ 21 | 'server_id': {'$in': list(vxlan_ids - server_ids)} 22 | }) 23 | 24 | task.add_task(TaskCleanVxlans, minutes=52) 25 | -------------------------------------------------------------------------------- /pritunl/tasks/link.py: -------------------------------------------------------------------------------- 1 | from pritunl import settings 2 | from pritunl import task 3 | from pritunl import link 4 | 5 | import collections 6 | 7 | class TaskLink(task.Task): 8 | type = 'link' 9 | delay = 10 10 | 11 | def task(self): 12 | if settings.app.demo_mode: 13 | return 14 | 15 | hosts = [] 16 | location_available_hosts = collections.defaultdict(list) 17 | for hst in link.iter_hosts(): 18 | hosts.append(hst) 19 | 20 | if not hst.is_available: 21 | continue 22 | 23 | location_available_hosts[hst.location_id].append(hst) 24 | 25 | for hst in hosts: 26 | hst.update_available(location_available_hosts[hst.location_id]) 27 | 28 | task.add_task(TaskLink, seconds=range(0, 60, 3)) 29 | -------------------------------------------------------------------------------- /pritunl/tasks/pooler.py: -------------------------------------------------------------------------------- 1 | from pritunl import pooler 2 | from pritunl import task 3 | 4 | class TaskPooler(task.Task): 5 | type = 'pooler' 6 | 7 | def task(self): 8 | pooler.fill('org') 9 | pooler.fill('user') 10 | pooler.fill('dh_params') 11 | 12 | task.add_task(TaskPooler, minutes=range(0, 60, 5)) 13 | -------------------------------------------------------------------------------- /pritunl/tasks/sync_ip_pool.py: -------------------------------------------------------------------------------- 1 | from pritunl import task 2 | from pritunl import logger 3 | from pritunl import server 4 | 5 | class TaskSyncIpPool(task.Task): 6 | type = 'sync_ip_pool' 7 | 8 | def task(self): 9 | for svr in server.iter_servers(): 10 | try: 11 | svr.ip_pool.sync_ip_pool() 12 | except: 13 | logger.exception('Failed to sync server IP pool', 'tasks', 14 | server_id=svr.id, 15 | task_id=self.id, 16 | ) 17 | 18 | task.add_task(TaskSyncIpPool, hours=4, minutes=7) 19 | -------------------------------------------------------------------------------- /pritunl/transaction/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.transaction.transaction import Transaction 2 | from pritunl.transaction.collection import TransactionCollection 3 | -------------------------------------------------------------------------------- /pritunl/transaction/action.py: -------------------------------------------------------------------------------- 1 | from pritunl.constants import * 2 | 3 | class TransactionAction: 4 | def __init__(self, actions, func): 5 | self._actions = actions 6 | self._func = func 7 | 8 | def __call__(self, *args, **kwargs): 9 | from pritunl.transaction.collection import TransactionCollection 10 | self._actions.append([ 11 | self._func, 12 | args or '', 13 | kwargs or '', 14 | ]) 15 | return TransactionCollection(self._actions) 16 | 17 | def __getattr__(self, name): 18 | if name in MONGO_ACTION_METHODS: 19 | return TransactionAction(self._actions, name) 20 | raise AttributeError( 21 | 'TransactionAction instance has no attribute %r' % name) 22 | -------------------------------------------------------------------------------- /pritunl/upgrade/upgrade_1_17.py: -------------------------------------------------------------------------------- 1 | from pritunl.upgrade.utils import get_collection 2 | 3 | def upgrade_1_17(): 4 | hosts_collection = get_collection('hosts') 5 | hosts_collection.update_many({}, {'$set': { 6 | 'local_address': None, 7 | }}) 8 | -------------------------------------------------------------------------------- /pritunl/upgrade/upgrade_1_18.py: -------------------------------------------------------------------------------- 1 | from pritunl.upgrade.utils import get_collection 2 | 3 | def upgrade_1_18(): 4 | servers_collection = get_collection('servers') 5 | settings_collection = get_collection('settings') 6 | 7 | nat = True 8 | doc = settings_collection.find_one({'_id': 'vpn'}) 9 | if doc: 10 | nat = doc.get('nat_routes', True) 11 | 12 | for doc in servers_collection.find({}): 13 | routes = [] 14 | 15 | if doc.get('mode') == 'all_traffic': 16 | routes.append({ 17 | 'network': '0.0.0.0/0', 18 | 'nat': nat, 19 | }) 20 | 21 | for local_network in doc.get('local_networks', []): 22 | routes.append({ 23 | 'network': local_network, 24 | 'nat': nat, 25 | }) 26 | 27 | servers_collection.update_one({ 28 | '_id': doc['_id'], 29 | }, {'$set': { 30 | 'routes': routes, 31 | }}) 32 | -------------------------------------------------------------------------------- /pritunl/upgrade/upgrade_1_4.py: -------------------------------------------------------------------------------- 1 | from pritunl.upgrade.utils import get_collection 2 | 3 | from pritunl import utils 4 | 5 | def upgrade_1_4(): 6 | ip_pool_collection = get_collection('servers_ip_pool') 7 | 8 | docs = ip_pool_collection.find({}, { 9 | '_id': True, 10 | 'network': True, 11 | }) 12 | 13 | for doc in docs: 14 | if not doc.get('network'): 15 | continue 16 | 17 | if isinstance(doc['network'], int): 18 | continue 19 | 20 | ip_pool_collection.update_one({ 21 | '_id': doc['_id'], 22 | }, {'$set': { 23 | 'network': utils.fnv32a(doc['network']) 24 | }}) 25 | -------------------------------------------------------------------------------- /pritunl/upgrade/upgrade_1_5.py: -------------------------------------------------------------------------------- 1 | from pritunl.upgrade.utils import get_collection 2 | 3 | def upgrade_1_5(): 4 | settings_collection = get_collection('settings') 5 | 6 | response = settings_collection.update_one({ 7 | '_id': 'app', 8 | 'sso': True, 9 | }, {'$set': { 10 | 'sso': 'google', 11 | }}) 12 | 13 | if not bool(response.modified_count): 14 | settings_collection.update_one({ 15 | '_id': 'app', 16 | }, {'$set': { 17 | 'sso': None, 18 | }}) 19 | -------------------------------------------------------------------------------- /pritunl/user/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.user.user import User 2 | from pritunl.user.utils import * 3 | -------------------------------------------------------------------------------- /pritunl/utils/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.utils.cert import * 2 | from pritunl.utils.filter import * 3 | from pritunl.utils.json_helpers import * 4 | from pritunl.utils.least_common_counter import * 5 | from pritunl.utils.mail import * 6 | from pritunl.utils.misc import * 7 | from pritunl.utils.proc import * 8 | from pritunl.utils.network import * 9 | from pritunl.utils.aws import * 10 | from pritunl.utils.oracle import * 11 | from pritunl.utils.sig import * 12 | from pritunl.utils.none_queue import NoneQueue 13 | from pritunl.utils.auth import * 14 | from pritunl.utils.md5_hash import unsafe_md5 15 | -------------------------------------------------------------------------------- /pritunl/utils/auth.py: -------------------------------------------------------------------------------- 1 | from pritunl import settings 2 | 3 | def get_onelogin_mode(): 4 | if settings.app.sso_onelogin_mode is not None: 5 | return settings.app.sso_onelogin_mode 6 | if settings.app.sso_onelogin_push: 7 | if settings.app.sso_onelogin_skip_unavailable: 8 | return 'push_none' 9 | return 'push' 10 | return '' 11 | 12 | def get_okta_mode(): 13 | if settings.app.sso_okta_mode is not None: 14 | return settings.app.sso_okta_mode 15 | if settings.app.sso_okta_push: 16 | if settings.app.sso_okta_skip_unavailable: 17 | return 'push_none' 18 | return 'push' 19 | return '' 20 | -------------------------------------------------------------------------------- /pritunl/utils/least_common_counter.py: -------------------------------------------------------------------------------- 1 | import collections 2 | import heapq 3 | import operator 4 | 5 | class LeastCommonCounter(collections.Counter): 6 | def least_common(self, n=None): 7 | if n is None: 8 | return sorted(iter(self.items()), key=operator.itemgetter(1)) 9 | return heapq.nsmallest(n, iter(self.items()), key=operator.itemgetter(1)) 10 | -------------------------------------------------------------------------------- /pritunl/utils/sig.py: -------------------------------------------------------------------------------- 1 | from pritunl.utils.filter import session_str 2 | from pritunl.utils.misc import const_compare 3 | from pritunl import settings 4 | 5 | import base64 6 | import hashlib 7 | import hmac 8 | import flask 9 | 10 | def get_sig(sig_str, secret): 11 | return base64.b64encode( 12 | hmac.new(secret.encode(), sig_str.encode(), hashlib.sha512).digest(), 13 | ).decode() 14 | 15 | def get_flask_sig(): 16 | sig_str = '&'.join(( 17 | session_str('session_id'), 18 | session_str('admin_id'), 19 | session_str('timestamp'), 20 | )) 21 | return get_sig( 22 | settings.app.cookie_secret2, 23 | sig_str, 24 | ) 25 | 26 | def set_flask_sig(): 27 | flask.session['signature'] = get_flask_sig() 28 | 29 | def check_flask_sig(): 30 | return const_compare(session_str('signature'), get_flask_sig()) 31 | -------------------------------------------------------------------------------- /pritunl/vault/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.vault.vault import * 2 | from pritunl.vault.batch import * 3 | from pritunl.vault.item import * 4 | from pritunl.vault.utils import * 5 | -------------------------------------------------------------------------------- /pritunl/vault/nonces.py: -------------------------------------------------------------------------------- 1 | _nonces = set() 2 | 3 | def nonces_add(nonce): 4 | _nonces.add(nonce) 5 | 6 | def nonces_contains(nonce): 7 | return nonce in _nonces 8 | -------------------------------------------------------------------------------- /pritunl/vxlan/__init__.py: -------------------------------------------------------------------------------- 1 | from pritunl.vxlan.vxlan import * 2 | -------------------------------------------------------------------------------- /selinux/pritunl_dns.fc: -------------------------------------------------------------------------------- 1 | /usr/bin/pritunl-dns -- gen_context(system_u:object_r:pritunl_dns_exec_t,s0) 2 | -------------------------------------------------------------------------------- /selinux/pritunl_web.fc: -------------------------------------------------------------------------------- 1 | /etc/systemd/system/pritunl-web.service -- gen_context(system_u:object_r:pritunl_web_unit_file_t,s0) 2 | /usr/lib/systemd/system/pritunl-web.service -- gen_context(system_u:object_r:pritunl_web_unit_file_t,s0) 3 | /usr/bin/pritunl-web -- gen_context(system_u:object_r:pritunl_web_exec_t,s0) 4 | -------------------------------------------------------------------------------- /selinux8/pritunl_dns.fc: -------------------------------------------------------------------------------- 1 | /usr/bin/pritunl-dns -- gen_context(system_u:object_r:pritunl_dns_exec_t,s0) 2 | -------------------------------------------------------------------------------- /selinux8/pritunl_web.fc: -------------------------------------------------------------------------------- 1 | /etc/systemd/system/pritunl-web.service -- gen_context(system_u:object_r:pritunl_web_unit_file_t,s0) 2 | /usr/lib/systemd/system/pritunl-web.service -- gen_context(system_u:object_r:pritunl_web_unit_file_t,s0) 3 | /usr/bin/pritunl-web -- gen_context(system_u:object_r:pritunl_web_exec_t,s0) 4 | -------------------------------------------------------------------------------- /selinux9/pritunl_dns.fc: -------------------------------------------------------------------------------- 1 | /usr/bin/pritunl-dns -- gen_context(system_u:object_r:pritunl_dns_exec_t,s0) 2 | -------------------------------------------------------------------------------- /selinux9/pritunl_web.fc: -------------------------------------------------------------------------------- 1 | /etc/systemd/system/pritunl-web.service -- gen_context(system_u:object_r:pritunl_web_unit_file_t,s0) 2 | /usr/lib/systemd/system/pritunl-web.service -- gen_context(system_u:object_r:pritunl_web_unit_file_t,s0) 3 | /usr/bin/pritunl-web -- gen_context(system_u:object_r:pritunl_web_exec_t,s0) 4 | -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- 1 | import pritunl.__main__ 2 | 3 | pritunl.__main__.main('/etc/pritunl.conf') 4 | -------------------------------------------------------------------------------- /tools/ami_init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo -e "[pritunl]\nname=Pritunl Repository\nbaseurl=http://repo.pritunl.com/stable/yum/centos/7/\ngpgcheck=1\nenabled=1" > /etc/yum.repos.d/pritunl.repo 3 | echo -e "description \"Pritunl Override\"\n\nstart on starting pritunl\nstop on runlevel [!2345]\n\npre-start script\n stop pritunl\n sleep 1\nend script" > /etc/init/pritunl-override.conf 4 | echo -e "\nyum -y clean all\nyum -y upgrade\nsleep 1\nstart pritunl" >> /etc/rc.local 5 | gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys 7568D9BB55FF9E5287D586017AE645C0CF8E292A 6 | gpg --armor --export 7568D9BB55FF9E5287D586017AE645C0CF8E292A > key.tmp 7 | rpm --import key.tmp 8 | rm -f key.tmp 9 | yum -y upgrade 10 | yum -y install pritunl 11 | -------------------------------------------------------------------------------- /tools/ami_mongo_init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo -e "[mongodb-org-3.4]\nname=MongoDB Repository\nbaseurl=https://repo.mongodb.org/yum/redhat/amazon/mongodb-org/3.4/x86_64/\ngpgcheck=1\nenabled=1\ngpgkey=https://www.mongodb.org/static/pgp/server-3.4.asc" > /etc/yum.repos.d/mongodb-org-3.4.repo 3 | echo -e "[pritunl]\nname=Pritunl Repository\nbaseurl=http://repo.pritunl.com/stable/yum/centos/7/\ngpgcheck=1\nenabled=1" > /etc/yum.repos.d/pritunl.repo 4 | echo -e "description \"Pritunl Override\"\n\nstart on starting pritunl\nstop on runlevel [!2345]\n\npre-start script\n stop pritunl\n sleep 1\nend script" > /etc/init/pritunl-override.conf 5 | echo -e "\nyum -y clean all\nyum -y upgrade\nsleep 1\nstart pritunl" >> /etc/rc.local 6 | gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys 7568D9BB55FF9E5287D586017AE645C0CF8E292A 7 | gpg --armor --export 7568D9BB55FF9E5287D586017AE645C0CF8E292A > key.tmp 8 | rpm --import key.tmp 9 | rm -f key.tmp 10 | yum -y upgrade 11 | yum -y install pritunl mongodb-org 12 | -------------------------------------------------------------------------------- /tools/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | python2 tools/builder.py set-version $1 4 | python2 tools/builder.py build 5 | python2 tools/builder.py upload 6 | -------------------------------------------------------------------------------- /tools/development_pritunl.conf: -------------------------------------------------------------------------------- 1 | { 2 | "static_cache": false, 3 | "bind_addr": "0.0.0.0", 4 | "log_path": "var/pritunl.log", 5 | "www_path": "www", 6 | "local_address_interface": "auto", 7 | "mongodb_uri": "mongodb://localhost:27017/pritunl" 8 | } 9 | -------------------------------------------------------------------------------- /tools/stress_testing/connect_all.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os/exec" 6 | "os" 7 | "os/signal" 8 | "syscall" 9 | "time" 10 | ) 11 | 12 | const count = 256 13 | 14 | func Exec(name string, args ...string) (cmd *exec.Cmd, err error) { 15 | cmd = exec.Command(name, args...) 16 | err = cmd.Start() 17 | 18 | return 19 | } 20 | 21 | func main() { 22 | cmds := []*exec.Cmd{} 23 | 24 | defer func() { 25 | for _, cmd := range cmds { 26 | cmd.Process.Signal(os.Interrupt) 27 | } 28 | for _, cmd := range cmds { 29 | cmd.Wait() 30 | } 31 | }() 32 | 33 | for i := 1; i <= count; i++ { 34 | cmd, err := Exec( 35 | "openvpn", fmt.Sprintf("user_%05d.ovpn", i), 36 | ) 37 | if err != nil { 38 | panic(err) 39 | } 40 | cmds = append(cmds, cmd) 41 | 42 | time.Sleep(100 * time.Millisecond) 43 | } 44 | 45 | fmt.Println("\n") 46 | 47 | signals := make(chan os.Signal, 1) 48 | signal.Notify(signals, os.Interrupt) 49 | signal.Notify(signals, syscall.SIGTERM) 50 | <-signals 51 | } 52 | -------------------------------------------------------------------------------- /tools/stress_testing/get_test_names.py: -------------------------------------------------------------------------------- 1 | COUNT = 60000 2 | 3 | for i in xrange(1, COUNT + 1): 4 | print 'user_%s' % str(i).zfill(5) 5 | -------------------------------------------------------------------------------- /tools/stress_testing/test_client/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM pritunl/archlinux 2 | MAINTAINER Pritunl <contact@pritunl.com> 3 | 4 | RUN pacman -S --noconfirm go git bzr openvpn net-tools wget 5 | 6 | ENV GOPATH /go 7 | ENV PATH $PATH:/go/bin 8 | RUN go get github.com/gin-gonic/gin 9 | 10 | ADD . /test_client 11 | WORKDIR /test_client 12 | 13 | ENTRYPOINT ["go", "run", "client.go"] 14 | -------------------------------------------------------------------------------- /tools/vagrant_provision.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ntpdate ntp.ubuntu.com 3 | apt-get update -qq 4 | apt-get install -qq -y net-tools openvpn python python-dev python-pip bridge-utils 5 | pip install flask pymongo 6 | -------------------------------------------------------------------------------- /www/collections/admin.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'models/admin' 6 | ], function($, _, Backbone, AdminModel) { 7 | 'use strict'; 8 | var AdminCollection = Backbone.Collection.extend({ 9 | model: AdminModel, 10 | url: function() { 11 | return '/admin'; 12 | } 13 | }); 14 | 15 | return AdminCollection; 16 | }); 17 | -------------------------------------------------------------------------------- /www/collections/adminAudit.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'models/userAudit' 6 | ], function($, _, Backbone, UserAuditModel) { 7 | 'use strict'; 8 | var AdminAuditCollection = Backbone.Collection.extend({ 9 | model: UserAuditModel, 10 | initialize: function(options) { 11 | this.user = options.user; 12 | }, 13 | url: function() { 14 | return '/admin/' + this.user.get('id') + '/audit'; 15 | } 16 | }); 17 | 18 | return AdminAuditCollection; 19 | }); 20 | -------------------------------------------------------------------------------- /www/collections/device.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'models/device' 6 | ], function($, _, Backbone, DeviceModel) { 7 | 'use strict'; 8 | var DeviceCollection = Backbone.Collection.extend({ 9 | model: DeviceModel, 10 | initialize: function() { 11 | }, 12 | url: function() { 13 | return '/device/unregistered'; 14 | }, 15 | parse: function(response) { 16 | return response; 17 | } 18 | }); 19 | 20 | return DeviceCollection; 21 | }); 22 | -------------------------------------------------------------------------------- /www/collections/linkLocation.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'models/linkLocation' 6 | ], function($, _, Backbone, LinkLocationModel) { 7 | 'use strict'; 8 | var LinkLocationCollection = Backbone.Collection.extend({ 9 | model: LinkLocationModel, 10 | initialize: function(options) { 11 | this.link = options.link; 12 | }, 13 | url: function() { 14 | return '/link/' + this.link + '/location'; 15 | } 16 | }); 17 | 18 | return LinkLocationCollection; 19 | }); 20 | -------------------------------------------------------------------------------- /www/collections/log.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'models/log' 6 | ], function($, _, Backbone, LogModel) { 7 | 'use strict'; 8 | var LogCollection = Backbone.Collection.extend({ 9 | model: LogModel, 10 | url: function() { 11 | return '/log'; 12 | } 13 | }); 14 | 15 | return LogCollection; 16 | }); 17 | -------------------------------------------------------------------------------- /www/collections/serverHost.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'models/serverHost' 6 | ], function($, _, Backbone, ServerHostModel) { 7 | 'use strict'; 8 | var ServerHostCollection = Backbone.Collection.extend({ 9 | model: ServerHostModel, 10 | initialize: function(options) { 11 | this.server = options.server; 12 | }, 13 | url: function() { 14 | return '/server/' + this.server + '/host'; 15 | } 16 | }); 17 | 18 | return ServerHostCollection; 19 | }); 20 | -------------------------------------------------------------------------------- /www/collections/serverLink.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'models/serverLink' 6 | ], function($, _, Backbone, ServerLinkModel) { 7 | 'use strict'; 8 | var ServerLinkCollection = Backbone.Collection.extend({ 9 | model: ServerLinkModel, 10 | initialize: function(options) { 11 | this.server = options.server; 12 | }, 13 | url: function() { 14 | return '/server/' + this.server + '/link'; 15 | } 16 | }); 17 | 18 | return ServerLinkCollection; 19 | }); 20 | -------------------------------------------------------------------------------- /www/collections/serverOrg.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'models/serverOrg' 6 | ], function($, _, Backbone, ServerOrgModel) { 7 | 'use strict'; 8 | var ServerOrgCollection = Backbone.Collection.extend({ 9 | model: ServerOrgModel, 10 | initialize: function(options) { 11 | this.server = options.server; 12 | }, 13 | url: function() { 14 | return '/server/' + this.server + '/organization'; 15 | } 16 | }); 17 | 18 | return ServerOrgCollection; 19 | }); 20 | -------------------------------------------------------------------------------- /www/collections/serverRoute.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'models/serverRoute' 6 | ], function($, _, Backbone, ServerRouteModel) { 7 | 'use strict'; 8 | var ServerRouteCollection = Backbone.Collection.extend({ 9 | model: ServerRouteModel, 10 | initialize: function(options) { 11 | this.server = options.server; 12 | }, 13 | url: function() { 14 | return '/server/' + this.server + '/route'; 15 | } 16 | }); 17 | 18 | return ServerRouteCollection; 19 | }); 20 | -------------------------------------------------------------------------------- /www/collections/userAudit.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'models/userAudit' 6 | ], function($, _, Backbone, UserAuditModel) { 7 | 'use strict'; 8 | var UserAuditCollection = Backbone.Collection.extend({ 9 | model: UserAuditModel, 10 | initialize: function(options) { 11 | this.user = options.user; 12 | }, 13 | url: function() { 14 | return '/user/' + this.user.get('organization') + '/' + 15 | this.user.get('id') + '/audit'; 16 | } 17 | }); 18 | 19 | return UserAuditCollection; 20 | }); 21 | -------------------------------------------------------------------------------- /www/collections/userDevice.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'models/userDevice' 6 | ], function($, _, Backbone, UserDeviceModel) { 7 | 'use strict'; 8 | var UserDeviceCollection = Backbone.Collection.extend({ 9 | model: UserDeviceModel 10 | }); 11 | 12 | return UserDeviceCollection; 13 | }); 14 | -------------------------------------------------------------------------------- /www/collections/userServer.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'models/userServer' 6 | ], function($, _, Backbone, UserServerModel) { 7 | 'use strict'; 8 | var UserServerCollection = Backbone.Collection.extend({ 9 | model: UserServerModel 10 | }); 11 | 12 | return UserServerCollection; 13 | }); 14 | -------------------------------------------------------------------------------- /www/dart/lib/alert.dart: -------------------------------------------------------------------------------- 1 | library alert; 2 | 3 | import 'dart:collection' as collection; 4 | 5 | collection.Queue<Alert> alerts = new collection.Queue(); 6 | 7 | class Alert { 8 | String type; 9 | String text; 10 | 11 | Alert(this.text, this.type) { 12 | alerts.add(this); 13 | 14 | while (alerts.length > 3) { 15 | alerts.removeFirst(); 16 | } 17 | } 18 | } 19 | 20 | void clear() { 21 | alerts.clear(); 22 | } 23 | -------------------------------------------------------------------------------- /www/dart/lib/all_aware.dart: -------------------------------------------------------------------------------- 1 | library all_aware; 2 | 3 | import 'package:angular/angular.dart' as ng; 4 | import 'dart:html' as dom; 5 | 6 | class AllAware implements ng.ShadowRootAware, ng.AttachAware { 7 | var _root; 8 | var _onAll; 9 | 10 | void attach() { 11 | if (this._onAll == true || this._root == null) { 12 | return; 13 | } 14 | this._onAll = true; 15 | this.onAll(this._root); 16 | } 17 | 18 | void onShadowRoot(dom.ShadowRoot root) { 19 | this._root = root; 20 | if (this._onAll == true) { 21 | return; 22 | } 23 | this._onAll = true; 24 | this.onAll(this._root); 25 | } 26 | 27 | void onAll(dom.ShadowRoot root) {} 28 | } 29 | -------------------------------------------------------------------------------- /www/dart/lib/collections/collections.dart: -------------------------------------------------------------------------------- 1 | library collections; 2 | 3 | import 'package:pritunl/collections/events.dart' as evnts; 4 | import 'package:pritunl/collections/log_entries.dart' as log_ents; 5 | import 'package:pritunl/collections/organizations.dart' as organizations; 6 | import 'package:pritunl/collections/server_hosts.dart' as svr_hsts; 7 | import 'package:pritunl/collections/server_orgs.dart' as svr_orgs; 8 | import 'package:pritunl/collections/servers.dart' as svrs; 9 | import 'package:pritunl/collections/users.dart' as usrs; 10 | 11 | import 'package:angular/angular.dart' as ng; 12 | 13 | class CollectionsMod extends ng.Module { 14 | CollectionsMod() { 15 | this.bind(evnts.Events); 16 | this.bind(log_ents.LogEntries); 17 | this.bind(organizations.Organizations); 18 | this.bind(svr_hsts.ServerHosts); 19 | this.bind(svr_orgs.ServerOrgs); 20 | this.bind(svrs.Servers); 21 | this.bind(usrs.Users); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /www/dart/lib/collections/log_entries.dart: -------------------------------------------------------------------------------- 1 | library log_entries_col; 2 | 3 | import 'package:pritunl/collection.dart' as collec; 4 | import 'package:pritunl/models/log_entry.dart' as log_ent; 5 | 6 | import 'package:angular/angular.dart' show Injectable; 7 | import 'package:angular/angular.dart' as ng; 8 | 9 | @Injectable() 10 | class LogEntries extends collec.Collection { 11 | Type model = log_ent.LogEntry; 12 | 13 | LogEntries(ng.Http http) : super(http); 14 | 15 | String get url { 16 | return '/log'; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /www/dart/lib/collections/organizations.dart: -------------------------------------------------------------------------------- 1 | library organizations_col; 2 | 3 | import 'package:pritunl/collection.dart' as collec; 4 | import 'package:pritunl/models/organization.dart' as organization; 5 | 6 | import 'package:angular/angular.dart' show Injectable; 7 | import 'package:angular/angular.dart' as ng; 8 | 9 | @Injectable() 10 | class Organizations extends collec.Collection { 11 | Type model = organization.Organization; 12 | 13 | Organizations(ng.Http http) : super(http); 14 | 15 | String get url { 16 | return '/organization'; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /www/dart/lib/collections/server_hosts.dart: -------------------------------------------------------------------------------- 1 | library server_hosts_col; 2 | 3 | import 'package:pritunl/collection.dart' as collec; 4 | import 'package:pritunl/models/server.dart' as svr; 5 | import 'package:pritunl/models/server_host.dart' as svr_hst; 6 | 7 | import 'package:angular/angular.dart' show Injectable; 8 | import 'package:angular/angular.dart' as ng; 9 | 10 | @Injectable() 11 | class ServerHosts extends collec.Collection { 12 | Type model = svr_hst.ServerHost; 13 | svr.Server server; 14 | 15 | ServerHosts(ng.Http http, this.server) : super(http); 16 | 17 | String get url { 18 | return '/server/${this.server.id}/host'; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /www/dart/lib/collections/server_orgs.dart: -------------------------------------------------------------------------------- 1 | library server_orgs_col; 2 | 3 | import 'package:pritunl/collection.dart' as collec; 4 | import 'package:pritunl/models/server.dart' as svr; 5 | import 'package:pritunl/models/server_org.dart' as svr_org; 6 | 7 | import 'package:angular/angular.dart' show Injectable; 8 | import 'package:angular/angular.dart' as ng; 9 | 10 | @Injectable() 11 | class ServerOrgs extends collec.Collection { 12 | Type model = svr_org.ServerOrg; 13 | svr.Server server; 14 | 15 | ServerOrgs(ng.Http http, this.server) : super(http); 16 | 17 | String get url { 18 | return '/server/${this.server.id}/organization'; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /www/dart/lib/collections/servers.dart: -------------------------------------------------------------------------------- 1 | library server_col; 2 | 3 | import 'package:pritunl/collection.dart' as collec; 4 | import 'package:pritunl/models/server.dart' as svr; 5 | 6 | import 'package:angular/angular.dart' show Injectable; 7 | import 'package:angular/angular.dart' as ng; 8 | 9 | @Injectable() 10 | class Servers extends collec.Collection { 11 | Type model = svr.Server; 12 | 13 | Servers(ng.Http http) : super(http); 14 | 15 | String get url { 16 | return '/server'; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /www/dart/lib/components/alert/alert.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/base.scss'; 2 | 3 | .alert { 4 | padding: 10px; 5 | margin-bottom: 10px; 6 | border-width: 1px; 7 | border-style: solid; 8 | @include border-radius-default; 9 | } 10 | 11 | .alert btn { 12 | float: right; 13 | top: -1px; 14 | position: relative; 15 | margin-right: 2px; 16 | } 17 | 18 | .alert.flash-on { 19 | @include transition(background-color .175s); 20 | } 21 | 22 | .alert.flash-off { 23 | @include transition(background-color .175s); 24 | } 25 | 26 | .alert.ng-enter { 27 | @include transition(opacity .15s linear); 28 | @include opacity(0); 29 | } 30 | 31 | .alert.ng-enter-active { 32 | @include transition(opacity .15s linear); 33 | @include opacity(1); 34 | } 35 | 36 | .alert.ng-leave { 37 | @include transition(opacity .15s linear); 38 | @include opacity(1); 39 | } 40 | 41 | .alert.ng-leave-active { 42 | @include transition(opacity .15s linear); 43 | @include opacity(0); 44 | } 45 | -------------------------------------------------------------------------------- /www/dart/lib/components/alert_global/alert_global.dart: -------------------------------------------------------------------------------- 1 | library alert_global_comp; 2 | 3 | import 'package:pritunl/alert.dart' as alrt; 4 | 5 | import 'package:angular/angular.dart' show Component; 6 | import 'dart:collection' as collection; 7 | 8 | @Component( 9 | selector: 'x-alert-global', 10 | template: '<x-alert ng-repeat="alert in alerts" type="alert.type" ' 11 | 'text="alert.text" on-dismiss="onDismiss(alert)" dismissible></x-alert>' 12 | ) 13 | class AlertGlobalComp { 14 | collection.Queue<alrt.Alert> alerts = alrt.alerts; 15 | 16 | void onDismiss(alrt.Alert alert) { 17 | this.alerts.remove(alert); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /www/dart/lib/components/boilerplate/boilerplate.dart: -------------------------------------------------------------------------------- 1 | library boilerplate_comp; 2 | 3 | import 'package:angular/angular.dart' show Component, NgTwoWay, NgAttr; 4 | 5 | @Component( 6 | selector: 'x-boilerplate', 7 | templateUrl: 'packages/pritunl/components/boilerplate/boilerplate.html', 8 | cssUrl: 'packages/pritunl/components/boilerplate/boilerplate.css' 9 | ) 10 | class BoilerplateComp { 11 | BoilerplateComp() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /www/dart/lib/components/boilerplate/boilerplate.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/dart/lib/components/boilerplate/boilerplate.html -------------------------------------------------------------------------------- /www/dart/lib/components/boilerplate/boilerplate.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/base.scss'; 2 | -------------------------------------------------------------------------------- /www/dart/lib/components/box_label/box_label.dart: -------------------------------------------------------------------------------- 1 | library box_label_comp; 2 | 3 | import 'package:angular/angular.dart' show Component, NgAttr; 4 | import 'package:angular/angular.dart' as ng; 5 | import 'dart:html' as dom; 6 | 7 | @Component( 8 | selector: 'x-box-label', 9 | template: '<span ng-class="[type, size]"><content></content></span>', 10 | cssUrl: 'packages/pritunl/components/box_label/box_label.css' 11 | ) 12 | class BoxLabelComp implements ng.ShadowRootAware { 13 | @NgAttr('padding') 14 | String padding; 15 | 16 | @NgAttr('type') 17 | String type; 18 | 19 | @NgAttr('size') 20 | String size; 21 | 22 | onShadowRoot(dom.ShadowRoot root) { 23 | if (this.padding != null) { 24 | root.querySelector('span').style.padding = this.padding; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /www/dart/lib/components/box_label/box_label.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/base.scss'; 2 | 3 | span { 4 | display: inline; 5 | padding: .2em .6em .3em; 6 | font-size: 75%; 7 | font-weight: bold; 8 | line-height: 1; 9 | text-align: center; 10 | white-space: nowrap; 11 | vertical-align: baseline; 12 | @include border-radius-default; 13 | } 14 | 15 | .large { 16 | padding: 9px 12px; 17 | } 18 | -------------------------------------------------------------------------------- /www/dart/lib/components/checkbox/checkbox.dart: -------------------------------------------------------------------------------- 1 | library checkbox_comp; 2 | 3 | import 'package:angular/angular.dart' show Component, NgTwoWay, NgCallback; 4 | import 'dart:html' as dom; 5 | 6 | @Component( 7 | selector: 'x-checkbox', 8 | template: r'<div ng-click="onClick($event)">' 9 | '<x-glyphicon type="ok" ng-if="state"></x-glyphicon></div>', 10 | cssUrl: 'packages/pritunl/components/checkbox/checkbox.css' 11 | ) 12 | class CheckboxComp { 13 | @NgTwoWay('state') 14 | bool state; 15 | 16 | @NgCallback('on-select') 17 | Function onSelect; 18 | 19 | void onClick(dom.MouseEvent evt) { 20 | if (this.onSelect != null) { 21 | this.onSelect({r'$shift': evt.shiftKey}); 22 | } 23 | else { 24 | this.state = this.state != true; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /www/dart/lib/components/checkbox/checkbox.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/base.scss'; 2 | 3 | div { 4 | width: 19px; 5 | height: 19px; 6 | padding-left: 1px; 7 | border-width: 1px; 8 | border-style: solid; 9 | cursor: pointer; 10 | display: inline-block; 11 | @include border-radius-default; 12 | } 13 | 14 | x-glyphicon { 15 | position: relative; 16 | top: -1px; 17 | font-size: 14px; 18 | } 19 | -------------------------------------------------------------------------------- /www/dart/lib/components/container/container.dart: -------------------------------------------------------------------------------- 1 | library container_comp; 2 | 3 | import 'package:angular/angular.dart' show Component; 4 | 5 | @Component( 6 | selector: 'x-container', 7 | template: '<div class="container"><content></content></div>', 8 | cssUrl: 'packages/pritunl/components/container/container.css' 9 | ) 10 | class ContainerComp { 11 | } 12 | -------------------------------------------------------------------------------- /www/dart/lib/components/container/container.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/base.scss'; 2 | 3 | .container { 4 | width: 940px; 5 | padding-right: 15px; 6 | padding-left: 15px; 7 | margin-right: auto; 8 | margin-left: auto; 9 | } 10 | 11 | .container:before, 12 | .container:after { 13 | display: table; 14 | content: " "; 15 | } 16 | 17 | .container, 18 | .container:after { 19 | clear: both; 20 | } 21 | -------------------------------------------------------------------------------- /www/dart/lib/components/form_group/form_group.dart: -------------------------------------------------------------------------------- 1 | library form_group_comp; 2 | 3 | import 'package:angular/angular.dart' show Component; 4 | 5 | @Component( 6 | selector: 'x-form-group', 7 | template: '<content></content>', 8 | cssUrl: 'packages/pritunl/components/form_group/form_group.css' 9 | ) 10 | class FormGroupComp { 11 | } 12 | -------------------------------------------------------------------------------- /www/dart/lib/components/form_group/form_group.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/base.scss'; 2 | 3 | ::content label { 4 | display: inline-block; 5 | margin-bottom: 5px; 6 | } 7 | 8 | ::content x-form-input, 9 | ::content x-form-textarea, 10 | ::content x-form-select { 11 | display: block; 12 | margin-bottom: 20px; 13 | } 14 | -------------------------------------------------------------------------------- /www/dart/lib/components/form_input/form_input.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/base.scss'; 2 | 3 | input { 4 | display: inline-block; 5 | width: 100%; 6 | height: 34px; 7 | padding: 6px 12px; 8 | font-size: 14px; 9 | line-height: 1.42857143; 10 | background-image: none; 11 | border-width: 1px; 12 | border-style: solid; 13 | @include border-radius-default; 14 | @include box-shadow((inset 0 1px 1px rgba(0, 0, 0, .075))); 15 | @include transition(( 16 | border-color ease-in-out 0.15s, 17 | box-shadow ease-in-out 0.15s 18 | )) 19 | } 20 | 21 | input:focus { 22 | outline: 0; 23 | } 24 | 25 | input::-moz-placeholder { 26 | opacity: 1; 27 | } 28 | 29 | input[disabled], 30 | input[readonly] { 31 | cursor: default; 32 | opacity: 1; 33 | } 34 | -------------------------------------------------------------------------------- /www/dart/lib/components/form_select/form_select.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/base.scss'; 2 | 3 | select { 4 | display: inline-block; 5 | width: 100%; 6 | height: 34px; 7 | padding: 6px 12px; 8 | font-size: 14px; 9 | line-height: 1.42857143; 10 | background-image: none; 11 | border-width: 1px; 12 | border-style: solid; 13 | @include border-radius-default; 14 | @include box-shadow((inset 0 1px 1px rgba(0, 0, 0, .075))); 15 | @include transition(( 16 | border-color ease-in-out 0.15s, 17 | box-shadow ease-in-out 0.15s 18 | )) 19 | } 20 | 21 | select:focus { 22 | outline: 0; 23 | } 24 | 25 | select[disabled], 26 | select[readonly] { 27 | cursor: not-allowed; 28 | opacity: 1; 29 | } 30 | -------------------------------------------------------------------------------- /www/dart/lib/components/form_textarea/form_textarea.dart: -------------------------------------------------------------------------------- 1 | library form_textarea_comp; 2 | 3 | import 'package:pritunl/bases/form_control/form_control.dart' as 4 | form_control_base; 5 | 6 | import 'package:angular/angular.dart' show Component, NgTwoWay, NgAttr; 7 | 8 | @Component( 9 | selector: 'x-form-textarea', 10 | template: '<textarea placeholder="{{placeholder}}" ' 11 | 'ng-model="model" tooltip="{{formTooltip}}" rows="{{rows}}" ' 12 | 'spellcheck="{{spellcheck}}"></textarea>', 13 | cssUrl: 'packages/pritunl/components/form_textarea/form_textarea.css' 14 | ) 15 | class FormTextareaComp extends form_control_base.FormControlBase { 16 | String controlSelector = 'input'; 17 | 18 | @NgAttr('form-tooltip') 19 | String formTooltip; 20 | 21 | @NgAttr('rows') 22 | String rows; 23 | 24 | @NgAttr('spellcheck') 25 | String spellcheck; 26 | 27 | @NgAttr('placeholder') 28 | String placeholder; 29 | 30 | @NgTwoWay('model') 31 | String model; 32 | } 33 | -------------------------------------------------------------------------------- /www/dart/lib/components/form_textarea/form_textarea.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/base.scss'; 2 | 3 | textarea { 4 | display: inline-block; 5 | width: 100%; 6 | padding: 6px 12px; 7 | font-size: 14px; 8 | line-height: 1.42857143; 9 | background-image: none; 10 | border-width: 1px; 11 | border-style: solid; 12 | resize: none; 13 | font-family: 'Lucida Console', Monaco, monospace; 14 | @include border-radius-default; 15 | @include box-shadow((inset 0 1px 1px rgba(0, 0, 0, .075))); 16 | @include transition(( 17 | border-color ease-in-out 0.15s, 18 | box-shadow ease-in-out 0.15s 19 | )) 20 | } 21 | 22 | textarea:focus { 23 | outline: 0; 24 | } 25 | 26 | textarea::-moz-placeholder { 27 | opacity: 1; 28 | } 29 | 30 | textarea[disabled], 31 | textarea[readonly] { 32 | cursor: not-allowed; 33 | opacity: 1; 34 | } 35 | -------------------------------------------------------------------------------- /www/dart/lib/components/fraction/fraction.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/base.scss'; 2 | -------------------------------------------------------------------------------- /www/dart/lib/components/glyphicon/glyphicon.dart: -------------------------------------------------------------------------------- 1 | library glyphicon_comp; 2 | 3 | import 'package:angular/angular.dart' show Component, NgAttr; 4 | 5 | @Component( 6 | selector: 'x-glyphicon', 7 | template: '<span ng-class="iconClass"></span>', 8 | cssUrl: 'packages/pritunl/components/glyphicon/glyphicon.css' 9 | ) 10 | class GlyphiconComp { 11 | @NgAttr('type') 12 | String type; 13 | 14 | String get iconClass { 15 | return 'glyphicon glyphicon-${this.type}'; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /www/dart/lib/components/log_entries/log_entries.dart: -------------------------------------------------------------------------------- 1 | library log_entries_comp; 2 | 3 | import 'package:pritunl/collections/log_entries.dart' as log_ents; 4 | 5 | import 'package:angular/angular.dart' show Component; 6 | 7 | @Component( 8 | selector: 'x-log-entries', 9 | templateUrl: 'packages/pritunl/components/log_entries/log_entries.html', 10 | cssUrl: 'packages/pritunl/components/log_entries/log_entries.css' 11 | ) 12 | class LogEntriesComp { 13 | log_ents.LogEntries entries; 14 | 15 | LogEntriesComp(this.entries) { 16 | this.update(); 17 | } 18 | 19 | void update() { 20 | this.entries.fetch(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /www/dart/lib/components/log_entries/log_entries.html: -------------------------------------------------------------------------------- 1 | <div class="log-container"> 2 | <h2 class="title">Recent log entries</h2> 3 | <ul class="entries"> 4 | <li class="entry clearfix" ng-repeat="entry in entries"> 5 | <x-glyphicon type="record"></x-glyphicon> 6 | <span class="message" ng-bind="entry.message"></span> 7 | <span class="time" ng-bind="entry.timestamp | datetime"></span> 8 | </li> 9 | </ul> 10 | </div> 11 | -------------------------------------------------------------------------------- /www/dart/lib/components/modal/modal.html: -------------------------------------------------------------------------------- 1 | <div class="container" ng-if="state" ng-animate> 2 | <div class="backdrop"></div> 3 | <div class="modal" ng-click="softClose($event.target)"> 4 | <form class="content"> 5 | <div class="header"> 6 | <btn type="close" ng-click="hardClose()"></btn> 7 | <h4 class="title">{{title}}</h4> 8 | <div ng-if="advanced" class="advanced" no-select>Advanced</div> 9 | </div> 10 | <div class="body"> 11 | <content></content> 12 | </div> 13 | <div class="footer"> 14 | <x-btn ng-if="noCancel != true" type="default" ng-click="hardClose()" 15 | disabled="cancelDisabled">{{cancelText}}</x-btn> 16 | <x-btn ng-if="noOk != true" type="primary" ng-click="submit()" 17 | disabled="okDisabled" form-submit>{{okText}}</x-btn> 18 | </div> 19 | </form> 20 | </div> 21 | </div> 22 | -------------------------------------------------------------------------------- /www/dart/lib/components/navbar/navbar.dart: -------------------------------------------------------------------------------- 1 | library navbar_comp; 2 | 3 | import 'package:pritunl/settings/settings.dart' as settings; 4 | 5 | import 'package:angular/angular.dart' show Component; 6 | 7 | @Component( 8 | selector: 'x-navbar', 9 | templateUrl: 'packages/pritunl/components/navbar/navbar.html', 10 | cssUrl: 'packages/pritunl/components/navbar/navbar.css' 11 | ) 12 | class NavbarComp { 13 | Map<String, String> active; 14 | 15 | NavbarComp() { 16 | settings.set('active_page', this); 17 | settings.observe('active_page', (_, value) { 18 | this.active = {value: 'active'}; 19 | }); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /www/dart/lib/components/navbar/navbar.html: -------------------------------------------------------------------------------- 1 | <nav no-select> 2 | <x-container> 3 | <header> 4 | <a class="brand standard-brand" href="/s">pritunl</a> 5 | <a class="brand premium-brand" href="/s">pritunl premium</a> 6 | <a class="brand enterprise-brand" href="/s">pritunl enterprise</a> 7 | </header> 8 | <ul class="links" ng-class="active"> 9 | <li ng-class="active['dashboard']"><a 10 | href="/s/#/dashboard">Dashboard</a></li> 11 | <li ng-class="active['users']"><a href="/s/#/users">Users</a></li> 12 | <li ng-class="active['servers']"><a href="/s/#/servers">Servers</a></li> 13 | <li><a href="/s/#/hosts">Hosts</a></li> 14 | </ul> 15 | <ul class="links links-right"> 16 | <li><a><box-label type="default">Upgrade to Premium!</box-label></a></li> 17 | <li><a>Subscription</a></li> 18 | <li><a>Settings</a></li> 19 | <li><a href="/s/#/logout">Logout</a></li> 20 | </ul> 21 | <x-box-label class="feedback" type="success">Provide Feedback</x-box-label> 22 | </x-container> 23 | </nav> 24 | -------------------------------------------------------------------------------- /www/dart/lib/components/org_add/org_add.html: -------------------------------------------------------------------------------- 1 | <x-modal title="Add Organization" ok-text="Add" 2 | ok-disabled="okDisabled"> 3 | <x-alert type="alertType" text="alertText"></x-alert> 4 | <x-form-group> 5 | <label>Name</label> 6 | <x-form-input class="name" type="text" model="model.name" 7 | placeholder="Name of organization" 8 | form-tooltip="Enter name"></x-form-input> 9 | </x-form-group> 10 | </x-modal> 11 | -------------------------------------------------------------------------------- /www/dart/lib/components/org_del/org_del.html: -------------------------------------------------------------------------------- 1 | <x-modal title="Delete Organization" ok-text="Delete" ok-disabled="okDisabled"> 2 | <x-alert type="'danger'">Deleting the organization will delete all the users 3 | in it. Any servers that are attached to the organization will be 4 | stopped.</x-alert> 5 | <x-alert type="alertType" text="alertText"></x-alert> 6 | <x-form-group> 7 | <label>Enter the name of the organization to confirm</label> 8 | <x-form-input class="name" type="text" model="nameConfirm" 9 | placeholder="Name of organization" 10 | form-tooltip="Enter name"></x-form-input> 11 | </x-form-group> 12 | </x-modal> 13 | -------------------------------------------------------------------------------- /www/dart/lib/components/org_modify/org_modify.html: -------------------------------------------------------------------------------- 1 | <x-modal title="Modify Organization" ok-text="Rename" 2 | ok-disabled="okDisabled"> 3 | <x-alert type="alertType" text="alertText"></x-alert> 4 | <x-form-group> 5 | <label>Rename {{origModel.name}}</label> 6 | <x-form-input class="name" type="text" model="model.name" 7 | placeholder="Name of organization" 8 | form-tooltip="Enter new name"></x-form-input> 9 | </x-form-group> 10 | </x-modal> 11 | -------------------------------------------------------------------------------- /www/dart/lib/components/organizations/organizations.html: -------------------------------------------------------------------------------- 1 | <div class="header"> 2 | <h1 class="title">Users and Organizations</h1> 3 | <div class="buttons"> 4 | <x-org-add></x-org-add> 5 | <x-btn type="primary" modal-attach="x-org-add">Add Organization</x-btn> 6 | <x-user-add orgs="orgs"></x-user-add> 7 | <x-btn type="primary" modal-attach="x-user-add">Add User</x-btn> 8 | <x-user-add-bulk orgs="orgs"></x-user-add-bulk> 9 | <x-btn type="primary" modal-attach="x-user-add-bulk">Bulk Add Users</x-btn> 10 | <x-user-email users="selected"></x-user-email> 11 | <x-btn type="warning" modal-attach="x-user-email" 12 | disabled="selected.length == 0">Email Selected</x-btn> 13 | <x-user-del users="selected"></x-user-del> 14 | <x-btn type="danger" modal-attach="x-user-del" 15 | disabled="selected.length == 0">Delete Selected</x-btn> 16 | </div> 17 | </div> 18 | <x-alert-global></x-alert-global> 19 | <ul> 20 | <li class="org" ng-repeat="org in orgs"> 21 | <x-organization model="org" selected="selected"></x-organization> 22 | </li> 23 | <li ng-if="message != null" class="message"> 24 | <span ng-bind="message"></span> 25 | </li> 26 | </ul> 27 | -------------------------------------------------------------------------------- /www/dart/lib/components/organizations/organizations.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/base.scss'; 2 | 3 | .header .title { 4 | margin-top: 6px; 5 | margin-bottom: 19px; 6 | font-size: 22px; 7 | display: inline-block; 8 | } 9 | 10 | .header .buttons { 11 | float: right; 12 | display: block; 13 | } 14 | 15 | .header .buttons button { 16 | margin-top: 2px; 17 | } 18 | 19 | .message { 20 | margin-bottom: 25px; 21 | border-width: 1px; 22 | border-style: solid; 23 | text-align: center; 24 | font-size: 14px; 25 | padding: 10px; 26 | @include border-radius-default; 27 | @include box-shadow(( 28 | 0 2px 1px rgba(0, 0, 0, 0.05), 29 | 0 -1px 2px rgba(0, 0, 0, 0.05) inset 30 | )) 31 | } 32 | -------------------------------------------------------------------------------- /www/dart/lib/components/qrcode/qrcode.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/dart/lib/components/qrcode/qrcode.html -------------------------------------------------------------------------------- /www/dart/lib/components/server_del/server_del.html: -------------------------------------------------------------------------------- 1 | <x-modal title="Delete Server" ok-text="Delete" ok-disabled="okDisabled"> 2 | <x-alert type="alertType" text="alertText"></x-alert> 3 | <x-form-group> 4 | <label>Enter the name of the server to confirm</label> 5 | <x-form-input class="name" type="text" model="nameConfirm" 6 | placeholder="Name of server" 7 | form-tooltip="Enter name"></x-form-input> 8 | </x-form-group> 9 | </x-modal> 10 | -------------------------------------------------------------------------------- /www/dart/lib/components/servers/servers.html: -------------------------------------------------------------------------------- 1 | <div class="header"> 2 | <h1 class="title">Servers</h1> 3 | <div class="buttons"> 4 | <x-btn type="primary">Add Server</x-btn> 5 | <x-btn type="primary">Attach Organization</x-btn> 6 | <x-btn type="primary">Attach Host</x-btn> 7 | <x-btn type="primary">Link Server</x-btn> 8 | </div> 9 | </div> 10 | <x-alert-global></x-alert-global> 11 | <ul> 12 | <li class="server" ng-repeat="server in servers"> 13 | <x-server model="server"></x-server> 14 | </li> 15 | <li ng-if="message != null" class="message"> 16 | <span ng-bind="message"></span> 17 | </li> 18 | </ul> 19 | -------------------------------------------------------------------------------- /www/dart/lib/components/servers/servers.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/base.scss'; 2 | 3 | .header .title { 4 | margin-top: 6px; 5 | margin-bottom: 19px; 6 | font-size: 22px; 7 | display: inline-block; 8 | } 9 | 10 | .header .buttons { 11 | float: right; 12 | display: block; 13 | } 14 | 15 | .header .buttons button { 16 | margin-top: 2px; 17 | } 18 | 19 | .message { 20 | margin-bottom: 25px; 21 | border-width: 1px; 22 | border-style: solid; 23 | text-align: center; 24 | font-size: 14px; 25 | padding: 10px; 26 | @include border-radius-default; 27 | @include box-shadow(( 28 | 0 2px 1px rgba(0, 0, 0, 0.05), 29 | 0 -1px 2px rgba(0, 0, 0, 0.05) inset 30 | )) 31 | } 32 | -------------------------------------------------------------------------------- /www/dart/lib/components/status/status.dart: -------------------------------------------------------------------------------- 1 | library status_comp; 2 | 3 | import 'package:pritunl/models/status.dart' as stus; 4 | 5 | import 'package:angular/angular.dart' show Component; 6 | 7 | @Component( 8 | selector: 'x-status', 9 | templateUrl: 'packages/pritunl/components/status/status.html', 10 | cssUrl: 'packages/pritunl/components/status/status.css' 11 | ) 12 | class StatusComp { 13 | stus.Status model; 14 | 15 | StatusComp(this.model) { 16 | this.update(); 17 | } 18 | 19 | void update() { 20 | this.model.fetch(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /www/dart/lib/components/user_add/user_add.html: -------------------------------------------------------------------------------- 1 | <x-modal title="Add User" ok-text="Add" ok-disabled="okDisabled"> 2 | <x-alert type="alertType" text="alertText"></x-alert> 3 | <x-form-group> 4 | <label>Name</label> 5 | <x-form-input class="name" type="text" placeholder="Enter name" 6 | model="model.name" form-tooltip="Enter name"></x-form-input> 7 | </x-form-group> 8 | <x-form-group> 9 | <label>Select an organization</label> 10 | <x-form-select class="org" model="model.organization" collection="orgs" 11 | form-tooltip="Organization to add user to" 12 | opt-value="$model.id" opt-text="$model.name"></x-form-select> 13 | </x-form-group> 14 | <x-form-group> 15 | <label>Email (optional)</label> 16 | <x-form-input class="email" type="text" placeholder="Enter email address" 17 | model="model.email" form-tooltip="Email address of user"></x-form-input> 18 | </x-form-group> 19 | </x-modal> 20 | -------------------------------------------------------------------------------- /www/dart/lib/components/user_add_bulk/user_add_bulk.html: -------------------------------------------------------------------------------- 1 | <x-modal title="Bulk Add Users" ok-text="Add" ok-disabled="okDisabled"> 2 | <x-alert type="alertType" text="alertText"></x-alert> 3 | <x-form-group> 4 | <label>Enter list of usernames and optionally an email addresses on 5 | each line with a comma separating the username from the email 6 | address</label> 7 | <x-form-textarea class="users" type="text" model="users" 8 | rows="12" spellcheck="false" 9 | placeholder="user1,user1@pritunl.com"></x-form-textarea> 10 | </x-form-group> 11 | <x-form-group> 12 | <label>Select an organization</label> 13 | <x-form-select class="org" model="model.org" collection="orgs" 14 | form-tooltip="Organization to add user to" 15 | opt-value="$model.id" opt-text="$model.name"></x-form-select> 16 | </x-form-group> 17 | </x-modal> 18 | -------------------------------------------------------------------------------- /www/dart/lib/components/user_del/user_del.html: -------------------------------------------------------------------------------- 1 | <x-modal title="Delete Users" ok-text="Delete" ok-disabled="okDisabled"> 2 | <x-alert type="alertType" text="alertText"></x-alert> 3 | <label>Are you sure you want to delete the following users?</label> 4 | <ul class="users"> 5 | <li ng-repeat="user in users" ng-bind="user.name"></li> 6 | </ul> 7 | </x-modal> 8 | -------------------------------------------------------------------------------- /www/dart/lib/components/user_del/user_del.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/base.scss'; 2 | 3 | modal .users { 4 | padding-left: 30px; 5 | margin-top: 5px; 6 | margin-bottom: 20px; 7 | } 8 | 9 | modal .users li { 10 | list-style-type: disc; 11 | } 12 | -------------------------------------------------------------------------------- /www/dart/lib/components/user_email/user_email.html: -------------------------------------------------------------------------------- 1 | <x-modal title="Email Users" ok-text="{{okText}}" no-cancel="{{noCancel}}" 2 | ok-disabled="okDisabled"> 3 | <x-alert type="alertType" text="alertText"></x-alert> 4 | <label>Are you sure you want to email a key link to the following 5 | users?</label> 6 | <ul class="users"> 7 | <li ng-repeat="user in users" ng-bind="getUserData(user)" 8 | ng-class="userClass[user]"></li> 9 | </ul> 10 | </x-modal> 11 | -------------------------------------------------------------------------------- /www/dart/lib/components/user_email/user_email.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/base.scss'; 2 | 3 | modal .users { 4 | padding-left: 30px; 5 | margin-top: 5px; 6 | margin-bottom: 20px; 7 | } 8 | 9 | modal .users li { 10 | list-style-type: disc; 11 | } 12 | -------------------------------------------------------------------------------- /www/dart/lib/components/user_key_links/user_key_links.dart: -------------------------------------------------------------------------------- 1 | library user_key_links_comp; 2 | 3 | import 'package:pritunl/bases/modal_content/modal_content.dart' as 4 | modal_content_base; 5 | import 'package:pritunl/models/user.dart' as usr; 6 | import 'package:pritunl/models/key.dart' as ky; 7 | 8 | import 'package:angular/angular.dart' show Component, NgOneWayOneTime; 9 | 10 | @Component( 11 | selector: 'x-user-key-links', 12 | templateUrl: 'packages/pritunl/components/user_key_links/user_key_links.html', 13 | cssUrl: 'packages/pritunl/components/user_key_links/user_key_links.css' 14 | ) 15 | class UserKeyLinksComp extends modal_content_base.ModalContent { 16 | ky.Key model; 17 | 18 | @NgOneWayOneTime('model') 19 | usr.User user; 20 | 21 | UserKeyLinksComp(this.model); 22 | 23 | void show() { 24 | this.model.user = this.user.id; 25 | this.model.org = this.user.organization; 26 | this.model.fetch(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /www/dart/lib/components/user_key_links/user_key_links.scss: -------------------------------------------------------------------------------- 1 | a { 2 | float: right; 3 | top: -49px; 4 | left: -7px; 5 | position: relative; 6 | font-size: 21px; 7 | } 8 | -------------------------------------------------------------------------------- /www/dart/lib/components/user_modify/user_modify.html: -------------------------------------------------------------------------------- 1 | <x-modal title="Modify User" ok-text="Save" ok-disabled="okDisabled"> 2 | <x-alert type="alertType" text="alertText"></x-alert> 3 | <fx-orm-group> 4 | <label>Name</label> 5 | <x-form-input class="name" type="text" placeholder="Enter name" 6 | model="model.name" form-tooltip="Enter name"></x-form-input> 7 | </fx-orm-group> 8 | <fx-orm-group> 9 | <label>Email (optional)</label> 10 | <x-form-input class="email" type="text" placeholder="Enter email address" 11 | model="model.email" form-tooltip="Email address of user"></x-form-input> 12 | </fx-orm-group> 13 | </x-modal> 14 | -------------------------------------------------------------------------------- /www/dart/lib/components/user_otp/user_otp.html: -------------------------------------------------------------------------------- 1 | <x-modal title="Two-Step Authentication Key" no-cancel> 2 | <x-alert type="alertType" text="alertText"></x-alert> 3 | <label>Two-step authentication key</label> 4 | <x-form-input class="name" width="190px" value="model.otpSecret" 5 | type="text" readonly click-select></x-form-input> 6 | <x-qrcode width="192" height="192" text="qrcodeText"></x-qrcode> 7 | <x-btn type="danger" width="190px" ng-click="newKey()" 8 | disabled="genKeyDisabled">Generate New Key</x-btn> 9 | </x-modal> 10 | -------------------------------------------------------------------------------- /www/dart/lib/components/user_otp/user_otp.scss: -------------------------------------------------------------------------------- 1 | label, 2 | x-form-input, 3 | x-btn { 4 | display: block; 5 | text-align: center; 6 | } 7 | 8 | label { 9 | margin-bottom: 5px; 10 | } 11 | 12 | x-form-input { 13 | margin-bottom: 15px; 14 | } 15 | 16 | x-btn { 17 | margin-top: 15px; 18 | margin-bottom: 20px; 19 | } 20 | -------------------------------------------------------------------------------- /www/dart/lib/decorators/autofocus.dart: -------------------------------------------------------------------------------- 1 | library autofocus_dec; 2 | 3 | import 'package:angular/angular.dart' show Decorator; 4 | import 'package:angular/angular.dart' as ng; 5 | import 'dart:html' as dom; 6 | 7 | @Decorator( 8 | selector: '[autofocus]' 9 | ) 10 | class AutoFocusDec implements ng.AttachAware { 11 | dom.Element element; 12 | 13 | AutoFocusDec(this.element); 14 | 15 | void attach() { 16 | element.focus(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /www/dart/lib/decorators/conditional.dart: -------------------------------------------------------------------------------- 1 | library conditional_dec; 2 | 3 | import 'package:angular/angular.dart' as ng; 4 | import 'dart:html' as dom; 5 | 6 | abstract class Conditional { 7 | final ng.ViewFactory _viewFactory; 8 | final ng.ViewPort _viewPort; 9 | final ng.Scope _scope; 10 | ng.View _view; 11 | dom.Element element; 12 | 13 | Conditional(this._viewFactory, this._viewPort, this._scope); 14 | 15 | void set condition(value) { 16 | if (value == true) { 17 | this._ensureViewExists(); 18 | } else { 19 | this._ensureViewDestroyed(); 20 | } 21 | } 22 | 23 | void _ensureViewExists() { 24 | if (this._view == null) { 25 | this._view = this._viewPort.insertNew(this._viewFactory); 26 | this.element = this._view.nodes[0]; 27 | } 28 | } 29 | 30 | void _ensureViewDestroyed() { 31 | if (this._view != null) { 32 | this._viewPort.remove(this._view); 33 | this._view = null; 34 | this.element = null; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /www/dart/lib/decorators/decorators.dart: -------------------------------------------------------------------------------- 1 | library decorators; 2 | 3 | import 'package:pritunl/decorators/autofocus.dart' as autofocus; 4 | import 'package:pritunl/decorators/modal.dart' as modal; 5 | import 'package:pritunl/decorators/modal_attach.dart' as modal_attach; 6 | import 'package:pritunl/decorators/noselect.dart' as noselect; 7 | import 'package:pritunl/decorators/shift_click.dart' as shift_click; 8 | import 'package:pritunl/decorators/tooltip.dart' as tooltip; 9 | 10 | import 'package:angular/angular.dart' as ng; 11 | 12 | class DecoratorsMod extends ng.Module { 13 | DecoratorsMod() { 14 | this.bind(autofocus.AutoFocusDec); 15 | this.bind(modal.ModalDec); 16 | this.bind(modal_attach.ModalAttachDec); 17 | this.bind(noselect.NoSelectDec); 18 | this.bind(shift_click.ShiftClickDec); 19 | this.bind(tooltip.TooltipDec); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /www/dart/lib/decorators/noselect.dart: -------------------------------------------------------------------------------- 1 | library noselect_dec; 2 | 3 | import 'package:angular/angular.dart' show Decorator; 4 | import 'dart:html' as dom; 5 | 6 | @Decorator( 7 | selector: '[no-select]' 8 | ) 9 | class NoSelectDec { 10 | NoSelectDec(dom.Element element) { 11 | element.onMouseDown.listen((evt) { 12 | evt.preventDefault(); 13 | }); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /www/dart/lib/decorators/shift_click.dart: -------------------------------------------------------------------------------- 1 | library shift_click_dec; 2 | 3 | import 'package:angular/angular.dart' show Decorator, NgCallback; 4 | import 'dart:html' as dom; 5 | 6 | @Decorator( 7 | selector: '[shift-click]' 8 | ) 9 | class ShiftClickDec { 10 | @NgCallback('shift-click') 11 | Function callback; 12 | 13 | ShiftClickDec(dom.Element element) { 14 | element.onClick.listen((evt) { 15 | if (evt.shiftKey) { 16 | this.callback(); 17 | } 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /www/dart/lib/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/dart/lib/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /www/dart/lib/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/dart/lib/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /www/dart/lib/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/dart/lib/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /www/dart/lib/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/dart/lib/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /www/dart/lib/fonts/fredoka-one.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/dart/lib/fonts/fredoka-one.eot -------------------------------------------------------------------------------- /www/dart/lib/fonts/fredoka-one.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/dart/lib/fonts/fredoka-one.woff -------------------------------------------------------------------------------- /www/dart/lib/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/dart/lib/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /www/dart/lib/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/dart/lib/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /www/dart/lib/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/dart/lib/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /www/dart/lib/fonts/ubuntu-bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/dart/lib/fonts/ubuntu-bold.eot -------------------------------------------------------------------------------- /www/dart/lib/fonts/ubuntu-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/dart/lib/fonts/ubuntu-bold.woff -------------------------------------------------------------------------------- /www/dart/lib/fonts/ubuntu.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/dart/lib/fonts/ubuntu.eot -------------------------------------------------------------------------------- /www/dart/lib/fonts/ubuntu.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/dart/lib/fonts/ubuntu.woff -------------------------------------------------------------------------------- /www/dart/lib/formatters/capitalize.dart: -------------------------------------------------------------------------------- 1 | library capitalize_form; 2 | 3 | import 'package:angular/angular.dart' show Formatter; 4 | 5 | @Formatter(name: 'capitalize') 6 | class CapitalizeForm { 7 | String call(String input) { 8 | if (input == null) { 9 | return null; 10 | } 11 | 12 | if (input.length < 1) { 13 | return input; 14 | } 15 | 16 | return input.substring(0, 1).toUpperCase() + input.substring(1); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /www/dart/lib/formatters/datetime.dart: -------------------------------------------------------------------------------- 1 | library datetime_form; 2 | 3 | import 'package:angular/angular.dart' show Formatter; 4 | 5 | @Formatter(name: 'datetime') 6 | class DatetimeForm { 7 | String call(int time) { 8 | if (time == null) { 9 | return null; 10 | } 11 | 12 | var date = new DateTime.fromMillisecondsSinceEpoch(time * 1000); 13 | 14 | var abbrev = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 15 | 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; 16 | var month = abbrev[date.month - 1]; 17 | 18 | var day = date.day.toString(); 19 | 20 | var year = date.year; 21 | 22 | var meridiem; 23 | var hour = date.hour; 24 | if (hour > 12) { 25 | meridiem = 'pm'; 26 | hour = (hour - 12).toString(); 27 | } 28 | else { 29 | meridiem = 'am'; 30 | hour = hour.toString(); 31 | } 32 | 33 | var minute = date.minute.toString(); 34 | if (minute.length < 2) { 35 | minute = '0$minute'; 36 | } 37 | 38 | return '$hour:$minute $meridiem - $month $day $year'; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /www/dart/lib/formatters/formatters.dart: -------------------------------------------------------------------------------- 1 | library formatters; 2 | 3 | import 'package:pritunl/formatters/capitalize.dart' as capitalize; 4 | import 'package:pritunl/formatters/datetime.dart' as datetime; 5 | import 'package:pritunl/formatters/fraction.dart' as fraction; 6 | import 'package:pritunl/formatters/slash.dart' as slash; 7 | import 'package:pritunl/formatters/timer.dart' as timer; 8 | 9 | import 'package:angular/angular.dart' as ng; 10 | 11 | class FormattersMod extends ng.Module { 12 | FormattersMod() { 13 | this.bind(capitalize.CapitalizeForm); 14 | this.bind(datetime.DatetimeForm); 15 | this.bind(fraction.FractionForm); 16 | this.bind(slash.SlashForm); 17 | this.bind(timer.TimerForm); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /www/dart/lib/formatters/fraction.dart: -------------------------------------------------------------------------------- 1 | library fraction_form; 2 | 3 | import 'package:angular/angular.dart' show Formatter; 4 | 5 | @Formatter(name: 'fraction') 6 | class FractionForm { 7 | String call(List<int> input) { 8 | if (input[0] == null || input[1] == null || ( 9 | input[0] == 0 && input[1] == 0)) { 10 | return '-/-'; 11 | } 12 | return '${input[0]}/${input[1]}'; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /www/dart/lib/formatters/slash.dart: -------------------------------------------------------------------------------- 1 | library slash_form; 2 | 3 | import 'package:angular/angular.dart' show Formatter; 4 | 5 | @Formatter(name: 'slash') 6 | class SlashForm { 7 | dynamic call(dynamic input) { 8 | if (input == null) { 9 | return '-'; 10 | } 11 | return input; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /www/dart/lib/formatters/timer.dart: -------------------------------------------------------------------------------- 1 | library timer_form; 2 | 3 | import 'package:angular/angular.dart' show Formatter; 4 | 5 | @Formatter(name: 'timer') 6 | class TimerForm { 7 | String call(int count) { 8 | if (count == null || count == 0) { 9 | return '-'; 10 | } 11 | 12 | var days = (count / 86400).floor(); 13 | count -= days * 86400; 14 | 15 | var hours = (count / 3600).floor(); 16 | count -= hours * 3600; 17 | 18 | var mins = (count / 60).floor(); 19 | count -= mins * 60; 20 | 21 | if (days > 0) { 22 | return '${days}d ${hours}h ${mins}m ${count}s'; 23 | } 24 | else if (hours > 0) { 25 | return '${hours}h ${mins}m ${count}s'; 26 | } 27 | else if (mins > 0) { 28 | return '${mins}m ${count}s'; 29 | } 30 | else { 31 | return '${count}s'; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /www/dart/lib/models/event.dart: -------------------------------------------------------------------------------- 1 | library event_mod; 2 | 3 | import 'package:pritunl/model.dart' as mdl; 4 | 5 | import 'package:angular/angular.dart' show Injectable; 6 | import 'package:angular/angular.dart' as ng; 7 | 8 | @Injectable() 9 | class Event extends mdl.Model { 10 | @mdl.Attribute('id') 11 | String id; 12 | 13 | @mdl.Attribute('type') 14 | String type; 15 | 16 | @mdl.Attribute('resource_id') 17 | String resourceId; 18 | 19 | @mdl.Attribute('timestamp') 20 | double timestamp; 21 | 22 | Event(ng.Http http) : super(http); 23 | } 24 | -------------------------------------------------------------------------------- /www/dart/lib/models/log_entry.dart: -------------------------------------------------------------------------------- 1 | library log_entry_mod; 2 | 3 | import 'package:pritunl/model.dart' as mdl; 4 | 5 | import 'package:angular/angular.dart' show Injectable; 6 | import 'package:angular/angular.dart' as ng; 7 | 8 | @Injectable() 9 | class LogEntry extends mdl.Model { 10 | @mdl.Attribute('id') 11 | String id; 12 | 13 | @mdl.Attribute('timestamp') 14 | int timestamp; 15 | 16 | @mdl.Attribute('message') 17 | String message; 18 | 19 | LogEntry(ng.Http http) : super(http); 20 | } 21 | -------------------------------------------------------------------------------- /www/dart/lib/models/organization.dart: -------------------------------------------------------------------------------- 1 | library organization_mod; 2 | 3 | import 'package:pritunl/model.dart' as mdl; 4 | import 'package:pritunl/collections/users.dart' as usrs; 5 | 6 | import 'package:angular/angular.dart' show Injectable; 7 | import 'package:angular/angular.dart' as ng; 8 | 9 | @Injectable() 10 | class Organization extends mdl.Model { 11 | usrs.Users users; 12 | 13 | @mdl.Attribute('id') 14 | String id; 15 | 16 | @mdl.Attribute('name') 17 | String name; 18 | 19 | @mdl.Validator('name') 20 | void nameValidator(val) { 21 | if (val == null || val == '') { 22 | throw new mdl.Invalid('empty', 'Organization name cannot be empty'); 23 | } 24 | } 25 | 26 | @mdl.Attribute('user_count') 27 | int userCount; 28 | 29 | Organization(ng.Http http) : super(http); 30 | 31 | String get url { 32 | var url = '/organization'; 33 | 34 | if (this.id != null) { 35 | url += '/${this.id}'; 36 | } 37 | 38 | return url; 39 | } 40 | 41 | void init() { 42 | this.users = new usrs.Users(this.http); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /www/dart/lib/models/server_host.dart: -------------------------------------------------------------------------------- 1 | library server_host_mod; 2 | 3 | import 'package:pritunl/model.dart' as mdl; 4 | 5 | import 'package:angular/angular.dart' show Injectable; 6 | import 'package:angular/angular.dart' as ng; 7 | 8 | @Injectable() 9 | class ServerHost extends mdl.Model { 10 | @mdl.Attribute('id') 11 | String id; 12 | 13 | @mdl.Attribute('name') 14 | String name; 15 | 16 | @mdl.Attribute('server') 17 | String server; 18 | 19 | @mdl.Attribute('status') 20 | String status; 21 | 22 | @mdl.Attribute('address') 23 | String address; 24 | 25 | ServerHost(ng.Http http) : super(http); 26 | 27 | String get url { 28 | var url = '/server/${this.server}/host'; 29 | 30 | if (this.id != null) { 31 | url += '/${this.id}'; 32 | } 33 | 34 | return url; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /www/dart/lib/models/server_link_output.dart: -------------------------------------------------------------------------------- 1 | library server_link_output_mod; 2 | 3 | import 'package:pritunl/model.dart' as mdl; 4 | import 'package:pritunl/models/server.dart' as svr; 5 | 6 | import 'package:angular/angular.dart' show Injectable; 7 | import 'package:angular/angular.dart' as ng; 8 | 9 | @Injectable() 10 | class ServerLinkOutput extends mdl.Model { 11 | svr.Server server; 12 | 13 | @mdl.Attribute('output') 14 | List<String> output; 15 | 16 | ServerLinkOutput(ng.Http http, this.server) : super(http); 17 | 18 | String get url { 19 | return '/server/${this.server.id}/link_output'; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /www/dart/lib/models/server_org.dart: -------------------------------------------------------------------------------- 1 | library server_org_mod; 2 | 3 | import 'package:pritunl/model.dart' as mdl; 4 | 5 | import 'package:angular/angular.dart' show Injectable; 6 | import 'package:angular/angular.dart' as ng; 7 | 8 | @Injectable() 9 | class ServerOrg extends mdl.Model { 10 | @mdl.Attribute('id') 11 | String id; 12 | 13 | @mdl.Attribute('name') 14 | String name; 15 | 16 | @mdl.Attribute('server') 17 | String server; 18 | 19 | ServerOrg(ng.Http http) : super(http); 20 | 21 | String get url { 22 | var url = '/server/${this.server}/organization'; 23 | 24 | if (this.id != null) { 25 | url += '/${this.id}'; 26 | } 27 | 28 | return url; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /www/dart/lib/models/server_output.dart: -------------------------------------------------------------------------------- 1 | library server_output_mod; 2 | 3 | import 'package:pritunl/model.dart' as mdl; 4 | import 'package:pritunl/models/server.dart' as svr; 5 | 6 | import 'package:angular/angular.dart' show Injectable; 7 | import 'package:angular/angular.dart' as ng; 8 | 9 | @Injectable() 10 | class ServerOutput extends mdl.Model { 11 | svr.Server server; 12 | 13 | @mdl.Attribute('output') 14 | List<String> output; 15 | 16 | ServerOutput(ng.Http http, this.server) : super(http); 17 | 18 | String get url { 19 | return '/server/${this.server.id}/output'; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /www/dart/lib/models/status.dart: -------------------------------------------------------------------------------- 1 | library status_mod; 2 | 3 | import 'package:pritunl/model.dart' as mdl; 4 | 5 | import 'package:angular/angular.dart' show Injectable; 6 | import 'package:angular/angular.dart' as ng; 7 | 8 | @Injectable() 9 | class Status extends mdl.Model { 10 | @mdl.Attribute('org_count') 11 | int orgCount; 12 | 13 | @mdl.Attribute('users_online') 14 | int usersOnline; 15 | 16 | @mdl.Attribute('user_count') 17 | int userCount; 18 | 19 | @mdl.Attribute('servers_online') 20 | int serversOnline; 21 | 22 | @mdl.Attribute('server_count') 23 | int serverCount; 24 | 25 | @mdl.Attribute('hosts_online') 26 | int hostsOnline; 27 | 28 | @mdl.Attribute('host_count') 29 | int hostCount; 30 | 31 | @mdl.Attribute('server_version') 32 | String serverVersion; 33 | 34 | @mdl.Attribute('current_host') 35 | String currentHost; 36 | 37 | @mdl.Attribute('public_ip') 38 | String publicIp; 39 | 40 | @mdl.Attribute('local_networks') 41 | List<String> localNetworks; 42 | 43 | @mdl.Attribute('notification') 44 | String notification; 45 | 46 | Status(ng.Http http) : super(http); 47 | 48 | String get url { 49 | return '/status'; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /www/dart/lib/pritunl.dart: -------------------------------------------------------------------------------- 1 | library pritunl; 2 | 3 | export 'package:pritunl/transformers/sass.dart'; 4 | -------------------------------------------------------------------------------- /www/dart/lib/routers/main.dart: -------------------------------------------------------------------------------- 1 | library main_rout; 2 | 3 | import 'package:pritunl/settings/settings.dart' as settings; 4 | import 'package:pritunl/alert.dart' as alrt; 5 | 6 | import 'package:angular/angular.dart' as ng; 7 | 8 | MainRout(ng.Router router, ng.RouteViewFactory views) { 9 | views.configure({ 10 | 'dashboard': ng.ngRoute( 11 | path: '/dashboard', 12 | view: 'packages/pritunl/views/dashboard.html', 13 | enter: (_) { 14 | alrt.clear(); 15 | settings.set('active_page', 'dashboard'); 16 | }, 17 | defaultRoute: true 18 | ), 19 | 'users': ng.ngRoute( 20 | path: '/users', 21 | view: 'packages/pritunl/views/users.html', 22 | enter: (_) { 23 | alrt.clear(); 24 | settings.set('active_page', 'users'); 25 | } 26 | ), 27 | 'servers': ng.ngRoute( 28 | path: '/servers', 29 | view: 'packages/pritunl/views/servers.html', 30 | enter: (_) { 31 | alrt.clear(); 32 | settings.set('active_page', 'servers'); 33 | } 34 | ) 35 | }); 36 | } 37 | -------------------------------------------------------------------------------- /www/dart/lib/routers/routers.dart: -------------------------------------------------------------------------------- 1 | library routers; 2 | 3 | import 'package:pritunl/routers/main.dart' as main; 4 | 5 | import 'package:angular/angular.dart' as ng; 6 | 7 | class RoutersMod extends ng.Module { 8 | RoutersMod() { 9 | this.bind( 10 | ng.RouteInitializerFn, 11 | toValue: main.MainRout 12 | ); 13 | this.bind( 14 | ng.NgRoutingUsePushState, 15 | toValue: new ng.NgRoutingUsePushState.value(false) 16 | ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /www/dart/lib/settings/settings.dart: -------------------------------------------------------------------------------- 1 | library settings; 2 | 3 | var _data = {}; 4 | var _observers = {}; 5 | 6 | dynamic get(String name) { 7 | return _data[name]; 8 | } 9 | 10 | set(String name, dynamic value) { 11 | _data[name] = value; 12 | if (_observers[name] != null) { 13 | _observers[name](name, value); 14 | } 15 | } 16 | 17 | void observe(String name, Function callback) { 18 | _observers[name] = callback; 19 | } 20 | -------------------------------------------------------------------------------- /www/dart/lib/styles/base.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/variables.scss'; 2 | @import 'styles/mixins.scss'; 3 | -------------------------------------------------------------------------------- /www/dart/lib/views/dashboard.html: -------------------------------------------------------------------------------- 1 | <x-container> 2 | <x-status></x-status> 3 | <x-alert-global></x-alert-global> 4 | <x-log-entries></x-log-entries> 5 | </x-container> 6 | -------------------------------------------------------------------------------- /www/dart/lib/views/servers.html: -------------------------------------------------------------------------------- 1 | <x-container> 2 | <x-servers></x-servers> 3 | </x-container> 4 | -------------------------------------------------------------------------------- /www/dart/lib/views/users.html: -------------------------------------------------------------------------------- 1 | <x-container> 2 | <x-organizations></x-organizations> 3 | </x-container> 4 | -------------------------------------------------------------------------------- /www/dart/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: pritunl 2 | version: 1.0.0 3 | dependencies: 4 | angular: ">=1.1.0 <2.0.0" 5 | web_components: ">=0.10.1" 6 | browser: ">=0.10.0+2" 7 | barback: ">=0.14.1" 8 | logging: ">=0.9.3" 9 | transformers: 10 | - pritunl 11 | - angular 12 | -------------------------------------------------------------------------------- /www/dart/web/main.dart: -------------------------------------------------------------------------------- 1 | library pritunl; 2 | 3 | import 'package:pritunl/routers/routers.dart' as routers; 4 | import 'package:pritunl/collections/collections.dart' as collections; 5 | import 'package:pritunl/collections/events.dart' as evnts; 6 | import 'package:pritunl/components/components.dart' as components; 7 | import 'package:pritunl/decorators/decorators.dart' as decorators; 8 | import 'package:pritunl/formatters/formatters.dart' as formatters; 9 | import 'package:pritunl/models/models.dart' as models; 10 | import 'package:pritunl/logger.dart' as logger; 11 | 12 | import 'package:angular/application_factory.dart' as appfactory; 13 | import 'package:angular/animate/module.dart' as animate; 14 | 15 | void main() { 16 | logger.setup(); 17 | var app = appfactory.applicationFactory() 18 | .addModule(new routers.RoutersMod()) 19 | .addModule(new collections.CollectionsMod()) 20 | .addModule(new components.ComponentsMod()) 21 | .addModule(new decorators.DecoratorsMod()) 22 | .addModule(new formatters.FormattersMod()) 23 | .addModule(new models.ModelsMod()) 24 | .addModule(new animate.AnimationModule()) 25 | .run(); 26 | 27 | app.get(evnts.Events).start(); 28 | } 29 | -------------------------------------------------------------------------------- /www/dart/web/vendor/ace/mode-text.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/dart/web/vendor/ace/mode-text.js -------------------------------------------------------------------------------- /www/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /www/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /www/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /www/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /www/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /www/fonts/fredoka-one.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/fonts/fredoka-one.eot -------------------------------------------------------------------------------- /www/fonts/fredoka-one.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/fonts/fredoka-one.woff -------------------------------------------------------------------------------- /www/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /www/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /www/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /www/fonts/ubuntu-bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/fonts/ubuntu-bold.eot -------------------------------------------------------------------------------- /www/fonts/ubuntu-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/fonts/ubuntu-bold.woff -------------------------------------------------------------------------------- /www/fonts/ubuntu.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/fonts/ubuntu.eot -------------------------------------------------------------------------------- /www/fonts/ubuntu.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/fonts/ubuntu.woff -------------------------------------------------------------------------------- /www/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/img/favicon.ico -------------------------------------------------------------------------------- /www/img/header_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/img/header_logo.png -------------------------------------------------------------------------------- /www/img/header_logo.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/img/header_logo.xcf -------------------------------------------------------------------------------- /www/img/logo100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/img/logo100.png -------------------------------------------------------------------------------- /www/img/logo14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/img/logo14.png -------------------------------------------------------------------------------- /www/img/logo140.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/img/logo140.png -------------------------------------------------------------------------------- /www/img/logo16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/img/logo16.png -------------------------------------------------------------------------------- /www/img/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/img/logo192.png -------------------------------------------------------------------------------- /www/img/logo256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/img/logo256.png -------------------------------------------------------------------------------- /www/img/logo32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/img/logo32.png -------------------------------------------------------------------------------- /www/img/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/img/logo512.png -------------------------------------------------------------------------------- /www/img/logo64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/img/logo64.png -------------------------------------------------------------------------------- /www/img/logo_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/img/logo_code.png -------------------------------------------------------------------------------- /www/img/logo_full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/img/logo_full.png -------------------------------------------------------------------------------- /www/img/logo_full.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/img/logo_full.xcf -------------------------------------------------------------------------------- /www/img/logo_full2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/img/logo_full2.png -------------------------------------------------------------------------------- /www/img/logo_full2.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/img/logo_full2.xcf -------------------------------------------------------------------------------- /www/img/logo_full3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/img/logo_full3.png -------------------------------------------------------------------------------- /www/img/logo_full3.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/img/logo_full3.xcf -------------------------------------------------------------------------------- /www/img/logo_stripe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/img/logo_stripe.png -------------------------------------------------------------------------------- /www/init/demo.js: -------------------------------------------------------------------------------- 1 | /* jshint -W098:true */ 2 | define([ 3 | 'jquery', 4 | 'underscore', 5 | 'backbone', 6 | 'demo/ajax' 7 | ], function($, _, Backbone, demoAjax) { 8 | 'use strict'; 9 | var initialize = function() { 10 | window.demo = true; 11 | Backbone.ajax = demoAjax; 12 | }; 13 | 14 | return initialize; 15 | }); 16 | -------------------------------------------------------------------------------- /www/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/logo.png -------------------------------------------------------------------------------- /www/models/admin.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var AdminModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'username': null, 11 | 'yubikey_id': null, 12 | 'super_user': null, 13 | 'auth_api': null, 14 | 'token': null, 15 | 'secret': null, 16 | 'otp_auth': null, 17 | 'otp_secret': null, 18 | 'audit': null 19 | }, 20 | url: function() { 21 | var url = '/admin'; 22 | 23 | if (this.get('id')) { 24 | url += '/' + this.get('id'); 25 | } 26 | 27 | return url; 28 | }, 29 | destroyOtpSecret: function(options) { 30 | var otpSecret = this.get('otp_secret'); 31 | this.save({ 32 | otp_secret: true 33 | }, options); 34 | this.set({'otp_secret': otpSecret}); 35 | } 36 | }); 37 | 38 | return AdminModel; 39 | }); 40 | -------------------------------------------------------------------------------- /www/models/authSession.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var AuthSessionModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'authenticated': null, 10 | 'username': null, 11 | 'password': null, 12 | 'default': null 13 | }, 14 | url: function() { 15 | return '/auth/session'; 16 | } 17 | }); 18 | 19 | return AuthSessionModel; 20 | }); 21 | -------------------------------------------------------------------------------- /www/models/device.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var DeviceModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'org_id': null, 11 | 'user_id': null, 12 | 'user_name': null, 13 | 'name': null, 14 | 'platform': null, 15 | 'reg_key': null 16 | }, 17 | url: function() { 18 | return '/device/register/' + this.get('org_id') + '/' + 19 | this.get('user_id') + '/' + this.get('id'); 20 | } 21 | }); 22 | 23 | return DeviceModel; 24 | }); 25 | -------------------------------------------------------------------------------- /www/models/event.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var EventModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'type': null, 11 | 'resource_id': null, 12 | 'timestamp': null 13 | } 14 | }); 15 | 16 | return EventModel; 17 | }); 18 | -------------------------------------------------------------------------------- /www/models/host.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var HostModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'name': null, 10 | 'hostname': null, 11 | 'instance_id': null, 12 | 'status': null, 13 | 'uptime': null, 14 | 'version': null, 15 | 'user_count': null, 16 | 'users_online': null, 17 | 'public_address': null, 18 | 'public_addr': null, 19 | 'public_address6': null, 20 | 'public_addr6': null, 21 | 'routed_subnet6': null, 22 | 'routed_subnet6_wg': null, 23 | 'proxy_ndp': null, 24 | 'local_address': null, 25 | 'local_addr': null, 26 | 'local_address6': null, 27 | 'local_addr6': null, 28 | 'link_address': null, 29 | 'availability_group': null 30 | }, 31 | url: function() { 32 | var url = '/host'; 33 | 34 | if (this.get('id')) { 35 | url += '/' + this.get('id'); 36 | } 37 | 38 | return url; 39 | } 40 | }); 41 | 42 | return HostModel; 43 | }); 44 | -------------------------------------------------------------------------------- /www/models/hostUsage.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var HostUsageModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'cpu': null, 10 | 'mem': null 11 | }, 12 | url: function() { 13 | return '/host/' + this.get('id') + '/usage/' + this.getPeriod(); 14 | }, 15 | getPeriod: function() { 16 | return this.period; 17 | }, 18 | setPeriod: function(period) { 19 | this.period = period; 20 | }, 21 | getGraphData: function(type) { 22 | var i; 23 | var points = []; 24 | var data = this.get(type); 25 | if (!data) { 26 | return null; 27 | } 28 | for (i = 0; i < data.length; i++) { 29 | points.push({x: data[i][0], y: data[i][1]}); 30 | } 31 | return points; 32 | } 33 | }); 34 | 35 | return HostUsageModel; 36 | }); 37 | -------------------------------------------------------------------------------- /www/models/key.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var KeyModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'key_url': null, 11 | 'key_zip_url': null, 12 | 'key_onc_url': null, 13 | 'view_url': null, 14 | 'uri_url': null 15 | }, 16 | url: function() { 17 | return '/key/' + this.get('organization') + '/' + this.get('user'); 18 | } 19 | }); 20 | 21 | return KeyModel; 22 | }); 23 | -------------------------------------------------------------------------------- /www/models/link.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var LinkModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'name': null, 11 | 'type': null, 12 | 'ipv6': null, 13 | 'host_check': null, 14 | 'action': null, 15 | 'status': null, 16 | 'locations': null, 17 | 'timeout': null, 18 | 'preferred_ike': null, 19 | 'preferred_esp': null, 20 | 'force_preferred': null 21 | }, 22 | url: function() { 23 | var url = '/link'; 24 | 25 | if (this.get('id')) { 26 | url += '/' + this.get('id'); 27 | } 28 | 29 | return url; 30 | } 31 | }); 32 | 33 | return LinkModel; 34 | }); 35 | -------------------------------------------------------------------------------- /www/models/linkHost.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var LinkHostModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'link_id': null, 11 | 'location_id': null, 12 | 'name': null, 13 | 'timeout': null, 14 | 'priority': null, 15 | 'backoff': null, 16 | 'static': null, 17 | 'public_address': null, 18 | 'local_address': null, 19 | 'address6': null, 20 | 'version': null 21 | }, 22 | url: function() { 23 | var url = '/link/' + this.get('link_id') + '/location/' + 24 | this.get('location_id') + '/host'; 25 | 26 | if (this.get('id')) { 27 | url += '/' + this.get('id'); 28 | } 29 | 30 | return url; 31 | } 32 | }); 33 | 34 | return LinkHostModel; 35 | }); 36 | -------------------------------------------------------------------------------- /www/models/linkHostConf.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var LinkHostConfModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'name': null, 11 | 'hostname': null, 12 | 'conf': null, 13 | 'ubnt_conf': null 14 | }, 15 | url: function() { 16 | return '/link/' + this.get('link_id') + '/location/' + 17 | this.get('location_id') + '/host/' + this.get('id') + '/conf'; 18 | } 19 | }); 20 | 21 | return LinkHostConfModel; 22 | }); 23 | -------------------------------------------------------------------------------- /www/models/linkHostUri.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var LinkHostUriModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'name': null, 11 | 'hostname': null, 12 | 'uri': null 13 | }, 14 | url: function() { 15 | return '/link/' + this.get('link_id') + '/location/' + 16 | this.get('location_id') + '/host/' + this.get('id') + '/uri'; 17 | } 18 | }); 19 | 20 | return LinkHostUriModel; 21 | }); 22 | -------------------------------------------------------------------------------- /www/models/linkLocation.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var LinkLocationModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'link_id': null, 11 | 'link_type': null, 12 | 'type': null, 13 | 'ipv6': null, 14 | 'name': null, 15 | 'status': null, 16 | 'location': null, 17 | 'hosts': null, 18 | 'routes': null, 19 | 'peers': null 20 | }, 21 | url: function() { 22 | var url = '/link/' + this.get('link_id') + '/location'; 23 | 24 | if (this.get('id')) { 25 | url += '/' + this.get('id'); 26 | } 27 | 28 | return url; 29 | } 30 | }); 31 | 32 | return LinkLocationModel; 33 | }); 34 | -------------------------------------------------------------------------------- /www/models/linkPeer.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var LinkPeerModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'link_id': null, 11 | 'location_id': null, 12 | 'name': null, 13 | 'status': null 14 | }, 15 | url: function() { 16 | var url = '/link/' + this.get('link_id') + '/location/' + 17 | this.get('location_id') + '/peer'; 18 | 19 | if (this.get('id')) { 20 | url += '/' + this.get('id'); 21 | } 22 | 23 | return url; 24 | } 25 | }); 26 | 27 | return LinkPeerModel; 28 | }); 29 | -------------------------------------------------------------------------------- /www/models/linkRoute.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var LinkRouteModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'link_id': null, 11 | 'location_id': null 12 | }, 13 | url: function() { 14 | var url = '/link/' + this.get('link_id') + '/location/' + 15 | this.get('location_id') + '/route'; 16 | 17 | if (this.get('id')) { 18 | url += '/' + this.get('id'); 19 | } 20 | 21 | return url; 22 | } 23 | }); 24 | 25 | return LinkRouteModel; 26 | }); 27 | -------------------------------------------------------------------------------- /www/models/linkRouteExclude.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var LinkRouteModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'link_id': null, 11 | 'location_id': null 12 | }, 13 | url: function() { 14 | var url = '/link/' + this.get('link_id') + '/location/' + 15 | this.get('location_id') + '/route_exclude'; 16 | 17 | if (this.get('id')) { 18 | url += '/' + this.get('id'); 19 | } 20 | 21 | return url; 22 | } 23 | }); 24 | 25 | return LinkRouteModel; 26 | }); 27 | -------------------------------------------------------------------------------- /www/models/linkTransit.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var LinkTransitModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'link_id': null, 11 | 'location_id': null, 12 | 'transit_id': null, 13 | 'name': null 14 | }, 15 | url: function() { 16 | var url = '/link/' + this.get('link_id') + '/location/' + 17 | this.get('location_id') + '/transit'; 18 | 19 | if (this.get('id')) { 20 | url += '/' + this.get('id'); 21 | } 22 | 23 | return url; 24 | } 25 | }); 26 | 27 | return LinkTransitModel; 28 | }); 29 | -------------------------------------------------------------------------------- /www/models/log.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var LogModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'timestamp': null, 11 | 'message': null 12 | }, 13 | url: function() { 14 | var url = '/log'; 15 | 16 | if (this.get('id')) { 17 | url += '/' + this.get('id'); 18 | } 19 | 20 | return url; 21 | } 22 | }); 23 | 24 | return LogModel; 25 | }); 26 | -------------------------------------------------------------------------------- /www/models/logs.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var LogsModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'output': null 10 | }, 11 | url: function() { 12 | return '/logs'; 13 | } 14 | }); 15 | 16 | return LogsModel; 17 | }); 18 | -------------------------------------------------------------------------------- /www/models/org.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var OrgModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'name': null, 11 | 'user_count': null 12 | }, 13 | url: function() { 14 | var url = '/organization'; 15 | 16 | if (this.get('id')) { 17 | url += '/' + this.get('id'); 18 | } 19 | 20 | return url; 21 | } 22 | }); 23 | 24 | return OrgModel; 25 | }); 26 | -------------------------------------------------------------------------------- /www/models/serverBandwidth.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var ServerBandwidthModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'received': null, 10 | 'sent': null 11 | }, 12 | url: function() { 13 | return '/server/' + this.get('id') + '/bandwidth/' + this.getPeriod(); 14 | }, 15 | getPeriod: function() { 16 | return this.period; 17 | }, 18 | setPeriod: function(period) { 19 | this.period = period; 20 | }, 21 | getGraphData: function(type) { 22 | var i; 23 | var points = []; 24 | var data = this.get(type); 25 | if (!data) { 26 | return null; 27 | } 28 | var max = 0; 29 | for (i = 0; i < data.length; i++) { 30 | max = Math.max(data[i][1], max); 31 | points.push({x: data[i][0], y: data[i][1]}); 32 | } 33 | return { 34 | 'max': max, 35 | 'points': points 36 | }; 37 | } 38 | }); 39 | 40 | return ServerBandwidthModel; 41 | }); 42 | -------------------------------------------------------------------------------- /www/models/serverHost.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var ServerHostModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'server': null, 11 | 'name': null, 12 | 'address': null 13 | }, 14 | url: function() { 15 | var url = '/server/' + this.get('server') + '/host'; 16 | 17 | if (this.get('id')) { 18 | url += '/' + this.get('id'); 19 | } 20 | 21 | return url; 22 | } 23 | }); 24 | 25 | return ServerHostModel; 26 | }); 27 | -------------------------------------------------------------------------------- /www/models/serverLink.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var ServerLinkModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'server': null, 11 | 'name': null, 12 | 'use_local_address': null 13 | }, 14 | url: function() { 15 | var url = '/server/' + this.get('server') + '/link'; 16 | 17 | if (this.get('id')) { 18 | url += '/' + this.get('id'); 19 | } 20 | 21 | return url; 22 | } 23 | }); 24 | 25 | return ServerLinkModel; 26 | }); 27 | -------------------------------------------------------------------------------- /www/models/serverOrg.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var ServerOrgModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'server': null, 11 | 'name': null 12 | }, 13 | url: function() { 14 | var url = '/server/' + this.get('server') + '/organization'; 15 | 16 | if (this.get('id')) { 17 | url += '/' + this.get('id'); 18 | } 19 | 20 | return url; 21 | } 22 | }); 23 | 24 | return ServerOrgModel; 25 | }); 26 | -------------------------------------------------------------------------------- /www/models/serverOutput.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var ServerOutputModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'output': null 11 | }, 12 | url: function() { 13 | return '/server/' + this.get('id') + '/output'; 14 | } 15 | }); 16 | 17 | return ServerOutputModel; 18 | }); 19 | -------------------------------------------------------------------------------- /www/models/serverOutputLink.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var ServerOutputLinkModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'output': null 11 | }, 12 | url: function() { 13 | return '/server/' + this.get('id') + '/link_output'; 14 | } 15 | }); 16 | 17 | return ServerOutputLinkModel; 18 | }); 19 | -------------------------------------------------------------------------------- /www/models/serverRoute.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var ServerRouteModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'server': null, 11 | 'network': null, 12 | 'comment': null, 13 | 'metric': null, 14 | 'virtual_network': null, 15 | 'wg_network': null, 16 | 'network_link': null, 17 | 'server_link': null, 18 | 'nat': null, 19 | 'nat_interface': null, 20 | 'nat_netmap': null, 21 | 'net_gateway': null, 22 | 'advertise': null, 23 | 'vpc_region': null, 24 | 'vpc_id': null 25 | }, 26 | url: function() { 27 | var url = '/server/' + this.get('server') + '/route'; 28 | 29 | if (this.get('id')) { 30 | url += '/' + this.get('id'); 31 | } 32 | 33 | return url; 34 | } 35 | }); 36 | 37 | return ServerRouteModel; 38 | }); 39 | -------------------------------------------------------------------------------- /www/models/state.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var StateModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'super_user': null, 10 | 'csrf_token': null, 11 | 'theme': null, 12 | 'active': null, 13 | 'plan': null, 14 | 'version': null, 15 | 'sso': null 16 | }, 17 | url: function() { 18 | return '/state'; 19 | } 20 | }); 21 | 22 | return StateModel; 23 | }); 24 | -------------------------------------------------------------------------------- /www/models/status.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var StatusModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'org_count': null, 10 | 'users_online': null, 11 | 'user_count': null, 12 | 'servers_online': null, 13 | 'server_count': null, 14 | 'server_version': null, 15 | 'public_ip': null, 16 | 'local_networks': null, 17 | 'notification': null 18 | }, 19 | url: function() { 20 | return '/status'; 21 | } 22 | }); 23 | 24 | return StatusModel; 25 | }); 26 | -------------------------------------------------------------------------------- /www/models/userAudit.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var UserAuditModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'user_id': null, 11 | 'org_id': null, 12 | 'timestamp': null, 13 | 'type': null, 14 | 'remote_addr': null, 15 | 'message': null 16 | }, 17 | url: function() { 18 | return null; 19 | } 20 | }); 21 | 22 | return UserAuditModel; 23 | }); 24 | -------------------------------------------------------------------------------- /www/models/userBulk.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var UserBulkModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'organization': null, 10 | 'users': null 11 | }, 12 | initialize: function() { 13 | this.set({'users': []}); 14 | }, 15 | url: function() { 16 | return '/user/' + this.get('organization') + '/multi'; 17 | }, 18 | toJSON: function() { 19 | return this.get('users'); 20 | }, 21 | addUser: function(name, email) { 22 | var users = this.get('users'); 23 | users.push({ 24 | 'name': name, 25 | 'email': email || null, 26 | }); 27 | } 28 | }); 29 | 30 | return UserBulkModel; 31 | }); 32 | -------------------------------------------------------------------------------- /www/models/userDevice.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var UserDeviceModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'user_id': null, 11 | 'org_id': null, 12 | 'name': null, 13 | 'registered': null, 14 | 'timestamp': null 15 | }, 16 | url: function() { 17 | return '/user/' + this.get('org_id') + '/' + this.get('user_id') + 18 | '/device/' + this.get('id'); 19 | } 20 | }); 21 | 22 | return UserDeviceModel; 23 | }); 24 | -------------------------------------------------------------------------------- /www/models/userServer.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var UserServerModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'id': null, 10 | 'name': null, 11 | 'status': null, 12 | 'server_id': null, 13 | 'device_id': null, 14 | 'device_name': null, 15 | 'platform': null, 16 | 'real_address': null, 17 | 'virt_address': null, 18 | 'connected_since': null 19 | } 20 | }); 21 | 22 | return UserServerModel; 23 | }); 24 | -------------------------------------------------------------------------------- /www/models/zones.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var ZonesModel = Backbone.Model.extend({ 8 | defaults: { 9 | 'us-east-1': [], 10 | 'us-east-2': [], 11 | 'us-west-1': [], 12 | 'us-west-2': [], 13 | 'us-gov-east-1': [], 14 | 'us-gov-west-1': [], 15 | 'eu-north-1': [], 16 | 'eu-west-1': [], 17 | 'eu-west-2': [], 18 | 'eu-west-3': [], 19 | 'eu-central-1': [], 20 | 'ca-central-1': [], 21 | 'cn-north-1': [], 22 | 'cn-northwest-1': [], 23 | 'ap-northeast-1': [], 24 | 'ap-northeast-2': [], 25 | 'ap-southeast-1': [], 26 | 'ap-southeast-2': [], 27 | 'ap-east-1': [], 28 | 'ap-south-1': [], 29 | 'sa-east-1': [] 30 | }, 31 | url: '/settings/zones' 32 | }); 33 | 34 | return ZonesModel; 35 | }); 36 | -------------------------------------------------------------------------------- /www/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pritunl.js", 3 | "dependencies": { 4 | "grunt": "0.4.5", 5 | "grunt-contrib-clean": "0.5.0", 6 | "grunt-contrib-copy": "0.4.1", 7 | "grunt-contrib-jshint": "0.6.0", 8 | "grunt-contrib-requirejs": "0.4.1" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /www/root/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: / 3 | -------------------------------------------------------------------------------- /www/templates/admins.html: -------------------------------------------------------------------------------- 1 | <div class="admins-list"> 2 | <div class="admins-list-header"> 3 | <h1 class="admins-title title">Administrators</h1> 4 | <div class="admins-list-buttons"> 5 | <button type="button" class="header-button admins-del-selected btn btn-danger" disabled>Delete Selected</button> 6 | <button type="button" class="header-button admins-add-admin btn btn-primary">Add Administrator</button> 7 | </div> 8 | </div> 9 | <div class="alerts-container"></div> 10 | <div class="admins-container"> 11 | <div class="admins-list-header"> 12 | <div class="label label-warning toggle-hidden no-select">Administrators</div> 13 | </div> 14 | </div> 15 | </div> 16 | -------------------------------------------------------------------------------- /www/templates/adminsList.html: -------------------------------------------------------------------------------- 1 | <div class="loading"> 2 | Loading... 3 | </div> 4 | -------------------------------------------------------------------------------- /www/templates/adminsListItem.html: -------------------------------------------------------------------------------- 1 | <div class="admin layout-horizontal"> 2 | <div class="selector no-select"> 3 | <span class="selector-inner glyphicon glyphicon-ok"></span> 4 | </div> 5 | <div class="name-container layout-flex"> 6 | <span class="name-icon glyphicon glyphicon-user"></span> 7 | <a class="admin-username title no-select" data-toggle="tooltip" title="Click to modify this administrator"><%- username %></a> 8 | <span class="admin-id title">(<%- id %>)</span> 9 | </div> 10 | <div class="right-container"> 11 | <a class="get-otp-auth glyphicon glyphicon-qrcode no-select <%- otp_auth ? '' : 'no-otp-auth' %>" data-toggle="tooltip" title="Get two-step authentication key"></a> 12 | <a class="audit-admin glyphicon glyphicon-list-alt no-select <%- audit ? '' : 'no-audit-admin' %>" data-toggle="tooltip" title="Administrator audit"></a> 13 | <a class="disable-admin glyphicon glyphicon glyphicon-ban-circle no-select" data-toggle="tooltip" title="Disable and logout administrator"></a> 14 | <a class="enable-admin glyphicon glyphicon glyphicon-ok-circle no-select" data-toggle="tooltip" title="Enable administrator"></a> 15 | </div> 16 | </div> 17 | -------------------------------------------------------------------------------- /www/templates/alert.html: -------------------------------------------------------------------------------- 1 | <div class="alert alert-<%- type %> <%- (dismissable) ? 'alert-dismissable' : '' %>"> 2 | <% if (dismissable) { %> 3 | <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> 4 | <% } %> 5 | <span> 6 | <%= message %> 7 | </span> 8 | </div> 9 | -------------------------------------------------------------------------------- /www/templates/dashboard.html: -------------------------------------------------------------------------------- 1 | <div class="alerts-container"></div> 2 | -------------------------------------------------------------------------------- /www/templates/dashboardLog.html: -------------------------------------------------------------------------------- 1 | <h2 class="log-title title"> 2 | Recent log entries 3 | </h2> 4 | <div class="log-entry-list"></div> 5 | -------------------------------------------------------------------------------- /www/templates/dashboardLogItem.html: -------------------------------------------------------------------------------- 1 | <span class="log-icon glyphicon glyphicon-record"></span> 2 | <span class="log-msg"> 3 | <%- message %> 4 | </span> 5 | <span class="log-time"> 6 | <%- window.formatTime(timestamp) %> 7 | </span> 8 | -------------------------------------------------------------------------------- /www/templates/devicesList.html: -------------------------------------------------------------------------------- 1 | <div class="devices-list"> 2 | <div class="devices-list-header"> 3 | <div class="label label-success toggle-hidden no-select">Devices</div><h2 class="devices-list-title title">Devices Pending Registration</h2> 4 | </div> 5 | <div class="devices-list-container"> 6 | <div class="no-devices"> 7 | There are no pending devices. 8 | </div> 9 | </div> 10 | </div> 11 | -------------------------------------------------------------------------------- /www/templates/devicesListItem.html: -------------------------------------------------------------------------------- 1 | <div class="devices-device"> 2 | <div class="name-container"> 3 | <span class="name-icon glyphicon glyphicon-tasks"></span> 4 | <span class="device-name title"><%- user_name + ' - ' + name %></span> 5 | </div> 6 | <div class="button-container"> 7 | <button type="button" class="devices-device-reg btn btn-primary btn-xs">Register Device</button> 8 | <button type="button" class="devices-device-del btn btn-danger btn-xs">Remove Device</button> 9 | </div> 10 | </div> 11 | -------------------------------------------------------------------------------- /www/templates/hostUsage.html: -------------------------------------------------------------------------------- 1 | <div class="host-graph-cpu"></div> 2 | <div class="host-graph-mem"></div> 3 | -------------------------------------------------------------------------------- /www/templates/hostsList.html: -------------------------------------------------------------------------------- 1 | <div class="hosts-list-header"> 2 | <h1 class="hosts-list-title title">Hosts</h1> 3 | <div class="hosts-list-buttons"> 4 | </div> 5 | </div> 6 | <div class="alerts-container"></div> 7 | <div class="hosts-list-container"> 8 | </div> 9 | <button type="button" class="prev-page btn btn-primary btn-sm">Previous Page</button> 10 | <button type="button" class="next-page btn btn-primary btn-sm">Next Page</button> 11 | <div class="pages no-select"> 12 | <div class="links"> 13 | <a class="link first">First</a> 14 | <a class="link last">Last</a> 15 | </div> 16 | </div> 17 | -------------------------------------------------------------------------------- /www/templates/linkLocationsList.html: -------------------------------------------------------------------------------- 1 | <div class="no-locations"> 2 | There are no locations on this link. 3 | </div> 4 | -------------------------------------------------------------------------------- /www/templates/linksList.html: -------------------------------------------------------------------------------- 1 | <div class="links-upgrade"> 2 | Upgrade to Enterprise+ for site-to-site links with IPsec 3 | </div> 4 | <div class="links-list"> 5 | <div class="links-list-header"> 6 | <h1 class="links-list-title title">Links</h1> 7 | <div class="links-list-buttons"> 8 | <button type="button" class="header-button links-add-link btn btn-primary">Add Link</button> 9 | <button type="button" class="header-button links-add-location btn btn-primary">Add Location</button> 10 | </div> 11 | </div> 12 | <div class="alerts-container"></div> 13 | <div class="links-list-container"> 14 | <div class="no-links"> 15 | There are no links on this system. 16 | </div> 17 | </div> 18 | <button type="button" class="prev-page btn btn-primary btn-sm">Previous Page</button> 19 | <button type="button" class="next-page btn btn-primary btn-sm">Next Page</button> 20 | <div class="pages no-select"> 21 | <div class="page-links"> 22 | <a class="page-link first">First</a> 23 | <a class="page-link last">Last</a> 24 | </div> 25 | </div> 26 | </div> 27 | -------------------------------------------------------------------------------- /www/templates/linksListItem.html: -------------------------------------------------------------------------------- 1 | <div class="link-header"> 2 | <div class="link-label label label-purple toggle-hidden no-select"><%- (type === 'direct' ? 'Direct' : 'Site-To-Site') + ' Link' %></div><h2 class="link-title title"><a class="no-select" data-toggle="tooltip" title="Click to open link settings"></a><span class="link-id title">(<%- id %>)</span></h2> 3 | <button type="button" class="link-del btn btn-danger btn-sm no-select">Delete Link</button> 4 | <button type="button" class="link-stop btn btn-warning btn-sm no-select">Stop Link</button> 5 | <button type="button" class="link-start btn btn-success btn-sm no-select">Start Link</button> 6 | <button type="button" class="link-rekey btn btn-primary btn-sm no-select">Rekey Link</button> 7 | </div> 8 | -------------------------------------------------------------------------------- /www/templates/modal.html: -------------------------------------------------------------------------------- 1 | <div class="modal fade" tabindex="-1" role="dialog" aria-hidden="true"> 2 | <div class="modal-dialog"> 3 | <div class="modal-content"> 4 | <div class="modal-header"> 5 | <button type="button" class="close" aria-hidden="true">×</button> 6 | <h4 class="modal-title title"><%- title %></h4> 7 | <div class="modal-advanced-toggle no-select">Advanced</div> 8 | </div> 9 | <div class="modal-body"></div> 10 | <div class="modal-footer"> 11 | <% if (cancelText !== null) { %> 12 | <button type="button" class="btn btn-default cancel"><%- cancelText %></button> 13 | <% } %> 14 | <% if (okText !== null) { %> 15 | <button type="button" class="btn btn-primary ok"><%- okText %></button> 16 | <% } %> 17 | </div> 18 | </div> 19 | </div> 20 | </div> 21 | -------------------------------------------------------------------------------- /www/templates/modalAddLocPeer.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <div class="form-group peer-id"> 3 | <label>Peer Location</label> 4 | <select class="form-control" data-toggle="tooltip" title="Select location to peer"> 5 | <% _.each(locations, function(location) { %> 6 | <% if (location.id !== location_id) { %> 7 | <option value="<%- location.id %>"><%- location.name %></option> 8 | <% } %> 9 | <% }); %> 10 | </select> 11 | </div> 12 | </div> 13 | -------------------------------------------------------------------------------- /www/templates/modalAddLocRoute.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <div class="form-group network"> 3 | <label>Network</label> 4 | <input type="text" class="form-control" placeholder="Enter network address" data-toggle="tooltip" title="Network address with subnet to route" autofocus> 5 | </div> 6 | </div> 7 | -------------------------------------------------------------------------------- /www/templates/modalAddLocTransit.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <label>Are you sure you want to transit the <b><%- name %></b> peer?</label> 3 | </div> 4 | -------------------------------------------------------------------------------- /www/templates/modalAddLocation.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <div class="form-group name"> 3 | <label>Name</label> 4 | <input type="text" class="form-control" placeholder="Enter name" data-toggle="tooltip" title="Name of location" autofocus> 5 | </div> 6 | <div class="form-group link"> 7 | <label>Link</label> 8 | <select class="form-control"> 9 | <% _.each(links, function(link) { %> 10 | <% if (link.type !== 'direct') { %> 11 | <option value="<%- link.id %>" <%= (lastLink === link.id) ? 'selected' : '' %>><%- link.name %></option> 12 | <% } %> 13 | <% }); %> 14 | </select> 15 | </div> 16 | </div> 17 | -------------------------------------------------------------------------------- /www/templates/modalAddOrg.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <div class="form-group name"> 3 | <label>Name</label> 4 | <input type="text" class="form-control" placeholder="Enter name" data-toggle="tooltip" title="Name of organization" autofocus> 5 | </div> 6 | </div> 7 | -------------------------------------------------------------------------------- /www/templates/modalAddUserBulk.html: -------------------------------------------------------------------------------- 1 | <div class="form-group users"> 2 | <label>Enter list of usernames and optionally an email addresses on each line with a comma separating the username from the email address</label><br> 3 | <textarea class="form-control" rows="12" placeholder="user1,user1@pritunl.com" spellcheck="false" autofocus></textarea> 4 | </div> 5 | <div class="form-group org"> 6 | <label>Select an organization</label> 7 | <select class="form-control"> 8 | <% _.each(orgs, function(org) { %> 9 | <option value="<%- org.id %>" <%= (lastOrg === org.id) ? 'selected' : '' %>><%- org.name %></option> 10 | <% }); %> 11 | </select> 12 | </div> 13 | -------------------------------------------------------------------------------- /www/templates/modalAttachHost.html: -------------------------------------------------------------------------------- 1 | <div class="host form-group"> 2 | <label>Select a host</label> 3 | <select class="form-control"> 4 | <% _.each(hosts, function(host) { %> 5 | <option value="<%- host.id %>"><%- host.name %></option> 6 | <% }); %> 7 | </select> 8 | </div> 9 | <div class="server form-group"> 10 | <label>Select a server</label> 11 | <select class="form-control"> 12 | <% _.each(servers, function(server) { %> 13 | <option value="<%- server.id %>" <%= (lastServer === server.id) ? 'selected' : '' %>><%- server.name %></option> 14 | <% }); %> 15 | </select> 16 | </div> 17 | -------------------------------------------------------------------------------- /www/templates/modalAttachLink.html: -------------------------------------------------------------------------------- 1 | <div class="server form-group"> 2 | <label>Select first server</label> 3 | <select class="form-control"> 4 | <% _.each(servers, function(server) { %> 5 | <option value="<%- server.id %>" <%= server.id === servers[1].id ? 'style="display: none;"' : '' %> <%= (lastServer === server.id) ? 'selected' : '' %>><%- server.name %></option> 6 | <% }); %> 7 | </select> 8 | </div> 9 | <div class="link form-group"> 10 | <label>Select second server</label> 11 | <select class="form-control"> 12 | <% _.each(servers, function(server) { %> 13 | <option value="<%- server.id %>" <%= server.id === servers[0].id ? 'style="display: none;"' : '' %> <%= (server.id === servers[1].id) ? 'selected' : '' %>><%- server.name %></option> 14 | <% }); %> 15 | </select> 16 | </div> 17 | <div class="use-local-toggle toggle-form form-group"> 18 | <label>Use local address</label> 19 | <div class="selector no-select" data-toggle="tooltip" title="Use the hosts local address when linking servers"> 20 | <span class="selector-inner glyphicon glyphicon-ok"></span> 21 | </div> 22 | </div> 23 | -------------------------------------------------------------------------------- /www/templates/modalAttachOrg.html: -------------------------------------------------------------------------------- 1 | <div class="org form-group"> 2 | <label>Select an organization</label> 3 | <select class="form-control"> 4 | <% _.each(orgs, function(org) { %> 5 | <option value="<%- org.id %>"><%- org.name %></option> 6 | <% }); %> 7 | </select> 8 | </div> 9 | <div class="server form-group"> 10 | <label>Select a server</label> 11 | <select class="form-control"> 12 | <% _.each(servers, function(server) { %> 13 | <option value="<%- server.id %>" <%= (lastServer === server.id) ? 'selected' : '' %>><%- server.name %></option> 14 | <% }); %> 15 | </select> 16 | </div> 17 | -------------------------------------------------------------------------------- /www/templates/modalAuditUser.html: -------------------------------------------------------------------------------- 1 | <label class="user-title" style="<%= user.name ? '' : 'display: none' %>"><%- user.name %><%- user.email ? ' (' + user.email + ')' : '' %></label> 2 | <ul class="modal-audit-user" style="<%= events.length ? '' : 'display: none' %>"> 3 | <% _.each(events, function(event) { %> 4 | <li class="audit-event layout-horizontal"> 5 | <span class="event-msg layout-flex"> 6 | <span class="glyphicon glyphicon-record"></span> 7 | <%- event.message %> 8 | </span> 9 | <span class="event-addr" style="<%= event.remote_addr ? '' : 'display: none' %>"> 10 | <span class="glyphicon glyphicon-globe"></span> 11 | <%- event.remote_addr %> 12 | </span> 13 | <span class="event-time"> 14 | <span class="glyphicon glyphicon-time"></span> 15 | <%- window.formatTime(event.timestamp) %> 16 | </span> 17 | </li> 18 | <% }); %> 19 | </ul> 20 | -------------------------------------------------------------------------------- /www/templates/modalDeleteAdmins.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <label>Are you sure you want to logout and delete the following administrators?</label> 3 | <ul class="modal-user-list"> 4 | <% _.each(admins, function(admin) { %> 5 | <li> 6 | <%- admin.username %> 7 | </li> 8 | <% }); %> 9 | </ul> 10 | </div> 11 | -------------------------------------------------------------------------------- /www/templates/modalDeleteHost.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <label>Enter the name of the host to confirm</label> 3 | <input type="text" class="form-control" placeholder="Enter name" data-toggle="tooltip" title="Name of host" autofocus> 4 | </div> 5 | -------------------------------------------------------------------------------- /www/templates/modalDeleteLink.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <label>Enter the name of the link to confirm</label> 3 | <input type="text" class="form-control" placeholder="Enter name" data-toggle="tooltip" title="Name of link" autofocus> 4 | </div> 5 | -------------------------------------------------------------------------------- /www/templates/modalDeleteLocHost.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <label>Are you sure you want to remove the <b><%- name %></b> host?</label> 3 | </div> 4 | -------------------------------------------------------------------------------- /www/templates/modalDeleteLocPeer.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <label>Are you sure you want to remove the <b><%- name %></b> peer?</label> 3 | </div> 4 | -------------------------------------------------------------------------------- /www/templates/modalDeleteLocRoute.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <label>Are you sure you want to remove the <b><%- network %></b> route?</label> 3 | </div> 4 | -------------------------------------------------------------------------------- /www/templates/modalDeleteLocTransit.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <label>Are you sure you want to untransit the <b><%- name %></b> peer?</label> 3 | </div> 4 | -------------------------------------------------------------------------------- /www/templates/modalDeleteLocation.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <label>Enter the name of the location to confirm</label> 3 | <input type="text" class="form-control" placeholder="Enter name" data-toggle="tooltip" title="Name of location" autofocus> 4 | </div> 5 | -------------------------------------------------------------------------------- /www/templates/modalDeleteOrg.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <label>Enter the name of the organization to confirm</label> 3 | <input type="text" class="form-control" placeholder="Enter name" data-toggle="tooltip" title="Name of organization" autofocus> 4 | </div> 5 | -------------------------------------------------------------------------------- /www/templates/modalDeleteServer.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <label>Enter the name of the server to confirm</label> 3 | <input type="text" class="form-control" placeholder="Enter name" data-toggle="tooltip" title="Name of server" autofocus> 4 | </div> 5 | -------------------------------------------------------------------------------- /www/templates/modalDeleteUserDevice.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <label>Are you sure you want to remove the <b><%- name %></b> device?</label> 3 | </div> 4 | -------------------------------------------------------------------------------- /www/templates/modalDeleteUsers.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <label>Are you sure you want to disconnect and delete the following users?</label> 3 | <ul class="modal-user-list"> 4 | <% _.each(users, function(user) { %> 5 | <li> 6 | <%- user.name %> 7 | </li> 8 | <% }); %> 9 | </ul> 10 | </div> 11 | -------------------------------------------------------------------------------- /www/templates/modalDetachHost.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <label>Are you sure you want to detach the <b><%- name %></b> host?</label> 3 | </div> 4 | -------------------------------------------------------------------------------- /www/templates/modalDetachLink.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <label>Are you sure you want to detach the <b><%- name %></b> link?</label> 3 | </div> 4 | -------------------------------------------------------------------------------- /www/templates/modalDetachOrg.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <label>Are you sure you want to detach the <b><%- name %></b> organization?</label> 3 | </div> 4 | -------------------------------------------------------------------------------- /www/templates/modalDeviceRegister.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <div class="form-group reg-key"> 3 | <label>Registration Key</label> 4 | <input type="text" class="form-control" placeholder="Enter registration key" data-toggle="tooltip" title="Device registration key, provided by user" autofocus> 5 | </div> 6 | </div> 7 | -------------------------------------------------------------------------------- /www/templates/modalEmailUsers.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <label>Are you sure you want to email a key link to the following users?</label> 3 | <ul class="modal-user-list"> 4 | <% _.each(users, function(user) { %> 5 | <li class="user-<%- user.id %>"> 6 | <%- user.name %><%- user.email ? ' (' + user.email + ')' : '' %> 7 | </li> 8 | <% }); %> 9 | </ul> 10 | </div> 11 | -------------------------------------------------------------------------------- /www/templates/modalLocHostConf.html: -------------------------------------------------------------------------------- 1 | <div class="conf-link form-group"> 2 | <label>Host Static Configuration</label> 3 | <textarea class="form-control" rows="16" spellcheck="false" readonly></textarea> 4 | </div> 5 | -------------------------------------------------------------------------------- /www/templates/modalLocHostUri.html: -------------------------------------------------------------------------------- 1 | <div class="uri-link form-group"> 2 | <label>Host URI Link</label> 3 | <input type="text" class="form-control" readonly> 4 | </div> 5 | -------------------------------------------------------------------------------- /www/templates/modalModifyLocation.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <div class="form-group name"> 3 | <label>Name</label> 4 | <input type="text" class="form-control" placeholder="Enter name" data-toggle="tooltip" title="Name of location" autofocus value="<%- name %>"> 5 | </div> 6 | </div> 7 | -------------------------------------------------------------------------------- /www/templates/modalNotification.html: -------------------------------------------------------------------------------- 1 | <div class="notification"> 2 | <%- notification %> 3 | </div> 4 | -------------------------------------------------------------------------------- /www/templates/modalOtpAuth.html: -------------------------------------------------------------------------------- 1 | <div class="otp-auth-key form-group"> 2 | <label>Two-step authentication key</label> 3 | <input type="text" class="form-control" readonly> 4 | <div class="qrcode"></div> 5 | <button type="button" class="generate-new-key btn btn-danger">Generate New Key</button> 6 | </div> 7 | -------------------------------------------------------------------------------- /www/templates/modalRekeyLink.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <label>Are you sure you want to regenerate the secret key for <b><%- name %></b> link?</label> 3 | </div> 4 | -------------------------------------------------------------------------------- /www/templates/modalRemoveRoute.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <label>Are you sure you want to remove the <b><%- network %></b> route?</label> 3 | </div> 4 | -------------------------------------------------------------------------------- /www/templates/modalRenameOrg.html: -------------------------------------------------------------------------------- 1 | <div class="form-group"> 2 | <div class="form-group name"> 3 | <label>Name</label> 4 | <input type="text" class="form-control" placeholder="Enter name" data-toggle="tooltip" title="Name of organization" value="<%- name %>" autofocus> 5 | </div> 6 | </div> 7 | -------------------------------------------------------------------------------- /www/templates/orgsListItem.html: -------------------------------------------------------------------------------- 1 | <div class="users-list-header"> 2 | <div class="label label-success toggle-hidden no-select">Organization</div><h2 class="users-list-title title"><a class="org-title no-select" data-toggle="tooltip" title="Click to modify this organization"><%- name %></a><span class="org-id title"> (<%- id %>)</span></h2> 3 | <button type="button" class="org-del btn btn-danger btn-sm">Delete Organization</button> 4 | <button type="button" class="org-sort btn btn-primary btn-sm">Sort by <%- sort_active ? 'Name' : 'Last Active' %></button> 5 | <input type="text" class="org-search form-control" placeholder="Search for user" autocomplete="off"> 6 | <div class="user-count label label-default no-select"> 7 | <%- user_count %> users 8 | </div> 9 | </div> 10 | -------------------------------------------------------------------------------- /www/templates/serverBandwidth.html: -------------------------------------------------------------------------------- 1 | <div class="server-graph-recv"></div> 2 | <div class="server-graph-sent"></div> 3 | -------------------------------------------------------------------------------- /www/templates/serverHostsList.html: -------------------------------------------------------------------------------- 1 | <div class="no-hosts"> 2 | There are no hosts attached to this server. 3 | </div> 4 | -------------------------------------------------------------------------------- /www/templates/serverHostsListItem.html: -------------------------------------------------------------------------------- 1 | <div class="name-container"> 2 | <span class="name-icon glyphicon glyphicon-dashboard"></span> 3 | <span class="host-name title"><%- name %></span> 4 | <span class="host-public-address title"><%- address ? '(' + address + ')' : ''%></span> 5 | <span class="host-id title">(<%- id %>)</span> 6 | </div> 7 | <div class="button-container"> 8 | <div class="host-online label label-success no-select" <%= status === 'online' ? '' : 'style="display: none;"' %>>Online</div> 9 | <div class="host-offline label label-danger no-select" <%= status === 'offline' ? '' : 'style="display: none;"' %>>Offline</div> 10 | <button type="button" class="server-detach-host btn btn-danger btn-xs">Detach Host</button> 11 | </div> 12 | -------------------------------------------------------------------------------- /www/templates/serverLinksList.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/templates/serverLinksList.html -------------------------------------------------------------------------------- /www/templates/serverLinksListItem.html: -------------------------------------------------------------------------------- 1 | <div class="name-container"> 2 | <span class="name-icon glyphicon glyphicon-transfer"></span> 3 | <span class="link-name title"><%- name %></span> 4 | <span class="link-id title">(<%- id %>)</span> 5 | </div> 6 | <div class="button-container"> 7 | <div class="link-use-local label label-default no-select" <%= use_local_address ? '' : 'style="display: none;"' %>>LAN</div> 8 | <div class="link-online label label-success no-select" <%= status === 'online' ? '' : 'style="display: none;"' %>>Online</div> 9 | <div class="link-offline label label-danger no-select" <%= status === 'offline' ? '' : 'style="display: none;"' %>>Offline</div> 10 | <button type="button" class="server-detach-link btn btn-danger btn-xs">Unlink Server</button> 11 | </div> 12 | -------------------------------------------------------------------------------- /www/templates/serverOrgsList.html: -------------------------------------------------------------------------------- 1 | <div class="no-orgs"> 2 | There are no organizations attached to this server. 3 | </div> 4 | -------------------------------------------------------------------------------- /www/templates/serverOrgsListItem.html: -------------------------------------------------------------------------------- 1 | <div class="name-container"> 2 | <span class="name-icon glyphicon glyphicon-tower"></span> 3 | <span class="org-name title"><%- name %></span> 4 | <span class="org-id title">(<%- id %>)</span> 5 | </div> 6 | <div class="button-container"> 7 | <button type="button" class="server-detach-org btn btn-danger btn-xs">Detach Organization</button> 8 | </div> 9 | -------------------------------------------------------------------------------- /www/templates/serverRoutesList.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/templates/serverRoutesList.html -------------------------------------------------------------------------------- /www/templates/userDevicesList.html: -------------------------------------------------------------------------------- 1 | <div class="user-devices"> 2 | <div class="no-devices title"> 3 | No devices available 4 | </div> 5 | </div> 6 | -------------------------------------------------------------------------------- /www/templates/userDevicesListItem.html: -------------------------------------------------------------------------------- 1 | <div class="layout-horizontal"> 2 | <div class="info-container layout-flex"> 3 | <div class="server-name-device"> 4 | <div class="user-device-label user-device-unregisted-label label label-danger toggle-hidden no-select">Unregistered</div> 5 | <span class="server-item device-name" data-toggle="tooltip" title="Device name"> 6 | <span class="name-icon glyphicon glyphicon-tasks"></span> 7 | <span class="title"></span> 8 | </span> 9 | </div> 10 | </div> 11 | <div class="client-container"> 12 | <span class="server-item device-time" data-toggle="tooltip" title="Last connected"> 13 | <span class="name-icon glyphicon glyphicon-time"></span> 14 | <span class="title"></span> 15 | </span> 16 | </div> 17 | <div class="button-container"> 18 | <button type="button" class="user-device-reg btn btn-primary btn-xs">Register Device</button> 19 | <button type="button" class="user-device-del btn btn-danger btn-xs">Remove Device</button> 20 | </div> 21 | </div> 22 | -------------------------------------------------------------------------------- /www/templates/userServersList.html: -------------------------------------------------------------------------------- 1 | <div class="no-servers title"> 2 | No servers available 3 | </div> 4 | -------------------------------------------------------------------------------- /www/templates/usersList.html: -------------------------------------------------------------------------------- 1 | <div class="no-users"> 2 | There are no users in this organization 3 | </div> 4 | <div class="no-users-search"> 5 | No users found 6 | </div> 7 | <div class="loading"> 8 | Loading... 9 | </div> 10 | <button type="button" class="prev-page btn btn-primary btn-sm">Previous Page</button> 11 | <button type="button" class="next-page btn btn-primary btn-sm">Next Page</button> 12 | <div class="pages no-select"> 13 | <div class="links"> 14 | <a class="link first">First</a> 15 | <a class="link last">Last</a> 16 | </div> 17 | </div> 18 | <div class="search-time no-select"></div> 19 | <div class="search-more"> 20 | <a class="no-select">show more results</a> 21 | </div> 22 | -------------------------------------------------------------------------------- /www/vendor/ace/mode-text.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/vendor/ace/mode-text.js -------------------------------------------------------------------------------- /www/vendor/dist/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/vendor/dist/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /www/vendor/dist/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/vendor/dist/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /www/vendor/dist/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/vendor/dist/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /www/vendor/dist/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/vendor/dist/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /www/vendor/dist/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/vendor/dist/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /www/vendor/dist/fonts/fredoka-one.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/vendor/dist/fonts/fredoka-one.eot -------------------------------------------------------------------------------- /www/vendor/dist/fonts/fredoka-one.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/vendor/dist/fonts/fredoka-one.woff -------------------------------------------------------------------------------- /www/vendor/dist/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/vendor/dist/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /www/vendor/dist/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/vendor/dist/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /www/vendor/dist/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/vendor/dist/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /www/vendor/dist/fonts/ubuntu-bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/vendor/dist/fonts/ubuntu-bold.eot -------------------------------------------------------------------------------- /www/vendor/dist/fonts/ubuntu-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/vendor/dist/fonts/ubuntu-bold.woff -------------------------------------------------------------------------------- /www/vendor/dist/fonts/ubuntu.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/vendor/dist/fonts/ubuntu.eot -------------------------------------------------------------------------------- /www/vendor/dist/fonts/ubuntu.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pritunl/pritunl/ab6498e5ddee639f010c279f565b354d12a3e745/www/vendor/dist/fonts/ubuntu.woff -------------------------------------------------------------------------------- /www/vendor/dist/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: / 3 | -------------------------------------------------------------------------------- /www/views/dashboard.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'views/dashboardStatus', 6 | 'views/devicesList', 7 | 'views/dashboardLog', 8 | 'text!templates/dashboard.html' 9 | ], function($, _, Backbone, DashboardStatusView, DevicesListView, 10 | DashboardLogView, dashboardTemplate) { 11 | 'use strict'; 12 | var DashboardView = Backbone.View.extend({ 13 | className: 'dashboard container', 14 | template: _.template(dashboardTemplate), 15 | initialize: function() { 16 | this.dashboardStatusView = new DashboardStatusView(); 17 | this.addView(this.dashboardStatusView); 18 | this.devicesListView = new DevicesListView(); 19 | this.addView(this.devicesListView); 20 | this.dashboardLogView = new DashboardLogView(); 21 | this.addView(this.dashboardLogView); 22 | }, 23 | render: function() { 24 | this.$el.html(this.template()); 25 | this.$el.prepend(this.dashboardStatusView.render().el); 26 | this.$el.append(this.devicesListView.render().el); 27 | this.$el.append(this.dashboardLogView.render().el); 28 | return this; 29 | } 30 | }); 31 | 32 | return DashboardView; 33 | }); 34 | -------------------------------------------------------------------------------- /www/views/dashboardLogItem.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'text!templates/dashboardLogItem.html' 6 | ], function($, _, Backbone, dashboardLogItemTemplate) { 7 | 'use strict'; 8 | var DashboardLogItemView = Backbone.View.extend({ 9 | className: 'log-entry clearfix', 10 | template: _.template(dashboardLogItemTemplate), 11 | render: function() { 12 | this.$el.html(this.template(this.model.toJSON())); 13 | return this; 14 | }, 15 | update: function() { 16 | this.$('.log-msg').text(this.model.get('message')); 17 | this.$('.log-time').text(window.formatTime(this.model.get('timestamp'))); 18 | } 19 | }); 20 | 21 | return DashboardLogItemView; 22 | }); 23 | -------------------------------------------------------------------------------- /www/views/devices.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'views/devicesList' 6 | ], function($, _, Backbone, DevicesListView) { 7 | 'use strict'; 8 | var DevicesView = Backbone.View.extend({ 9 | className: 'devices container', 10 | initialize: function() { 11 | this.devicesList = new DevicesListView(); 12 | this.addView(this.devicesList); 13 | }, 14 | render: function() { 15 | this.$el.append(this.devicesList.render().el); 16 | return this; 17 | } 18 | }); 19 | 20 | return DevicesView; 21 | }); 22 | -------------------------------------------------------------------------------- /www/views/hosts.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'views/hostsList' 6 | ], function($, _, Backbone, HostsListView) { 7 | 'use strict'; 8 | var HostsView = Backbone.View.extend({ 9 | className: 'hosts container', 10 | initialize: function() { 11 | this.hostsList = new HostsListView(); 12 | this.addView(this.hostsList); 13 | }, 14 | render: function() { 15 | this.$el.append(this.hostsList.render().el); 16 | return this; 17 | } 18 | }); 19 | 20 | return HostsView; 21 | }); 22 | -------------------------------------------------------------------------------- /www/views/links.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'views/linksList' 6 | ], function($, _, Backbone, LinksListView) { 7 | 'use strict'; 8 | var LinksView = Backbone.View.extend({ 9 | className: 'links container', 10 | initialize: function() { 11 | this.linksList = new LinksListView(); 12 | this.addView(this.linksList); 13 | }, 14 | render: function() { 15 | this.$el.append(this.linksList.render().el); 16 | return this; 17 | } 18 | }); 19 | 20 | return LinksView; 21 | }); 22 | -------------------------------------------------------------------------------- /www/views/loginBackdrop.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone' 5 | ], function($, _, Backbone) { 6 | 'use strict'; 7 | var LoginBackdropView = Backbone.View.extend({ 8 | className: 'login-backdrop' 9 | }); 10 | 11 | return LoginBackdropView; 12 | }); 13 | -------------------------------------------------------------------------------- /www/views/modalDetachHost.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'views/modal', 6 | 'views/alert', 7 | 'text!templates/modalDetachHost.html' 8 | ], function($, _, Backbone, ModalView, AlertView, modalDetachHostTemplate) { 9 | 'use strict'; 10 | var ModalDetachHostView = ModalView.extend({ 11 | className: 'detach-host-modal', 12 | template: _.template(modalDetachHostTemplate), 13 | title: 'Detach Host', 14 | okText: 'Detach', 15 | body: function() { 16 | return this.template(this.model.toJSON()); 17 | }, 18 | onOk: function() { 19 | this.setLoading('Detaching host...'); 20 | this.model.destroy({ 21 | success: function() { 22 | this.close(true); 23 | }.bind(this), 24 | error: function(model, response) { 25 | this.clearLoading(); 26 | if (response.responseJSON) { 27 | this.setAlert('danger', response.responseJSON.error_msg); 28 | } 29 | else { 30 | this.setAlert('danger', this.errorMsg); 31 | } 32 | }.bind(this) 33 | }); 34 | } 35 | }); 36 | 37 | return ModalDetachHostView; 38 | }); 39 | -------------------------------------------------------------------------------- /www/views/modalLogs.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'views/modal', 6 | 'views/alert', 7 | 'views/logs' 8 | ], function($, _, Backbone, ModalView, AlertView, LogsView) { 9 | 'use strict'; 10 | var ModalLogsView = ModalView.extend({ 11 | className: 'logs-modal', 12 | title: 'System Logs', 13 | okText: 'Close', 14 | cancelText: null, 15 | initialize: function() { 16 | this.logsView = new LogsView(); 17 | this.addView(this.logsView); 18 | ModalLogsView.__super__.initialize.call(this); 19 | }, 20 | postRender: function() { 21 | this.$('.modal-body').append( 22 | this.logsView.render().el); 23 | } 24 | }); 25 | 26 | return ModalLogsView; 27 | }); 28 | -------------------------------------------------------------------------------- /www/views/modalNotification.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'models/org', 6 | 'views/modal', 7 | 'text!templates/modalNotification.html' 8 | ], function($, _, Backbone, OrgModel, ModalView, modalNotificationTemplate) { 9 | 'use strict'; 10 | var ModalNotificationView = ModalView.extend({ 11 | className: 'notification-modal', 12 | template: _.template(modalNotificationTemplate), 13 | title: 'Update Notification', 14 | okText: 'Close', 15 | cancelText: null, 16 | body: function() { 17 | return this.template(this.model.toJSON()); 18 | } 19 | }); 20 | 21 | return ModalNotificationView; 22 | }); 23 | -------------------------------------------------------------------------------- /www/views/modalRekeyLink.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'views/modal', 6 | 'views/alert', 7 | 'text!templates/modalRekeyLink.html' 8 | ], function($, _, Backbone, ModalView, AlertView, modalRekeyLinkTemplate) { 9 | 'use strict'; 10 | var ModalRekeyLinkView = ModalView.extend({ 11 | className: 'rekey-link-modal', 12 | template: _.template(modalRekeyLinkTemplate), 13 | title: 'Rekey Link', 14 | okText: 'Rekey', 15 | body: function() { 16 | return this.template(this.model.toJSON()); 17 | }, 18 | onOk: function() { 19 | this.setLoading('Rekeying link...'); 20 | this.model.save({ 21 | key: true 22 | }, { 23 | success: function() { 24 | this.close(true); 25 | }.bind(this), 26 | error: function(model, response) { 27 | this.clearLoading(); 28 | if (response.responseJSON) { 29 | this.setAlert('danger', response.responseJSON.error_msg); 30 | } 31 | else { 32 | this.setAlert('danger', this.errorMsg); 33 | } 34 | }.bind(this) 35 | }); 36 | } 37 | }); 38 | 39 | return ModalRekeyLinkView; 40 | }); 41 | -------------------------------------------------------------------------------- /www/views/modalRemoveRoute.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'views/modal', 6 | 'views/alert', 7 | 'text!templates/modalRemoveRoute.html' 8 | ], function($, _, Backbone, ModalView, AlertView, modalRemoveRouteTemplate) { 9 | 'use strict'; 10 | var ModalRemoveRouteView = ModalView.extend({ 11 | className: 'remove-route-modal', 12 | template: _.template(modalRemoveRouteTemplate), 13 | title: 'Remove Route', 14 | okText: 'Remove', 15 | body: function() { 16 | return this.template(this.model.toJSON()); 17 | }, 18 | onOk: function() { 19 | this.setLoading('Removing route...'); 20 | this.model.destroy({ 21 | success: function() { 22 | this.close(true); 23 | }.bind(this), 24 | error: function(model, response) { 25 | this.clearLoading(); 26 | if (response.responseJSON) { 27 | this.setAlert('danger', response.responseJSON.error_msg); 28 | } 29 | else { 30 | this.setAlert('danger', this.errorMsg); 31 | } 32 | }.bind(this) 33 | }); 34 | } 35 | }); 36 | 37 | return ModalRemoveRouteView; 38 | }); 39 | -------------------------------------------------------------------------------- /www/views/serverOutputLink.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'models/serverOutputLink', 6 | 'views/serverOutput' 7 | ], function($, _, Backbone, ServerOutputLinkModel, ServerOutputView) { 8 | 'use strict'; 9 | var ServerOutputLinkView = ServerOutputView.extend({ 10 | errorMsg: 'Failed to load server link output, server error occurred.', 11 | initialize: function(options) { 12 | this.model = new ServerOutputLinkModel({ 13 | id: options.server 14 | }); 15 | this.state = false; 16 | this.listenTo(window.events, 'server_link_output_updated:' + 17 | options.server, this.update); 18 | } 19 | }); 20 | 21 | return ServerOutputLinkView; 22 | }); 23 | -------------------------------------------------------------------------------- /www/views/servers.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'views/serversList' 6 | ], function($, _, Backbone, ServersListView) { 7 | 'use strict'; 8 | var ServersView = Backbone.View.extend({ 9 | className: 'servers container', 10 | initialize: function() { 11 | this.serversList = new ServersListView(); 12 | this.addView(this.serversList); 13 | }, 14 | render: function() { 15 | this.$el.append(this.serversList.render().el); 16 | return this; 17 | } 18 | }); 19 | 20 | return ServersView; 21 | }); 22 | -------------------------------------------------------------------------------- /www/views/users.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'underscore', 4 | 'backbone', 5 | 'views/orgsList' 6 | ], function($, _, Backbone, OrgsListView) { 7 | 'use strict'; 8 | var UsersView = Backbone.View.extend({ 9 | className: 'users container', 10 | initialize: function() { 11 | this.orgsList = new OrgsListView(); 12 | this.addView(this.orgsList); 13 | }, 14 | render: function() { 15 | this.$el.append(this.orgsList.render().el); 16 | return this; 17 | } 18 | }); 19 | 20 | return UsersView; 21 | }); 22 | --------------------------------------------------------------------------------