mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-10 19:43:01 +00:00
Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
bf73e6f7b7 | ||
![]() |
e2631b302a | ||
![]() |
0d89241c9f | ||
![]() |
5ac9e7f73a | ||
![]() |
9672b534ec | ||
![]() |
254365716d | ||
![]() |
dcac8c4efe | ||
![]() |
0611169dea | ||
![]() |
a432fa3bb6 | ||
![]() |
44141ae025 | ||
![]() |
04ae25d2c2 | ||
![]() |
69a1e97fbe | ||
![]() |
eb0c6514af | ||
![]() |
d03fc8c531 | ||
![]() |
1c8dce533b | ||
![]() |
bbfbc47bb3 | ||
![]() |
be6ec28dab | ||
![]() |
bd3a215c9e | ||
![]() |
3783a1bc6c | ||
![]() |
7b0f29b340 | ||
![]() |
f63e810dfe | ||
![]() |
909b3ad4d7 | ||
![]() |
114493be9b | ||
![]() |
4c0ac5ba91 | ||
![]() |
52793d65bd | ||
![]() |
320e1924a7 | ||
![]() |
2c90715c8d | ||
![]() |
c99bb32e12 | ||
![]() |
fee4ee23c0 |
@@ -201,7 +201,7 @@ These accounts will be used for authentication in JupyterHub's default configura
|
||||
## Contributing
|
||||
|
||||
If you would like to contribute to the project, please read our
|
||||
[contributor documentation](http://jupyter.readthedocs.io/en/latest/contributor/content-contributor.html)
|
||||
[contributor documentation](https://jupyter.readthedocs.io/en/latest/contributing/content-contributor.html)
|
||||
and the [`CONTRIBUTING.md`](CONTRIBUTING.md). The `CONTRIBUTING.md` file
|
||||
explains how to set up a development installation, how to run the test suite,
|
||||
and how to contribute to documentation.
|
||||
|
@@ -1,9 +1,8 @@
|
||||
-r ../requirements.txt
|
||||
|
||||
alabaster_jupyterhub
|
||||
# Temporary fix of #3021. Revert back to released autodoc-traits when
|
||||
# 0.1.0 released.
|
||||
https://github.com/jupyterhub/autodoc-traits/archive/75885ee24636efbfebfceed1043459715049cd84.zip
|
||||
autodoc-traits
|
||||
docutils<0.18
|
||||
pydata-sphinx-theme
|
||||
pytablewriter>=0.56
|
||||
recommonmark>=0.6
|
||||
|
@@ -3,7 +3,7 @@ swagger: "2.0"
|
||||
info:
|
||||
title: JupyterHub
|
||||
description: The REST API for JupyterHub
|
||||
version: 1.4.0
|
||||
version: 1.5.0
|
||||
license:
|
||||
name: BSD-3-Clause
|
||||
schemes: [http, https]
|
||||
@@ -873,7 +873,7 @@ definitions:
|
||||
description: The user that owns a token (undefined if owned by a service)
|
||||
service:
|
||||
type: string
|
||||
description: The service that owns the token (undefined of owned by a user)
|
||||
description: The service that owns the token (undefined if owned by a user)
|
||||
note:
|
||||
type: string
|
||||
description: A note about the token, typically describing what it was created for.
|
||||
|
@@ -6,6 +6,41 @@ command line for details.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## 1.5
|
||||
|
||||
JupyterHub 1.5 is a **security release**,
|
||||
fixing a vulnerability [ghsa-cw7p-q79f-m2v7][] where JupyterLab users
|
||||
with multiple tabs open could fail to logout completely,
|
||||
leaving their browser with valid credentials until they logout again.
|
||||
|
||||
A few fully backward-compatible features have been backported from 2.0.
|
||||
|
||||
[ghsa-cw7p-q79f-m2v7]: https://github.com/jupyterhub/jupyterhub/security/advisories/GHSA-cw7p-q79f-m2v7
|
||||
|
||||
### [1.5.0] 2021-11-04
|
||||
|
||||
([full changelog](https://github.com/jupyterhub/jupyterhub/compare/1.4.2...1.5.0))
|
||||
|
||||
#### New features added
|
||||
|
||||
- Backport #3636 to 1.4.x (opt-in support for JupyterHub.use_legacy_stopped_server_status_code) [#3639](https://github.com/jupyterhub/jupyterhub/pull/3639) ([@yuvipanda](https://github.com/yuvipanda))
|
||||
- Backport PR #3552 on branch 1.4.x (Add expiration date dropdown to Token page) [#3580](https://github.com/jupyterhub/jupyterhub/pull/3580) ([@meeseeksmachine](https://github.com/meeseeksmachine))
|
||||
- Backport PR #3488 on branch 1.4.x (Support auto login when used as a OAuth2 provider) [#3579](https://github.com/jupyterhub/jupyterhub/pull/3579) ([@meeseeksmachine](https://github.com/meeseeksmachine))
|
||||
|
||||
#### Maintenance and upkeep improvements
|
||||
|
||||
- 1.4.x: update doc requirements [#3677](https://github.com/jupyterhub/jupyterhub/pull/3677) ([@minrk](https://github.com/minrk))
|
||||
|
||||
#### Documentation improvements
|
||||
|
||||
- use_legacy_stopped_server_status_code: use 1.\* language [#3676](https://github.com/jupyterhub/jupyterhub/pull/3676) ([@manics](https://github.com/manics))
|
||||
|
||||
#### Contributors to this release
|
||||
|
||||
([GitHub contributors page for this release](https://github.com/jupyterhub/jupyterhub/graphs/contributors?from=2021-07-16&to=2021-11-03&type=c))
|
||||
|
||||
[@choldgraf](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Acholdgraf+updated%3A2021-07-16..2021-11-03&type=Issues) | [@consideRatio](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3AconsideRatio+updated%3A2021-07-16..2021-11-03&type=Issues) | [@manics](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Amanics+updated%3A2021-07-16..2021-11-03&type=Issues) | [@meeseeksmachine](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Ameeseeksmachine+updated%3A2021-07-16..2021-11-03&type=Issues) | [@minrk](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Aminrk+updated%3A2021-07-16..2021-11-03&type=Issues) | [@support](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Asupport+updated%3A2021-07-16..2021-11-03&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Awelcome+updated%3A2021-07-16..2021-11-03&type=Issues) | [@yuvipanda](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Ayuvipanda+updated%3A2021-07-16..2021-11-03&type=Issues)
|
||||
|
||||
## 1.4
|
||||
|
||||
JupyterHub 1.4 is a small release, with several enhancements, bug fixes,
|
||||
@@ -24,6 +59,32 @@ This is now also configurable via `JupyterHub.oauth_token_expires_in`.
|
||||
The result is that it should be much less likely for auth tokens stored in cookies
|
||||
to expire during the lifetime of a server.
|
||||
|
||||
### [1.4.2] 2021-06-15
|
||||
|
||||
1.4.2 is a small bugfix release for 1.4.
|
||||
|
||||
([full changelog](https://github.com/jupyterhub/jupyterhub/compare/1.4.1...d9860aa98cc537cf685022f81b8f725bfef41304))
|
||||
|
||||
#### Bugs fixed
|
||||
|
||||
- Fix regression where external services api_token became required [#3531](https://github.com/jupyterhub/jupyterhub/pull/3531) ([@consideRatio](https://github.com/consideRatio))
|
||||
- Bug: save_bearer_token (provider.py) passes a float value to the expires_at field (int) [#3484](https://github.com/jupyterhub/jupyterhub/pull/3484) ([@weisdd](https://github.com/weisdd))
|
||||
|
||||
#### Maintenance and upkeep improvements
|
||||
|
||||
- bump autodoc-traits [#3510](https://github.com/jupyterhub/jupyterhub/pull/3510) ([@minrk](https://github.com/minrk))
|
||||
|
||||
#### Documentation improvements
|
||||
|
||||
- Fix contributor documentation's link [#3521](https://github.com/jupyterhub/jupyterhub/pull/3521) ([@icankeep](https://github.com/icankeep))
|
||||
- Fix typo [#3494](https://github.com/jupyterhub/jupyterhub/pull/3494) ([@davidbrochart](https://github.com/davidbrochart))
|
||||
|
||||
#### Contributors to this release
|
||||
|
||||
([GitHub contributors page for this release](https://github.com/jupyterhub/jupyterhub/graphs/contributors?from=2021-05-12&to=2021-07-15&type=c))
|
||||
|
||||
[@consideRatio](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3AconsideRatio+updated%3A2021-05-12..2021-07-15&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Adavidbrochart+updated%3A2021-05-12..2021-07-15&type=Issues) | [@icankeep](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Aicankeep+updated%3A2021-05-12..2021-07-15&type=Issues) | [@minrk](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Aminrk+updated%3A2021-05-12..2021-07-15&type=Issues) | [@weisdd](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Aweisdd+updated%3A2021-05-12..2021-07-15&type=Issues)
|
||||
|
||||
### [1.4.1] 2021-05-12
|
||||
|
||||
1.4.1 is a small bugfix release for 1.4.
|
||||
@@ -53,7 +114,7 @@ to expire during the lifetime of a server.
|
||||
|
||||
[@0mar](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3A0mar+updated%3A2021-04-19..2021-05-12&type=Issues) | [@betatim](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Abetatim+updated%3A2021-04-19..2021-05-12&type=Issues) | [@consideRatio](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3AconsideRatio+updated%3A2021-04-19..2021-05-12&type=Issues) | [@danlester](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Adanlester+updated%3A2021-04-19..2021-05-12&type=Issues) | [@davidbrochart](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Adavidbrochart+updated%3A2021-04-19..2021-05-12&type=Issues) | [@IvanaH8](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3AIvanaH8+updated%3A2021-04-19..2021-05-12&type=Issues) | [@manics](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Amanics+updated%3A2021-04-19..2021-05-12&type=Issues) | [@minrk](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Aminrk+updated%3A2021-04-19..2021-05-12&type=Issues) | [@naatebarber](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Anaatebarber+updated%3A2021-04-19..2021-05-12&type=Issues) | [@OrnithOrtion](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3AOrnithOrtion+updated%3A2021-04-19..2021-05-12&type=Issues) | [@support](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Asupport+updated%3A2021-04-19..2021-05-12&type=Issues) | [@welcome](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Awelcome+updated%3A2021-04-19..2021-05-12&type=Issues)
|
||||
|
||||
### 1.4.0 2021-04-19
|
||||
### [1.4.0] 2021-04-19
|
||||
|
||||
([full changelog](https://github.com/jupyterhub/jupyterhub/compare/1.3.0...1.4.0))
|
||||
|
||||
@@ -1071,7 +1132,9 @@ Fix removal of `/login` page in 0.4.0, breaking some OAuth providers.
|
||||
|
||||
First preview release
|
||||
|
||||
[unreleased]: https://github.com/jupyterhub/jupyterhub/compare/1.4.1...HEAD
|
||||
[unreleased]: https://github.com/jupyterhub/jupyterhub/compare/1.5.0...HEAD
|
||||
[1.5.0]: https://github.com/jupyterhub/jupyterhub/compare/1.4.2...1.5.0
|
||||
[1.4.2]: https://github.com/jupyterhub/jupyterhub/compare/1.4.1...1.4.2
|
||||
[1.4.1]: https://github.com/jupyterhub/jupyterhub/compare/1.4.0...1.4.1
|
||||
[1.4.0]: https://github.com/jupyterhub/jupyterhub/compare/1.3.0...1.4.0
|
||||
[1.3.0]: https://github.com/jupyterhub/jupyterhub/compare/1.2.1...1.3.0
|
||||
|
@@ -4,8 +4,8 @@
|
||||
|
||||
version_info = (
|
||||
1,
|
||||
4,
|
||||
1,
|
||||
5,
|
||||
0,
|
||||
"", # release (b1, rc1, or "" for final or dev)
|
||||
# "dev", # dev or nothing for beta/rc/stable releases
|
||||
)
|
||||
|
@@ -222,6 +222,14 @@ class OAuthAuthorizeHandler(OAuthHandler, BaseHandler):
|
||||
# default: require confirmation
|
||||
return True
|
||||
|
||||
def get_login_url(self):
|
||||
"""
|
||||
Support automatically logging in when JupyterHub is used as auth provider
|
||||
"""
|
||||
if self.authenticator.auto_login_oauth2_authorize:
|
||||
return self.authenticator.login_url(self.hub.base_url)
|
||||
return super().get_login_url()
|
||||
|
||||
@web.authenticated
|
||||
async def get(self):
|
||||
"""GET /oauth/authorization
|
||||
|
@@ -1476,6 +1476,26 @@ class JupyterHub(Application):
|
||||
""",
|
||||
).tag(config=True)
|
||||
|
||||
use_legacy_stopped_server_status_code = Bool(
|
||||
True,
|
||||
help="""
|
||||
Return 503 rather than 424 when request comes in for a non-running server.
|
||||
|
||||
Prior to JupyterHub 2.0, this returns a 503 when any request comes in for
|
||||
a user server that is currently not running. By default, JupyterHub 2.0
|
||||
will return a 424 - this makes operational metric dashboards more useful.
|
||||
|
||||
JupyterLab < 3.2 expected the 503 to know if the user server is no longer
|
||||
running, and prompted the user to start their server. Set this config to
|
||||
true to retain the old behavior, so JupyterLab < 3.2 can continue to show
|
||||
the appropriate UI when the user server is stopped.
|
||||
|
||||
This option will default to False in JupyterHub 2.0, and be removed in a
|
||||
future release.
|
||||
""",
|
||||
config=True,
|
||||
)
|
||||
|
||||
def init_handlers(self):
|
||||
h = []
|
||||
# load handlers from the authenticator
|
||||
@@ -2042,18 +2062,14 @@ class JupyterHub(Application):
|
||||
raise AttributeError("No such service field: %s" % key)
|
||||
setattr(service, key, value)
|
||||
|
||||
if service.managed:
|
||||
if not service.api_token:
|
||||
# generate new token
|
||||
# TODO: revoke old tokens?
|
||||
service.api_token = service.orm.new_api_token(
|
||||
note="generated at startup"
|
||||
)
|
||||
else:
|
||||
# ensure provided token is registered
|
||||
self.service_tokens[service.api_token] = service.name
|
||||
else:
|
||||
if service.api_token:
|
||||
self.service_tokens[service.api_token] = service.name
|
||||
elif service.managed:
|
||||
# generate new token
|
||||
# TODO: revoke old tokens?
|
||||
service.api_token = service.orm.new_api_token(
|
||||
note="generated at startup"
|
||||
)
|
||||
|
||||
if service.url:
|
||||
parsed = urlparse(service.url)
|
||||
|
@@ -646,6 +646,26 @@ class Authenticator(LoggingConfigurable):
|
||||
""",
|
||||
)
|
||||
|
||||
auto_login_oauth2_authorize = Bool(
|
||||
False,
|
||||
config=True,
|
||||
help="""
|
||||
Automatically begin login process for OAuth2 authorization requests
|
||||
|
||||
When another application is using JupyterHub as OAuth2 provider, it
|
||||
sends users to `/hub/api/oauth2/authorize`. If the user isn't logged
|
||||
in already, and auto_login is not set, the user will be dumped on the
|
||||
hub's home page, without any context on what to do next.
|
||||
|
||||
Setting this to true will automatically redirect users to login if
|
||||
they aren't logged in *only* on the `/hub/api/oauth2/authorize`
|
||||
endpoint.
|
||||
|
||||
.. versionadded:: 1.5
|
||||
|
||||
""",
|
||||
)
|
||||
|
||||
def login_url(self, base_url):
|
||||
"""Override this when registering a custom login handler
|
||||
|
||||
|
@@ -1330,7 +1330,7 @@ class UserUrlHandler(BaseHandler):
|
||||
|
||||
**Changed Behavior as of 1.0** This handler no longer triggers a spawn. Instead, it checks if:
|
||||
|
||||
1. server is not active, serve page prompting for spawn (status: 503)
|
||||
1. server is not active, serve page prompting for spawn (status: 424)
|
||||
2. server is ready (This shouldn't happen! Proxy isn't updated yet. Wait a bit and redirect.)
|
||||
3. server is active, redirect to /hub/spawn-pending to monitor launch progress
|
||||
(will redirect back when finished)
|
||||
@@ -1349,7 +1349,14 @@ class UserUrlHandler(BaseHandler):
|
||||
self.log.warning(
|
||||
"Failing suspected API request to not-running server: %s", self.request.path
|
||||
)
|
||||
self.set_status(503)
|
||||
|
||||
# If we got here, the server is not running. To differentiate
|
||||
# that the *server* itself is not running, rather than just the particular
|
||||
# resource *in* the server is not found, we return a 424 instead of a 404.
|
||||
# We allow retaining the old behavior to support older JupyterLab versions
|
||||
self.set_status(
|
||||
424 if not self.app.use_legacy_stopped_server_status_code else 503
|
||||
)
|
||||
self.set_header("Content-Type", "application/json")
|
||||
|
||||
spawn_url = urlparse(self.request.full_url())._replace(query="")
|
||||
@@ -1514,15 +1521,17 @@ class UserUrlHandler(BaseHandler):
|
||||
self.redirect(pending_url, status=303)
|
||||
return
|
||||
|
||||
# if we got here, the server is not running
|
||||
# serve a page prompting for spawn and 503 error
|
||||
# visiting /user/:name no longer triggers implicit spawn
|
||||
# without explicit user action
|
||||
# If we got here, the server is not running. To differentiate
|
||||
# that the *server* itself is not running, rather than just the particular
|
||||
# page *in* the server is not found, we return a 424 instead of a 404.
|
||||
# We allow retaining the old behavior to support older JupyterLab versions
|
||||
spawn_url = url_concat(
|
||||
url_path_join(self.hub.base_url, "spawn", user.escaped_name, server_name),
|
||||
{"next": self.request.uri},
|
||||
)
|
||||
self.set_status(503)
|
||||
self.set_status(
|
||||
424 if not self.app.use_legacy_stopped_server_status_code else 503
|
||||
)
|
||||
|
||||
auth_state = await user.get_auth_state()
|
||||
html = await self.render_template(
|
||||
|
@@ -342,7 +342,7 @@ class JupyterHubRequestValidator(RequestValidator):
|
||||
orm_access_token = orm.OAuthAccessToken(
|
||||
client=client,
|
||||
grant_type=orm.GrantType.authorization_code,
|
||||
expires_at=orm.OAuthAccessToken.now() + token['expires_in'],
|
||||
expires_at=int(orm.OAuthAccessToken.now() + token['expires_in']),
|
||||
refresh_token=token['refresh_token'],
|
||||
# TODO: save scopes,
|
||||
# scopes=scopes,
|
||||
|
@@ -927,8 +927,8 @@ class HubAuthenticated(object):
|
||||
self._hub_auth_user_cache = None
|
||||
raise
|
||||
|
||||
# store tokens passed via url or header in a cookie for future requests
|
||||
url_token = self.hub_auth.get_token(self)
|
||||
# store ?token=... tokens passed via url in a cookie for future requests
|
||||
url_token = self.get_argument('token', '')
|
||||
if (
|
||||
user_model
|
||||
and url_token
|
||||
|
@@ -675,6 +675,18 @@ class SingleUserNotebookAppMixin(Configurable):
|
||||
orig_loader = env.loader
|
||||
env.loader = ChoiceLoader([FunctionLoader(get_page), orig_loader])
|
||||
|
||||
def load_server_extensions(self):
|
||||
# Loading LabApp sets $JUPYTERHUB_API_TOKEN on load, which is incorrect
|
||||
r = super().load_server_extensions()
|
||||
# clear the token in PageConfig at this step
|
||||
# so that cookie auth is used
|
||||
# FIXME: in the future,
|
||||
# it would probably make sense to set page_config.token to the token
|
||||
# from the current request.
|
||||
if 'page_config_data' in self.web_app.settings:
|
||||
self.web_app.settings['page_config_data']['token'] = ''
|
||||
return r
|
||||
|
||||
|
||||
def detect_base_package(App):
|
||||
"""Detect the base package for an App class
|
||||
|
@@ -1008,6 +1008,13 @@ async def test_server_not_running_api_request(app):
|
||||
assert " /user/bees" in message
|
||||
|
||||
|
||||
async def test_server_not_running_api_request_legacy_status(app):
|
||||
app.use_legacy_stopped_server_status_code = False
|
||||
cookies = await app.login_user("bees")
|
||||
r = await get_page("user/bees/api/status", app, hub=False, cookies=cookies)
|
||||
assert r.status_code == 424
|
||||
|
||||
|
||||
async def test_metrics_no_auth(app):
|
||||
r = await get_page("metrics", app)
|
||||
assert r.status_code == 403
|
||||
|
@@ -102,3 +102,51 @@ async def test_external_service(app):
|
||||
assert len(resp) >= 1
|
||||
assert isinstance(resp[0], dict)
|
||||
assert 'name' in resp[0]
|
||||
|
||||
|
||||
async def test_external_services_without_api_token_set(app):
|
||||
"""
|
||||
This test was made to reproduce an error like this:
|
||||
|
||||
ValueError: Tokens must be at least 8 characters, got ''
|
||||
|
||||
The error had the following stack trace in 1.4.1:
|
||||
|
||||
jupyterhub/app.py:2213: in init_api_tokens
|
||||
await self._add_tokens(self.service_tokens, kind='service')
|
||||
jupyterhub/app.py:2182: in _add_tokens
|
||||
obj.new_api_token(
|
||||
jupyterhub/orm.py:424: in new_api_token
|
||||
return APIToken.new(token=token, service=self, **kwargs)
|
||||
jupyterhub/orm.py:699: in new
|
||||
cls.check_token(db, token)
|
||||
|
||||
This test also make _add_tokens receive a token_dict that is buggy:
|
||||
|
||||
{"": "external_2"}
|
||||
|
||||
It turned out that whatever passes token_dict to _add_tokens failed to
|
||||
ignore service's api_tokens that were None, and instead passes them as blank
|
||||
strings.
|
||||
|
||||
It turned out that init_api_tokens was passing self.service_tokens, and that
|
||||
self.service_tokens had been populated with blank string tokens for external
|
||||
services registered with JupyterHub.
|
||||
"""
|
||||
name_1 = 'external_1'
|
||||
name_2 = 'external_2'
|
||||
async with external_service(app, name=name_1) as env_1, external_service(
|
||||
app, name=name_2
|
||||
) as env_2:
|
||||
app.services = [
|
||||
{
|
||||
'name': name_1,
|
||||
'url': "http://irrelevant",
|
||||
},
|
||||
{
|
||||
'name': name_2,
|
||||
'url': "http://irrelevant",
|
||||
},
|
||||
]
|
||||
await maybe_future(app.init_services())
|
||||
await app.init_api_tokens()
|
||||
|
10
setup.py
10
setup.py
@@ -12,8 +12,11 @@ import shutil
|
||||
import sys
|
||||
from subprocess import check_call
|
||||
|
||||
from setuptools import Command
|
||||
from setuptools import setup
|
||||
from setuptools.command.bdist_egg import bdist_egg
|
||||
from setuptools.command.build_py import build_py
|
||||
from setuptools.command.sdist import sdist
|
||||
|
||||
|
||||
v = sys.version_info
|
||||
@@ -132,14 +135,9 @@ setup_args = dict(
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# custom distutils commands
|
||||
# custom setuptools commands
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# imports here, so they are after setuptools import if there was one
|
||||
from distutils.cmd import Command
|
||||
from distutils.command.build_py import build_py
|
||||
from distutils.command.sdist import sdist
|
||||
|
||||
|
||||
def mtime(path):
|
||||
"""shorthand for mtime"""
|
||||
|
@@ -20,9 +20,14 @@ require(["jquery", "jhapi", "moment"], function ($, JHAPI, moment) {
|
||||
if (!note.length) {
|
||||
note = "Requested via token page";
|
||||
}
|
||||
var expiration_seconds =
|
||||
parseInt($("#token-expiration-seconds").val()) || null;
|
||||
api.request_token(
|
||||
user,
|
||||
{ note: note },
|
||||
{
|
||||
note: note,
|
||||
expires_in: expiration_seconds,
|
||||
},
|
||||
{
|
||||
success: function (reply) {
|
||||
$("#token-result").text(reply.token);
|
||||
|
@@ -19,6 +19,20 @@
|
||||
<small id="note-note" class="form-text text-muted">
|
||||
This note will help you keep track of what your tokens are for.
|
||||
</small>
|
||||
<br><br>
|
||||
<label for="token-expiration-seconds">Token expires</label>
|
||||
{% block expiration_options %}
|
||||
<select id="token-expiration-seconds"
|
||||
class="form-control">
|
||||
<option value="3600">1 Day</option>
|
||||
<option value="86400">1 Week</option>
|
||||
<option value="604800">1 Month</option>
|
||||
<option value="" selected="selected">Never</option>
|
||||
</select>
|
||||
{% endblock expiration_options %}
|
||||
<small id="note-expires-at" class="form-text text-muted">
|
||||
You can configure when your token will be expired.
|
||||
</small>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -56,6 +70,7 @@
|
||||
<td>Note</td>
|
||||
<td>Last used</td>
|
||||
<td>Created</td>
|
||||
<td>Expires at</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -77,6 +92,13 @@
|
||||
N/A
|
||||
{%- endif -%}
|
||||
</td>
|
||||
<td class="time-col col-sm-3">
|
||||
{%- if token.expires_at -%}
|
||||
{{ token.expires_at.isoformat() + 'Z' }}
|
||||
{%- else -%}
|
||||
Never
|
||||
{%- endif -%}
|
||||
</td>
|
||||
<td class="col-sm-1 text-center">
|
||||
<button class="revoke-token-btn btn btn-xs btn-danger">revoke</button>
|
||||
</td>
|
||||
|
Reference in New Issue
Block a user