-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature - Manage payloads #2989
Feature - Manage payloads #2989
Conversation
8016b60
to
3e9e877
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See inline comments for minor requested changes.
Tested locally, all functionality works as detailed.
Overall looks great.
@jbaptperez Re-ping me when complete minor changes. TY! |
return file_name, file_path | ||
|
||
@staticmethod | ||
def __save_file(target_file_path: str, io_base_src: IOBase): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apologies, didnt notice this before but is this file saving method necessary over just using the file saving method from the File service (https://github.com/mitre/caldera/blob/master/app/service/file_svc.py#L65)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@elegantmoose, relevant remark.
Actually, it would be good to use it but I cannot directly.
When defining the post_payloads()
method (which indirectly calls __save_file()
), I used the @aiohttp_apispec.form_schema(PayloadCreateRequestSchema)
annotation in order to have a proper swagger form and documentation.
However, this annotation (hidden function) calls request.multipart()
before I even enter the post_payloads()
method, to check the form according to the given schema.
Then the file can be read from another special request
dictionary object (see aiohttp_apispec documentation).
I cannot read twice the multipart form using standard aiohttp methods because the second time, I get no data.
Therefore, I cannot the file_svc.save_multipart_file_upload()
or file_svc.save_file()
directly because they assume nothing has called the aiohttp
multipart methods yet.
However, I can try to do one of the following changes:
- Adapt the current
file_svc.save_multipart_file_upload()
so that according to the given parameters, the file will be read the aiohttp standard way or using a special aiohttp_apispec object produced by the@aiohttp_apispec.form_schema
annotation, - Add another dedicated method to handle the aiohttp_apispec file upload case.
In both cases, I would try to use as maximum common code as possible.
Note that the file_svc.save_multipart_file_upload()
method reads entirely the uploaded file and gives it as a payload
parameter to file_svc.save_file()
, which can lead to performance issues in the case of big files, but that's another story.
So tell me what you prefer (including another proposal).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like 2.
But only if not a big lift. Can you take a quick look but cap your effort, dont want to hold this PR up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@elegantmoose, I had a look to the file_svc.py
code.
It handles general file upload for other services or the (old v1?) API (I'm new to Cladera and I don't have the whole history).
Beside, this payload upload code looks the first API v2 file upload implementation (what is more, using aiohttp_apispec for swagger integration), and there are some global differences:
file_svc.py
(v1) handles file encoding (HTTP header) and encryption for storage as my v2 code doesn't,file_svc.py
(v1) looks to handle some particular cases (file storage path, file extension),- The v2 code follows the aiohttp_apispec to handle uploaded file, so the way the file is read is different than in
file_svc.py
(however, the implementation I made should supports big file).
Finally, I'm running out of time for this work.
Therefore, I propose the following:
- I only change the multipart form field name from payload to file to make my code as generic as possible,
- If you agree, you merge this PR, and one nows that there is a base code for general API v2 file upload using aiohttp_apispec,
- A future and distinct task / user story will handle a migration from v1 file upload to v2 in
file_svc.py
, with all features (file encoding, file encryption, aiohttp_apispec constraints for swagger).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@elegantmoose, I pushed the field name change (see point 1. above).
I saw you merged from master in the feature/manage-payloads branch: I can rebase it (+ git push --force
) to avoid a complex history if you want before validating this PR.
I'll create another PR for the GUI part (magma repository).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay yea, too much of additional lift for this PR. Thanks for looking into though.
Yea, feel free to rebase it.
Im happy with this PR, I would just like @clenk to do quick look over.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@elegantmoose, branch rebased and force pushed.
067e13a
to
78c819d
Compare
Looks good. Is Would be nice to have tests in https://github.com/mitre/caldera/blob/master/tests/api/v2/handlers/test_payloads_api.py for it, but I understand with the failing test harness.... Maybe in a future PR. Thank you for the contribution! |
Adds optional parameters: - sort: Sorts the returned list, - exclude_plugins: Excludes payloads of plugins (only retains data/payloads ones).
Adds the optional parameter: add_path: Adds the relative path to the payload, from the Caldera root directory.
78c819d
to
d150b0b
Compare
d150b0b
to
d8b03fc
Compare
@clenk, I fixed the incorrect You are right about tests, they are missing. |
Description
GET /payloads
: Adds optional GET parameters:sort
: Boolean, sorts payload names,exclude_plugins
: Boolean, excludes payloads fromplugins/<plugin-name/data/payloads
directories (onlydata/payloads
),add_path
: Boolean adds relative path to the payload from the caldera root,POST /payloads
: Add a payload todata/payloads
,DELETE /payloads/{name}
: Delete a payload fromdata/payloads
.This is the first PR (out of two) to add payload management (add/delete) directly from the Caldera user interface.
I'll send a second PR to the magma repository (which depends on this one) for the frontend part, once this one is merged.
Type of change
Please delete options that are not relevant.
How Has This Been Tested?
Please describe the tests that you ran to verify your changes.
As Python tests are broken for now, I only tested this code locally using the swagger, an HTTP client but also with a dedicated Vue.js frontend (next magma PR).
Checklist: