Journalist Interface API¶
This document describes the endpoints for SecureDrop’s Journalist Interface API.
Versioning¶
The API is versioned and we are currently using version 1. This is set via the base URL, which is:
/api/v1/
Content Type¶
Clients shall send the following headers:
'Accept': 'application/json',
'Content-Type': 'application/json'
Authentication¶
POST /api/v1/token
to get a token with the username, password, and two-factor
code in the request body:
{
"username": "journalist",
"passphrase": "monkey potato pizza quality silica growing deduce",
"one_time_code": "123456"
}
This will produce a response with your Authorization token:
{
"expiration": "2018-07-10T04:29:41.696321Z",
"token": "eyJhbGciOiJIUzI1NiIsImV4cCI6MTUzMTE5Njk4MSwiaWF0IjoxNTMxMTY4MTgxfQ.eyJpZCI6MX0.TBSvfrICMxtvWgpVZzqTl6wHYNQuGPOaZpuAKwwIXXo",
"journalist_uuid": "54d81dae-9d94-4145-8a57-4c804a04cfe0",
"journalist_first_name": "daniel",
"journalist_last_name": "ellsberg"
}
Thereafter in order to authenticate to protected endpoints, send the token in HTTP Authorization header:
Authorization: Token eyJhbGciOiJIUzI1NiIsImV4cCI6MTUzMDU4NjU4MiwifWF0IjoxNTMwNTc5MzgyfQ.eyJpZCI6MX0.P_PfcLMk1Dq5VCIANo-lJbu0ZyCL2VcT8qf9fIZsTCM
This header will be checked with each API request to see if it is valid and not yet expired. Tokens currently expire after 8 hours.
Logout¶
Clients should use the logout endpoint to invalidate their token:
POST /api/v1/logout
with the token in the HTTP Authorization header
and you will get the following response upon successful invalidation of the
API token:
{
"message": "Your token has been revoked."
}
Errors¶
The API will respond to all errors (400-599) with a JSON object with the following fields:
{
"message": "This is a detailed error message."
}
Endpoints¶
Root Endpoint¶
Does not require authentication.
The root endpoint describes the available resources:
GET /api/v1/
Response 200 (application/json):
{
"all_users_url": "/api/v1/users",
"auth_token_url": "/api/v1/token",
"current_user_url": "/api/v1/user",
"replies_url": "/api/v1/replies",
"seen_url": "/api/v1/seen",
"sources_url": "/api/v1/sources",
"submissions_url": "/api/v1/submissions"
}
Sources¶
Get all sources¶
Requires authentication. Provides a list of all sources and data about them (such as number of documents, submissions, and their public key that replies should be encrypted to).
GET /api/v1/sources
Response 200 (application/json):
{
"sources": [
{
"add_star_url": "/api/v1/sources/9b6df7c9-a6b1-461d-91f0-5b715fc7a47a/add_star",
"interaction_count": 2,
"is_flagged": false,
"is_starred": false,
"journalist_designation": "validated benefactress",
"key": {
"fingerprint": "8C71EA66B0278309A31DBD691733DA655854DB12",
"public": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFGRfoABEACf5Y+6prky4JcWmKSsuh/52ZLw1FTCqrgAIK0QVFZ+cy2riFHv\njQXYB4bPOCt7PmYbmMxxIWkXqJCaPVkLbpi7p5X2Wkgh+qGgjIjotq2Y9iPP6KQ3\nGvJdpG3rWwbOsrt4rDh/L/lStn+ty4io3cDr7l7ISOtOcmOPKeKv6eGxSmCAYsnJ\nKKsIWcSjfb82KhCzL/BBApqXt9uc6Jqjh1RPL3bGIG0tq37yX/zbFefDBDF8m8d6\nc7pvvYMaO90PGViBVg6hh8+rPq/rK7YyHOWZlt6MXw7cm/GaH+DkGxGKe8Yuj92R\nOPNQFfpAI/tXldEcEvdG/4mba7uxrEMe33tsnbQamFZtXFAIrSjXa9O4CEEWnRCz\nNE90u9FeM4bk/lModsr7gOrWbO6QwctVt/YnvI7blUXzpMzDsbgvR89auKS9VHGZ\nY5L3yz0yVwRAIw3/CwsJEYajKiPadcExhZhc8OCTTe8zPXxQ8OWrvmFBA6x6cfvq\nSqoH3NXrDVY/6w9dCqVXitcYynATqm0Qkkr81jXE3BEfx7AQPXHXGasvFM1mqeQU\n+WQPqUKheomy7/7z3heasKub3MYLkuW6y7c31z6cmvt6h5fYcNPvQXCox4BJkVcK\nPbzst612sbqhTQEeSsDnVU1sPLxpfbxFfKuWQlEV8kfm4JsMbryqG9Z0RQARAQAB\ntHxBdXRvZ2VuZXJhdGVkIEtleSA8UFlNR0IzRE9BNVFLVFozNjVPUTNQWUpDMk9a\nQ0RXQjIyM1dFS1Q3V0o1NDI0QUZUT1ZFSjI0SEpaSFRYQTZTQjVGUkFBVjdHRVFQ\nS01HQjQzUUxMVzNTRUxFWENYWklVRk5QWTU2WT0+iQI3BBMBCgAhBQJRkX6AAhsv\nBQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJEBcz2mVYVNsSQ88P/3e54noTBb/O\nFVVNYw5oY9zIQPsoYUkCCvKCv26bi3qpfsDWjohyupKLth9AfFBTk3oiNhzeFhiv\nZ5RbLgJYAWuzWNdMCSd3RAqZbbzFx3255oR9t+/RNwjeOqKpoO313myAKsRR1z+N\nbRF0A1C8GiMOCrvV/9p+rsTDrv+8fXkrQz55nGkt6JlI43EqlH0Eg7wxI+HMgTdz\nsPWBR63INNhkrR5Ln7YShOBmnUWjpEjFYvZlAbzkMbbfznDZ2g7auRpT0S8vNgcG\n9k9dG3gpMFnHiaE4SmdOIb82qv9X6Q7Owwxmz85JAe/P/CYsndUbRHSfXMp16igm\nj0RfcC7J0E/SkwBY9jc+YtGCWfqqXa1a4uY03vN1YqqFWqb+exa/Qv14wwgcS17p\n8O/X1y9gPV0qleikFgNt8sPd+a2lVdRSjh4Xh7l6eTHMqoDUJXtFu0evSg3oBFZj\n8OIXe8KZltJCYlxN+1/xlvZjAVfmYT6kxOXYsPB3o3Z9Hemgsw2PnjI04ZMwTSyb\n101xfgB1XBd1Hrv9WQ5PNoPwXRhx7/bfzQWTx/uP8luT6yqEerLiF0m/ShvYvKQa\ncLuwtW3Rlj1BD5CpdG+491jJ6cRXq8xfYmCd2MmBTtMAoq4DobYw75NKIssZ5gs6\nu6NXuCWOsf8lQNBKxkNpuohLlTef8n1y\n=Zp4Z\n-----END PGP PUBLIC KEY BLOCK-----\n",
"type": "PGP"
},
"last_updated": "2018-07-10T00:52:21.157409Z",
"number_of_documents": 0,
"number_of_messages": 2,
"remove_star_url": "/api/v1/sources/9b6df7c9-a6b1-461d-91f0-5b715fc7a47a/remove_star",
"replies_url": "/api/v1/sources/9b6df7c9-a6b1-461d-91f0-5b715fc7a47a/replies",
"submissions_url": "/api/v1/sources/9b6df7c9-a6b1-461d-91f0-5b715fc7a47a/submissions",
"url": "/api/v1/sources/9b6df7c9-a6b1-461d-91f0-5b715fc7a47a",
"uuid": "9b6df7c9-a6b1-461d-91f0-5b715fc7a47a"
},
{
"add_star_url": "/api/v1/sources/f086bd03-1c89-49fb-82d5-00084c17b4ce/add_star",
"interaction_count": 2,
"is_flagged": false,
"is_starred": false,
"journalist_designation": "navigational firearm",
"key": {
"fingerprint": "C20D06197FFAE44552358AA5886EEA0A360D9FF1",
"public": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFGRfoABEACdO+SPazdXyWRnK6JQmDvwL5Vfmp4bxK3fzM6JFO0X6B6T8Unj\n5bLyUM3+K7Cwp4x1uANo60X5k6zMJFqxFVbIdXearfU0DyGWG3DINGsIwf1NNkuA\noj3QVcv+jhigpn1wZvDT8AyJqaEisUddREUw1CpvOdCFw1uIFfodz5GJmVXZnApN\n27BJKNnsJtL8lWrUvTY/n4afXgMZ78ZH8aOkdmJ7wmVbIhrZlHu4UHJP6DbCm/+D\n7o74ozWCv6si9bfBpG6UbCxVqaeRYjb1kGT0y36TLy8W6+JXw+yISgKTORETTjQX\nzzHP5gfLu8ZTJhSvMV+xkpxc0HaX6P80rQR40QfVYRgO1uZ1Bfab+rPdUrQSPdnb\ntN6Rh6rN0QfucuqPYpiS8AJl1Si9ztyIdkYLJTL/CseO6SWDc/krIj8mX4VbN0h0\nYwECCbtv5uX8q3Jhkc8oTjpW+DRxfb1UW7us1nOoXVj9aOQaUM6QZtbVz0qQDJ9e\nSOqIx2tv5qToTxKim8E9HjX+NCvZKDIqvaoDpreMHkFP/Fo0t0tnbHTZAWcUMaih\n5WNqrFqpGYm1fDfYDIL9m3DPVaFHk3eO7apxQXwDrckeRY7Bma+YLOXG4yVf/If6\nKedgBz0Nx1gZcU6c10Fy3Dn90jcjYtTOtrEsVORdfE/1SVBKmAOjpYirnQARAQAB\ntHxBdXRvZ2VuZXJhdGVkIEtleSA8MldXQlhaRlo1Q1RYSkVCQzZYQUNZUVhMWlNN\nNEdCUk0zUVlZWjJMR0VPQUxQTEZKSjVCR1lPSzRZUzU0SktYSlQzTlhVTkpLQ0VH\nTFU2RFVQUldGWEM1WlEzRk1UVFhDM0VSRlQzWT0+iQI3BBMBCgAhBQJRkX6AAhsv\nBQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJEIhu6go2DZ/xLcgP/1lEL1F7hoQr\nLQm8T/DqjoExh0F8am9SKb2lH9HSBUJPY9b/oPjptxyg/3NlGXP/GJGcI6SVXtnq\nGU2D2+vMUUrnV/AemAtBUIquIXMEujbGdKOuWTBCntgj6PJL6/VNi2o+v9FxATN1\n6hefcdOIk7DMaK8y56BJA+aI/7TnCr1ndHLUMXh0rKd8GSl3vXtv2kuY8iSqiOmj\nuOtW1w2lByFBglNLgnozdbudwwVqNvKX8j3oWJKsJ525Y3HsWka/l4GbkowveUYR\nU66usAX6KS1zT01pLDmYFCL7lX8SPkZq97qHoFa1C9NIHW2gP+y8Q922E9QWBqy7\n/g30ZF73MgZCOnFOChswH607LBvMGUyz+A2Qjpd7Zvf67G33inY7QlGkMI59Zz4T\nXXv/1U3Gl6LLkwGWrTDhqHgK2KA9+B6gPYDV9xh/1HTvLBE4Wf8EHhtUyW1ZxzY5\nuXvZt5OH/UKpuhcsuN6c/5+QQk0i85jTBPXm7/0XcbbRuBTnl6CiVM8vGuaLjOdW\ntAlRmX9hS7jmdE9e3Yl17qUPwlEEKSFH8Z6GgEEommoHPsgmDrQxUS6v68zfcmf3\nAE+dfKUDfC7muZfZQ0YaqeHMrDyLozRIjVtx6P3fxZPZfUvfrV4guJOVOMwi+Z1F\n5UrZB6IrSA4njr9Vr+Fb0p+v73pfV6NT\n=e+yq\n-----END PGP PUBLIC KEY BLOCK-----\n",
"type": "PGP"
},
"last_updated": "2018-07-10T00:52:25.696391Z",
"number_of_documents": 0,
"number_of_messages": 2,
"remove_star_url": "/api/v1/sources/f086bd03-1c89-49fb-82d5-00084c17b4ce/remove_star",
"replies_url": "/api/v1/sources/f086bd03-1c89-49fb-82d5-00084c17b4ce/replies",
"submissions_url": "/api/v1/sources/f086bd03-1c89-49fb-82d5-00084c17b4ce/submissions",
"url": "/api/v1/sources/f086bd03-1c89-49fb-82d5-00084c17b4ce",
"uuid": "f086bd03-1c89-49fb-82d5-00084c17b4ce"
}
]
}
Get a single source¶
Requires authentication.
GET /sources/<source_uuid>
Response 200 (application/json):
{
"add_star_url": "/api/v1/sources/9b6df7c9-a6b1-461d-91f0-5b715fc7a47a/add_star",
"interaction_count": 2,
"is_flagged": false,
"is_starred": false,
"journalist_designation": "validated benefactress",
"key": {
"fingerprint": "8C71EA66B0278309A31DBD691733DA655854DB12",
"public": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFGRfoABEACf5Y+6prky4JcWmKSsuh/52ZLw1FTCqrgAIK0QVFZ+cy2riFHv\njQXYB4bPOCt7PmYbmMxxIWkXqJCaPVkLbpi7p5X2Wkgh+qGgjIjotq2Y9iPP6KQ3\nGvJdpG3rWwbOsrt4rDh/L/lStn+ty4io3cDr7l7ISOtOcmOPKeKv6eGxSmCAYsnJ\nKKsIWcSjfb82KhCzL/BBApqXt9uc6Jqjh1RPL3bGIG0tq37yX/zbFefDBDF8m8d6\nc7pvvYMaO90PGViBVg6hh8+rPq/rK7YyHOWZlt6MXw7cm/GaH+DkGxGKe8Yuj92R\nOPNQFfpAI/tXldEcEvdG/4mba7uxrEMe33tsnbQamFZtXFAIrSjXa9O4CEEWnRCz\nNE90u9FeM4bk/lModsr7gOrWbO6QwctVt/YnvI7blUXzpMzDsbgvR89auKS9VHGZ\nY5L3yz0yVwRAIw3/CwsJEYajKiPadcExhZhc8OCTTe8zPXxQ8OWrvmFBA6x6cfvq\nSqoH3NXrDVY/6w9dCqVXitcYynATqm0Qkkr81jXE3BEfx7AQPXHXGasvFM1mqeQU\n+WQPqUKheomy7/7z3heasKub3MYLkuW6y7c31z6cmvt6h5fYcNPvQXCox4BJkVcK\nPbzst612sbqhTQEeSsDnVU1sPLxpfbxFfKuWQlEV8kfm4JsMbryqG9Z0RQARAQAB\ntHxBdXRvZ2VuZXJhdGVkIEtleSA8UFlNR0IzRE9BNVFLVFozNjVPUTNQWUpDMk9a\nQ0RXQjIyM1dFS1Q3V0o1NDI0QUZUT1ZFSjI0SEpaSFRYQTZTQjVGUkFBVjdHRVFQ\nS01HQjQzUUxMVzNTRUxFWENYWklVRk5QWTU2WT0+iQI3BBMBCgAhBQJRkX6AAhsv\nBQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJEBcz2mVYVNsSQ88P/3e54noTBb/O\nFVVNYw5oY9zIQPsoYUkCCvKCv26bi3qpfsDWjohyupKLth9AfFBTk3oiNhzeFhiv\nZ5RbLgJYAWuzWNdMCSd3RAqZbbzFx3255oR9t+/RNwjeOqKpoO313myAKsRR1z+N\nbRF0A1C8GiMOCrvV/9p+rsTDrv+8fXkrQz55nGkt6JlI43EqlH0Eg7wxI+HMgTdz\nsPWBR63INNhkrR5Ln7YShOBmnUWjpEjFYvZlAbzkMbbfznDZ2g7auRpT0S8vNgcG\n9k9dG3gpMFnHiaE4SmdOIb82qv9X6Q7Owwxmz85JAe/P/CYsndUbRHSfXMp16igm\nj0RfcC7J0E/SkwBY9jc+YtGCWfqqXa1a4uY03vN1YqqFWqb+exa/Qv14wwgcS17p\n8O/X1y9gPV0qleikFgNt8sPd+a2lVdRSjh4Xh7l6eTHMqoDUJXtFu0evSg3oBFZj\n8OIXe8KZltJCYlxN+1/xlvZjAVfmYT6kxOXYsPB3o3Z9Hemgsw2PnjI04ZMwTSyb\n101xfgB1XBd1Hrv9WQ5PNoPwXRhx7/bfzQWTx/uP8luT6yqEerLiF0m/ShvYvKQa\ncLuwtW3Rlj1BD5CpdG+491jJ6cRXq8xfYmCd2MmBTtMAoq4DobYw75NKIssZ5gs6\nu6NXuCWOsf8lQNBKxkNpuohLlTef8n1y\n=Zp4Z\n-----END PGP PUBLIC KEY BLOCK-----\n",
"type": "PGP"
},
"last_updated": "2018-07-10T00:52:21.157409Z",
"number_of_documents": 0,
"number_of_messages": 2,
"remove_star_url": "/api/v1/sources/9b6df7c9-a6b1-461d-91f0-5b715fc7a47a/remove_star",
"replies_url": "/api/v1/sources/9b6df7c9-a6b1-461d-91f0-5b715fc7a47a/replies",
"submissions_url": "/api/v1/sources/9b6df7c9-a6b1-461d-91f0-5b715fc7a47a/submissions",
"url": "/api/v1/sources/9b6df7c9-a6b1-461d-91f0-5b715fc7a47a",
"uuid": "9b6df7c9-a6b1-461d-91f0-5b715fc7a47a"
}
Get all submissions associated with a source¶
Requires authentication.
GET /api/v1/sources/<source_uuid>/submissions
Response 200 (application/json):
{
"submissions": [
{
"download_url": "/api/v1/sources/e5a42bdb-1fef-4d66-9876-b2d592f90704/submissions/b7a7b6ca-9a11-4a51-8b59-7e454f6bf8d0/download",
"filename": "1-dark-haired_insolation-msg.gpg",
"is_file": false,
"is_message": true,
"is_read": true,
"seen_by": [
"1c914871-a335-44ba-b2ae-da878cbc3630"
],
"size": 593,
"source_url": "/api/v1/sources/e5a42bdb-1fef-4d66-9876-b2d592f90704",
"submission_url": "/api/v1/sources/e5a42bdb-1fef-4d66-9876-b2d592f90704/submissions/b7a7b6ca-9a11-4a51-8b59-7e454f6bf8d0",
"uuid": "b7a7b6ca-9a11-4a51-8b59-7e454f6bf8d0"
},
{
"download_url": "/api/v1/sources/e5a42bdb-1fef-4d66-9876-b2d592f90704/submissions/00d24bed-8d13-4f90-b068-52341593a727/download",
"filename": "2-dark-haired_insolation-doc.gz.gpg",
"is_file": true,
"is_message": false,
"is_read": true,
"seen_by": [
"1c914871-a335-44ba-b2ae-da878cbc3630"
],
"size": 179404,
"source_url": "/api/v1/sources/e5a42bdb-1fef-4d66-9876-b2d592f90704",
"submission_url": "/api/v1/sources/e5a42bdb-1fef-4d66-9876-b2d592f90704/submissions/00d24bed-8d13-4f90-b068-52341593a727",
"uuid": "00d24bed-8d13-4f90-b068-52341593a727"
}
]
}
Get a single submission associated with a source¶
Requires authentication.
GET /api/v1/sources/<source_uuid>/submissions/<submission_uuid>
Response 200 (application/json):
{
"download_url": "/api/v1/sources/e5a42bdb-1fef-4d66-9876-b2d592f90704/submissions/00d24bed-8d13-4f90-b068-52341593a727/download",
"filename": "2-dark-haired_insolation-doc.gz.gpg",
"is_file": true,
"is_message": false,
"is_read": true,
"seen_by": [
"1c914871-a335-44ba-b2ae-da878cbc3630"
],
"size": 179404,
"source_url": "/api/v1/sources/e5a42bdb-1fef-4d66-9876-b2d592f90704",
"submission_url": "/api/v1/sources/e5a42bdb-1fef-4d66-9876-b2d592f90704/submissions/00d24bed-8d13-4f90-b068-52341593a727",
"uuid": "00d24bed-8d13-4f90-b068-52341593a727"
}
Get all replies associated with a source¶
Requires authentication.
GET /api/v1/sources/<source_uuid>/replies
Response 200 (application/json):
{
"replies": [
{
"filename": "3-electrocardiographic_lost-and-found-reply.gpg",
"is_deleted_by_source": false,
"journalist_first_name": "",
"journalist_last_name": "",
"journalist_username": "journalist",
"journalist_uuid": "3ae405e0-01bb-41f5-98b6-c4707c5c4b96",
"reply_url": "/api/v1/sources/55b96e66-688a-4333-b429-f1a3233b40e9/replies/5d6260ce-cf70-420a-9ca0-250b09d6cc58",
"seen_by": [
"3ae405e0-01bb-41f5-98b6-c4707c5c4b96"
],
"size": 753,
"source_url": "/api/v1/sources/55b96e66-688a-4333-b429-f1a3233b40e9",
"uuid": "5d6260ce-cf70-420a-9ca0-250b09d6cc58"
},
{
"filename": "4-electrocardiographic_lost-and-found-reply.gpg",
"is_deleted_by_source": false,
"journalist_first_name": "",
"journalist_last_name": "",
"journalist_username": "journalist",
"journalist_uuid": "3ae405e0-01bb-41f5-98b6-c4707c5c4b96",
"reply_url": "/api/v1/sources/55b96e66-688a-4333-b429-f1a3233b40e9/replies/3400b55f-9bfb-4368-b975-0f6950fd5631",
"seen_by": [
"3ae405e0-01bb-41f5-98b6-c4707c5c4b96"
],
"size": 901,
"source_url": "/api/v1/sources/55b96e66-688a-4333-b429-f1a3233b40e9",
"uuid": "3400b55f-9bfb-4368-b975-0f6950fd5631"
}
]
}
Get a single reply associated with a source¶
Requires authentication.
GET /api/v1/sources/<source_uuid>/replies/<reply_uuid>
Response 200 (application/json):
{
"filename": "4-electrocardiographic_lost-and-found-reply.gpg",
"is_deleted_by_source": false,
"journalist_first_name": "",
"journalist_last_name": "",
"journalist_username": "journalist",
"journalist_uuid": "3ae405e0-01bb-41f5-98b6-c4707c5c4b96",
"reply_url": "/api/v1/sources/55b96e66-688a-4333-b429-f1a3233b40e9/replies/3400b55f-9bfb-4368-b975-0f6950fd5631",
"seen_by": [
"3ae405e0-01bb-41f5-98b6-c4707c5c4b96"
],
"size": 901,
"source_url": "/api/v1/sources/55b96e66-688a-4333-b429-f1a3233b40e9",
"uuid": "3400b55f-9bfb-4368-b975-0f6950fd5631"
}
Download a reply¶
Requires authentication.
GET /api/v1/sources/<source_uuid>/replies/<reply_uuid>/download
Response 200 will have Content-Type: application/pgp-encrypted
and is the
content of the PGP encrypted reply.
An ETag header is also present containing the SHA256 hash of the response data:
"sha256:c757c5aa263dc4a5a2bca8e7fe973367dbd2c1a6c780d19c0ba499e6b1b81efa"
Note that these are not intended for cryptographic purposes and are present for clients to check that downloads are not corrupted.
Delete a reply¶
Requires authentication.
DELETE /api/v1/sources/<source_uuid>/replies/<reply_uuid>
Response 200:
{
"message": "Reply deleted"
}
Add a reply to a source¶
Requires authentication. Clients are expected to encrypt replies prior to submission to the server. Replies should be encrypted to the public key of the source.
Including the uuid
field in the request is optional. Clients may want to
pre-set the uuid
so they can track in-flight messages.
POST /api/v1/sources/<source_uuid>/replies
with the reply in the request body:
{
"uuid": "0bc588dd-f613-4999-b21e-1cebbd9adc2c",
"reply": "-----BEGIN PGP MESSAGE-----[...]-----END PGP MESSAGE-----"
}
Response 201 created (application/json):
{
"message": "Your reply has been stored",
"uuid": "0bc588dd-f613-4999-b21e-1cebbd9adc2c"
}
The returned uuid
field is the UUID of the reply and can be used to
reference this reply later. If the client set the uuid
in the request,
this will have the same value.
Replies that do not contain a GPG encrypted message will be rejected:
Response 400 (application/json):
{
"message": "You must encrypt replies client side"
}
Delete a submission¶
Requires authentication.
DELETE /api/v1/sources/<source_uuid>/submissions/<submission_uuid>
Response 200:
{
"message": "Submission deleted"
}
Download a submission¶
Requires authentication.
GET /api/v1/sources/<source_uuid>/submissions/<submission_uuid>/download
Response 200 will have Content-Type: application/pgp-encrypted
and is the
content of the PGP encrypted submission.
An ETag header is also present containing the SHA256 hash of the response data:
"sha256:c757c5aa263dc4a5a2bca8e7fe973367dbd2c1a6c780d19c0ba499e6b1b81efa"
Note that these are not intended for cryptographic purposes and are present for clients to check that downloads are not corrupted.
Delete a source and all their associated submissions¶
Requires authentication.
DELETE /api/v1/sources/<source_uuid>
Response 200:
{
"message": "Source and submissions deleted"
}
Delete a source conversation (messages/files/replies) while preserving the source¶
Requires authentication.
DELETE /api/v1/sources/<source_uuid>/conversation
Response 200:
{
"message": "Source data deleted"
}
Star a source¶
Requires authentication.
POST /api/v1/sources/<source_uuid>/star
Response 201 created:
{
"message": "Star added"
}
Unstar a source¶
Requires authentication.
DELETE /api/v1/sources/<source_uuid>/star
Response 200:
{
"message": "Star removed"
}
Submissions¶
Get all submissions¶
Requires authentication. This gets details of all submissions across sources.
GET /api/v1/submissions
Response 200:
{
"submissions": [
{
"download_url": "/api/v1/sources/e5a42bdb-1fef-4d66-9876-b2d592f90704/submissions/b7a7b6ca-9a11-4a51-8b59-7e454f6bf8d0/download",
"filename": "1-dark-haired_insolation-msg.gpg",
"is_file": false,
"is_message": true,
"is_read": true,
"seen_by": [
"1c914871-a335-44ba-b2ae-da878cbc3630"
],
"size": 593,
"source_url": "/api/v1/sources/e5a42bdb-1fef-4d66-9876-b2d592f90704",
"submission_url": "/api/v1/sources/e5a42bdb-1fef-4d66-9876-b2d592f90704/submissions/b7a7b6ca-9a11-4a51-8b59-7e454f6bf8d0",
"uuid": "b7a7b6ca-9a11-4a51-8b59-7e454f6bf8d0"
},
{
"download_url": "/api/v1/sources/e5a42bdb-1fef-4d66-9876-b2d592f90704/submissions/00d24bed-8d13-4f90-b068-52341593a727/download",
"filename": "2-dark-haired_insolation-doc.gz.gpg",
"is_file": true,
"is_message": false,
"is_read": true,
"seen_by": [
"1c914871-a335-44ba-b2ae-da878cbc3630"
],
"size": 179404,
"source_url": "/api/v1/sources/e5a42bdb-1fef-4d66-9876-b2d592f90704",
"submission_url": "/api/v1/sources/e5a42bdb-1fef-4d66-9876-b2d592f90704/submissions/00d24bed-8d13-4f90-b068-52341593a727",
"uuid": "00d24bed-8d13-4f90-b068-52341593a727"
}
]
}
Replies¶
Get all replies¶
Requires authentication. This gets details of all replies across sources.
GET /api/v1/replies
Response 200:
{
"replies": [
{
"filename": "3-electrocardiographic_lost-and-found-reply.gpg",
"is_deleted_by_source": false,
"journalist_first_name": "",
"journalist_last_name": "",
"journalist_username": "journalist",
"journalist_uuid": "3ae405e0-01bb-41f5-98b6-c4707c5c4b96",
"reply_url": "/api/v1/sources/55b96e66-688a-4333-b429-f1a3233b40e9/replies/5d6260ce-cf70-420a-9ca0-250b09d6cc58",
"seen_by": [
"3ae405e0-01bb-41f5-98b6-c4707c5c4b96"
],
"size": 753,
"source_url": "/api/v1/sources/55b96e66-688a-4333-b429-f1a3233b40e9",
"uuid": "5d6260ce-cf70-420a-9ca0-250b09d6cc58"
},
{
"filename": "3-dark-haired_insolation-reply.gpg",
"is_deleted_by_source": false,
"journalist_first_name": "",
"journalist_last_name": "",
"journalist_username": "journalist",
"journalist_uuid": "3ae405e0-01bb-41f5-98b6-c4707c5c4b96",
"reply_url": "/api/v1/sources/e5a42bdb-1fef-4d66-9876-b2d592f90704/replies/285682f8-2bfb-47aa-9889-f9c41a44cebb",
"seen_by": [
"3ae405e0-01bb-41f5-98b6-c4707c5c4b96",
"1c914871-a335-44ba-b2ae-da878cbc3630"
],
"size": 744,
"source_url": "/api/v1/sources/e5a42bdb-1fef-4d66-9876-b2d592f90704",
"uuid": "285682f8-2bfb-47aa-9889-f9c41a44cebb"
}
]
}
Users¶
Get a list of all users¶
Requires authentication.
GET /api/v1/users
Response 200:
{
"users": [
{
"first_name": "Nellie",
"last_name": "Bly",
"username": "nbly",
"uuid": "2b3f05ef-3695-4522-88bd-f124d2e89d01"
},
{
"first_name": "Daniel",
"last_name": "Ellsberg",
"username": "dellsberg",
"uuid": "89eec426-f8c3-4c7a-921f-59ec8fa9fd69"
}
]
}
Get an object representing the current user¶
Requires authentication.
GET /api/v1/user
Response 200:
{
"is_admin": true,
"last_login": "2018-07-09T20:29:41.696782Z",
"username": "journalist",
"uuid": "a2405127-1c9e-4a3a-80ea-95f6a71e5738",
"first_name": "Bob",
"last_name": "Smith",
}
Mark items that have been seen by the current user¶
Requires authentication. Records that the current user has seen a reply from another user, or a file or message submitted by a source.
POST /api/v1/seen
The request body should contain one or more lists of UUIDs
representing the conversation items to be marked seen. The valid list
keys are files
, messages
, and replies
. The type of a given
submission (file or message) is available in the responses from
endpoints under /submissions
; each submission will have
is_file
and is_message
fields.
{
"files": [
"00d24bed-8d13-4f90-b068-52341593a727"
],
"messages": [
"b7a7b6ca-9a11-4a51-8b59-7e454f6bf8d0"
],
"replies": [
"285682f8-2bfb-47aa-9889-f9c41a44cebb"
]
}
Any of the lists may be omitted, but at least one must be specified. An empty or invalid request will result in a 400 Bad Request
response with the following body:
{
"error": "Bad Request",
"message": "Please specify the resources to mark seen."
}
A successful request will result in a 200 OK
response with the
following body:
{
"message": "resources marked seen"
}
Any submission or reply marked seen will thereafter include the user’s
UUID in the seen_by
field of responses including the item, like
/api/v1/submissions
or /api/v1/replies
.
If a file, message, or reply cannot be found with one of the specified
UUIDs, the response will be 404 Not Found
with details in the
response body:
{
"error": "Not Found",
"message": "reply not found: 285682f8-2bfb-47aa-9889-f9c41a44cebc"
}
None of the requested items will be marked seen if any of them cannot be found.
Removed functionality¶
Flagging sources¶
Previous versions of the API supported flagging sources for reply, which would generate a reply keypair for the source upon their next login. This functionality was removed in SecureDrop 2.0.0.
The /api/v1/sources/<source_uuid>/flag
endpoint (POST
) and the
is_flagged
property for sources are retained for backwards compatibility,
but no longer function. is_flagged
is always false
.
The endpoint and the is_flagged
property will be fully removed from the API
in a future release.