{ "info": { "author": "JupyterHub Share Link Contributors", "author_email": "dallan@bnl.gov", "bugtrack_url": null, "classifiers": [ "Development Status :: 2 - Pre-Alpha", "Natural Language :: English", "Programming Language :: Python :: 3" ], "description": "# JupyterHub Share Link\n\nThis is a new project that is still a work in progress. Please do not attempt to\nuse it in production yet. Contributors welcome!\n\n## Demo\n\nIn this GIF, Alice logs in, right-clicks a notebook and chooses \"Copy Shareable\nLink\". A dialog box appears, saying:\n\n> For the next hour, any other user on this JupyterHub who has this link will be\n> able to fetch a copy of your latest saved version of\n> dask-examples/array.ipynb.\n\nShe copies the link and gives it to Bob. Then, on the right, Bob logs in and\npastes the link into his browser. He is given a copy of Alice's notebook.\n\n![Demo](https://github.com/danielballan/jupyterhub-share-link/blob/master/demo.gif?raw=true)\n\n## JupyterHub Compatibility\n\n* jupyterhub-share-link v0.0.1 is compatible with JupyterHub 1.0\n* juptyerhub-share-link v0.1.x takes a different approach that requires a\n [one-line change](https://github.com/jupyterhub/jupyterhub/pull/2755) to\n jupyterhub itself, which has been submitted for consideration for inclusion in\n jupyterhub\n\n## Uses and Limitations\n\nThis is for low-effort, short-term sharing between users who are on the same\nHub.\n\nThe sender right-clicks a notebook (or any file) and clicks \"Copy Shareable\nLink.\" The sender gives that link to any other user on the same Hub. When\nanother user clicks the share link, the last saved version of the file is copied\nfrom the sender's notebook server to the recipient's. If the sender changes the\nfile, the recipient can click the link again to make another copy reflecting the\nchanges. After a given time interval, the link expires.\n\nOn Hubs that provide the user with options at spawn time, such as a\ncontainer-based spawner, the share link encodes both the notebook and the\noptions (e.g. the container image) that the sender was running that notebook in.\nThe recipient will automatically be directed to a server spawned with the same\noptions: the service finds a suitable existing one or spawns one if necessary.\nThus the recipient has some assurance that they will be running the notebook in\na compatible software environment.\n\nThis approach is not suitable for persistent sharing, such as galleries or lists\nof links to be maintained long term. For those use cases, it is better to encode\nsoftware dependencies (as in a Binder repo) rather than relying on the\navailability of a specific image.\n\n## Try it — with containers or without containers\n\nThis approach should be compatible with any spawner. Two examples are given\nhere, a local process spawner and a container-based spawner.\n\n### With Containers\n\n1. Install using pip.\n\n ```\n pip install jupyterhub-share-link\n ```\n\n2. Install [DockerSpawner](https://github.com/jupyterhub/dockerspawner).\n\n ```\n pip install dockerspawner\n ```\n\n3. Generate a key pair that will be used to sign and verify share links.\n\n ```\n # creates private.pem and public.pem in the current directory\n python -m jupyterhub_share_link.generate_keys\n ```\n\n4. Start JupyterHub using an example configuration provided in this repo.\n\n ```\n jupyterhub -f example_config_dockerspawner.py\n ```\n\n5. Log in with any username and password---for example, ``alice``.\n (The ``DummyAuthenticator`` is used by this demo configuration.)\n\n6. Spawn a server using the default image,\n ``danielballan/base-notebook-with-image-spec-extension``.\n\n7. Create and save a notebook ``Untitled.ipynb`` to share.\n\n8. Find ``Untitled.ipynb`` in the file browser and right-click it.\n A dialog box will appear. Click the button to copy the link.\n\n9. Log in as a different user and paste the shared link.\n\n10. The user will have a new server started running the same image as ``alice``,\n and the notebook will be copied and opened.\n\n### Without Containers\n\n1. Install using pip.\n\n ```\n pip install jupyterhub-share-link\n ```\n\n2. Generate a key pair that will be used to sign and verify share links.\n\n ```\n # creates private.pem and public.pem in the current directory\n python -m jupyterhub_share_link.generate_keys\n ```\n\n3. Install the labextension into the user environment.\n\n ```\n # Disable the default share-file extension and register our custom one.\n jupyter labextension disable @jupyterlab/filebrowser-extension:share-file\n jupyter labextension install jupyterhub-share-link-labextension\n ```\n\n4. Start JupyterHub using an example configuration provided in this repo. (In\n order to be able to log in as multiple users, you will likely need to run\n this as root.)\n\n ```\n jupyterhub -f example_config_no_containers.py\n ```\n\n5. Log in as a system user and start the user's server.\n\n6. Create and save a notebook ``Untitled.ipynb`` to share.\n\n7. Find ``Untitled.ipynb`` in the file browser and right-click it.\n A dialog box will appear. Click the button to copy the link.\n\n8. Log in as a different user and paste the shared link.\n\n9. The notebook will be copied to that user's server and opened.\n\n## Design\n\nThis involves:\n\n* A stateless Hub Service (in this repository) with the routes:\n\n ```\n POST /create # issue a shareable link\n GET /open # open a shared link\n GET / # verion info\n ```\n* A public/private key pair that belong to the service, enabling it issue\n \"share\" links that it can verify the recipient has not tampered with.\n* A labextension that customizes the behavior of the 'Copy Share Link' context\n menu item, stored at\n [danielballan/jupyterhub-share-link-labextension](https://github.com/danielballan/jupyterhub-share-link-labextension).\n\nThe file-copying occurs via the notebook's ContentsManager, so there is no need\nfor users to be on the same filesystem. They only have to be on the same Hub.\n\n## Open Questions\n\n* Encrypt path so that directory structure is not leaked to recipient?\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/danielballan/jupyterhub-share-link", "keywords": "", "license": "BSD (3-clause)", "maintainer": "", "maintainer_email": "", "name": "jupyterhub-share-link", "package_url": "https://pypi.org/project/jupyterhub-share-link/", "platform": "", "project_url": "https://pypi.org/project/jupyterhub-share-link/", "project_urls": { "Homepage": "https://github.com/danielballan/jupyterhub-share-link" }, "release_url": "https://pypi.org/project/jupyterhub-share-link/0.1.1/", "requires_dist": [ "cryptography", "jupyterhub", "pyjwt", "tornado", "traitlets" ], "requires_python": ">=3.6", "summary": "Make shareable links to notebooks.", "version": "0.1.1" }, "last_serial": 5928517, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "b18aaa5c09f0d05bf935a6e110b1ef03", "sha256": "4af87f01bfe3d52939ade2f37ce8bb08e7fafe98ce907beb24cdaaa2b4129785" }, "downloads": -1, "filename": "jupyterhub_share_link-0.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "b18aaa5c09f0d05bf935a6e110b1ef03", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 10542, "upload_time": "2019-10-02T15:45:44", "url": "https://files.pythonhosted.org/packages/33/7b/455d9a5ed7538ea5c6e41a0ffbcde3bf701daa2ca56fc4115da3dd5336a6/jupyterhub_share_link-0.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4d4ff5ccf5a8c686a669f4ea1d6ee641", "sha256": "2ebf78902ee3207955c348e112f4bbfbe257966d4686b5fb19ee789ccfc47568" }, "downloads": -1, "filename": "jupyterhub-share-link-0.0.1.tar.gz", "has_sig": false, "md5_digest": "4d4ff5ccf5a8c686a669f4ea1d6ee641", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 28289, "upload_time": "2019-10-02T15:45:58", "url": "https://files.pythonhosted.org/packages/98/26/963a4f7f62930f477baeb4aa207e0a00ab0e5f41da75bf01812aa1ffee88/jupyterhub-share-link-0.0.1.tar.gz" } ], "0.1.0": [ { "comment_text": "", "digests": { "md5": "8720c25dd6543541bbf6c71d5bb7bf21", "sha256": "4b08f4c884b374abebf8f48b3e0bbfc82e7b4cf5a81dcc8f91ba5ea6fa450ecb" }, "downloads": -1, "filename": "jupyterhub_share_link-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "8720c25dd6543541bbf6c71d5bb7bf21", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 11010, "upload_time": "2019-10-02T15:46:49", "url": "https://files.pythonhosted.org/packages/6f/32/5c0bc80e25514cdaa90483577986b076b13c1f0327c938bb45332dd9fcfb/jupyterhub_share_link-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d6b7e3f9fd38827bc2f626d6c8df0613", "sha256": "91b20a3cd068c6631341323622c2b6f980cfa610bd9a15442c5e6f66b4bebcfe" }, "downloads": -1, "filename": "jupyterhub-share-link-0.1.0.tar.gz", "has_sig": false, "md5_digest": "d6b7e3f9fd38827bc2f626d6c8df0613", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 28890, "upload_time": "2019-10-02T15:46:54", "url": "https://files.pythonhosted.org/packages/2b/04/2b572c76b07a1e014b969c20425a5bb06dc71c5670af98619a5f655dd40a/jupyterhub-share-link-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "351768234b005c382a2573896a9c0582", "sha256": "7af5faa734ba6fc9da54fda1a042382c5090cf6d23a29df60eb87bc8136e228d" }, "downloads": -1, "filename": "jupyterhub_share_link-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "351768234b005c382a2573896a9c0582", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 10957, "upload_time": "2019-10-04T14:00:37", "url": "https://files.pythonhosted.org/packages/b0/e3/d45bfee5c70a761d7f3ee204a7cf068dbba3e0d8357050060487852cf103/jupyterhub_share_link-0.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "5e6bb362440b4a285526c45966e24d33", "sha256": "58bb43b1b4f38788165532ba029a6d3ff90dd90f4a8c309277a62429a0b76b93" }, "downloads": -1, "filename": "jupyterhub-share-link-0.1.1.tar.gz", "has_sig": false, "md5_digest": "5e6bb362440b4a285526c45966e24d33", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 28659, "upload_time": "2019-10-04T14:00:40", "url": "https://files.pythonhosted.org/packages/b9/96/16a51e9b9ab33349d9d74ead47443995af5d22060b83b715ae847487e503/jupyterhub-share-link-0.1.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "351768234b005c382a2573896a9c0582", "sha256": "7af5faa734ba6fc9da54fda1a042382c5090cf6d23a29df60eb87bc8136e228d" }, "downloads": -1, "filename": "jupyterhub_share_link-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "351768234b005c382a2573896a9c0582", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 10957, "upload_time": "2019-10-04T14:00:37", "url": "https://files.pythonhosted.org/packages/b0/e3/d45bfee5c70a761d7f3ee204a7cf068dbba3e0d8357050060487852cf103/jupyterhub_share_link-0.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "5e6bb362440b4a285526c45966e24d33", "sha256": "58bb43b1b4f38788165532ba029a6d3ff90dd90f4a8c309277a62429a0b76b93" }, "downloads": -1, "filename": "jupyterhub-share-link-0.1.1.tar.gz", "has_sig": false, "md5_digest": "5e6bb362440b4a285526c45966e24d33", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 28659, "upload_time": "2019-10-04T14:00:40", "url": "https://files.pythonhosted.org/packages/b9/96/16a51e9b9ab33349d9d74ead47443995af5d22060b83b715ae847487e503/jupyterhub-share-link-0.1.1.tar.gz" } ] }