Publish v0.83

This commit is contained in:
MWedl 2023-05-12 08:39:02 +00:00
parent e873d45e7a
commit f63c1bf49a
49 changed files with 2079 additions and 1036 deletions

View File

@ -1,5 +1,16 @@
# Changelog
## v0.83 - 2023-05-12
* Fix parsing of nested markdown labels (link in footnote in image caption)
* On file not found during PDF rendering: add reference to finding/section in error message
* Add more languages
* Allow confiuring languages via setting PREFERRED_LANGUAGES
* Show current software version in license page
* Allow deleting users via UI
* Fix markdown code block alignment
* Update django to 4.2.1 (security release)
## v0.76 - 2023-05-02
* Release Community Edition
* Add license checks and enforce license limits

View File

@ -47,9 +47,10 @@ curl -s https://docs.sysreptor.com/install.sh | bash
Access your application at http://localhost:8000/.
Get detailed installation instructions at https://docs.sysreptor.com/setup/installation/.
![Create finding from template](https://docs.sysreptor.com/images/create_finding_from_template.gif)
![Export report as PDF](https://docs.sysreptor.com/images/export_project.gif)

5
SECURITY.md Normal file
View File

@ -0,0 +1,5 @@
# Disclosure Policy
This software project is within the scope of our disclosure policy: https://docs.syslifters.com/en/vulnerability-disclosure/
# Security Considerations
https://docs.sysreptor.com/insights/security-considerations/

View File

@ -57,7 +57,7 @@ THE SOFTWARE.
Django
4.2b1
4.2.1
BSD License
Copyright (c) Django Software Foundation and individual contributors.
All rights reserved.
@ -89,7 +89,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Pillow
9.4.0
9.5.0
Historical Permission Notice and Disclaimer (HPND)
The Python Imaging Library (PIL) is
@ -98,7 +98,7 @@ The Python Imaging Library (PIL) is
Pillow is the friendly PIL fork. It is
Copyright © 2010-2023 by Alex Clark and contributors
Copyright © 2010-2023 by Jeffrey A. Clark (Alex) and contributors.
Like PIL, Pillow is licensed under the open source HPND License:
@ -106,8 +106,8 @@ By obtaining, using, and/or copying this software and/or its associated
documentation, you agree that you have read, understood, and will comply
with the following terms and conditions:
Permission to use, copy, modify, and distribute this software and its
associated documentation for any purpose and without fee is hereby granted,
Permission to use, copy, modify and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appears in all copies, and that
both that copyright notice and this permission notice appear in supporting
documentation, and that the name of Secret Labs AB or the author not be
@ -815,32 +815,6 @@ the file ChangeLog history information documenting your changes. Please read
the FAQ for more information on the distribution of modified source versions.
PyJWT
2.6.0
MIT License
The MIT License (MIT)
Copyright (c) 2015-2022 José Padilla
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
adrf
0.1.0
MIT License
@ -1005,7 +979,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
attrs
22.2.0
23.1.0
MIT License
The MIT License (MIT)
@ -1031,7 +1005,7 @@ SOFTWARE.
billiard
3.6.4.0
4.1.0
BSD License
Copyright (c) 2006-2008, R Oudkerk and Contributors
@ -1065,7 +1039,7 @@ SUCH DAMAGE.
boto3
1.26.5
1.26.131
Apache Software License
Apache License
@ -1247,7 +1221,7 @@ Apache Software License
botocore
1.29.94
1.29.131
Apache Software License
Apache License
@ -1429,7 +1403,7 @@ Apache Software License
celery
5.2.7
5.3.0b2
BSD License
Copyright (c) 2015-2016 Ask Solem & contributors. All rights reserved.
Copyright (c) 2012-2014 GoPivotal, Inc. All rights reserved.
@ -1488,7 +1462,7 @@ Footnotes
certifi
2022.12.7
2023.5.7
Mozilla Public License 2.0 (MPL 2.0)
This package contains a modified version of ca-bundle.crt:
@ -1684,7 +1658,7 @@ SOFTWARE.
coverage
7.2.2
7.2.5
Apache Software License
Apache License
@ -1866,7 +1840,7 @@ Apache Software License
cryptography
39.0.2
40.0.2
Apache Software License; BSD License
This software is made available under the terms of *either* of the licenses
found in LICENSE.APACHE or LICENSE.BSD. Contributions to cryptography are made
@ -1911,7 +1885,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
debugpy
1.6.3
1.6.7
Eclipse Public License 2.0 (EPL-2.0); MIT License
debugpy
@ -2179,7 +2153,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
django-debug-toolbar
3.5.0
4.0.0
BSD License
Copyright (c) Rob Hudson and individual contributors.
All rights reserved.
@ -2211,7 +2185,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
django-filter
22.1
23.2
BSD License
Copyright (c) Alex Gaynor and individual contributors.
All rights reserved.
@ -2240,7 +2214,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
django-phonenumber-field
7.0.0
7.1.0
MIT License
Copyright (c) 2011 Stefan Foulis and contributors.
@ -2333,30 +2307,6 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
djangorestframework-simplejwt
5.2.2
MIT License
Copyright 2017 David Sanders
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
drf-nested-routers
0.93.4
Apache Software License
@ -2554,7 +2504,7 @@ third-party archives.
elastic-apm
6.14.0
6.15.1
BSD License
BSD 3-Clause License
@ -2690,7 +2640,7 @@ MIT License
fido2
1.1.0
1.1.1
Apache Software License; BSD License; Mozilla Public License 2.0 (MPL 2.0)
Copyright (c) 2018 Yubico AB
All rights reserved.
@ -2721,7 +2671,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
fonttools
4.39.2
4.39.3
MIT License
MIT License
@ -2994,7 +2944,7 @@ IN THE SOFTWARE.
jsonschema
4.17.0
4.17.3
MIT License
Copyright (c) 2013 Julian Berman
@ -3018,7 +2968,7 @@ THE SOFTWARE.
kombu
5.2.4
5.3.0b3
BSD License
Copyright (c) 2015-2016 Ask Solem & contributors. All rights reserved.
Copyright (c) 2012-2014 GoPivotal Inc & contributors. All rights reserved.
@ -3453,7 +3403,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
packaging
23.0
23.1
Apache Software License; BSD License
This software is made available under the terms of *either* of the licenses
found in LICENSE.APACHE or LICENSE.BSD. Contributions to this software is made
@ -3461,7 +3411,7 @@ under the terms of *both* these licenses.
phonenumberslite
8.13.7
8.13.11
Apache Software License
Apache License
Version 2.0, January 2004
@ -3642,7 +3592,7 @@ Apache Software License
pikepdf
6.0.2
7.2.0
Mozilla Public License 2.0 (MPL 2.0)
Mozilla Public License Version 2.0
==================================
@ -4020,7 +3970,7 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice
pillow-heif
0.7.2
0.10.1
GNU General Public License v2 (GPLv2)
Apache License
Version 2.0, January 2004
@ -4226,7 +4176,7 @@ GNU General Public License v2 (GPLv2)
playwright
1.28.0
1.33.0
Apache Software License
Apache License
Version 2.0, January 2004
@ -4490,58 +4440,344 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
psycopg2-binary
2.9.5
GNU Library or Lesser General Public License (LGPL)
psycopg2 and the LGPL
---------------------
psycopg
3.1.9
GNU Lesser General Public License v3 (LGPLv3)
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
psycopg2 is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
psycopg2 is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
In addition, as a special exception, the copyright holders give
permission to link this program with the OpenSSL library (or with
modified versions of OpenSSL that use the same license as OpenSSL),
and distribute linked combinations including the two.
You must obey the GNU Lesser General Public License in all respects for
all of the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the file(s),
but you are not obligated to do so. If you do not wish to do so, delete
this exception statement from your version. If you delete this exception
statement from all source files in the program, then also delete it here.
You should have received a copy of the GNU Lesser General Public License
along with psycopg2 (see the doc/ directory.)
If not, see <https://www.gnu.org/licenses/>.
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Alternative licenses
--------------------
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
The following BSD-like license applies (at your option) to the files following
the pattern ``psycopg/adapter*.{h,c}`` and ``psycopg/microprotocol*.{h,c}``:
0. Additional Definitions.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
2. Altered source versions must be plainly marked as such, and must not
be misrepresented as being the original software.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
3. This notice may not be removed or altered from any source distribution.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
psycopg-binary
3.1.9
GNU Lesser General Public License v3 (LGPLv3)
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
pycparser
@ -4577,7 +4813,7 @@ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pycryptodomex
3.15.0
3.17
Apache Software License; BSD License; Public Domain
The source code in PyCryptodome is partially in the public domain
and partially released under the BSD 2-Clause license.
@ -4643,7 +4879,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pydyf
0.5.0
0.6.0
BSD License
BSD 3-Clause License
@ -5075,6 +5311,32 @@ GNU General Public License v2 or later (GPLv2+); GNU Lesser General Public Licen
pypng
0.20220715.0
MIT License
LICENCE (MIT)
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
pyrsistent
0.19.3
MIT License
@ -5102,7 +5364,7 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
pytest
7.2.2
7.3.1
MIT License
The MIT License (MIT)
@ -5213,7 +5475,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pytest-xdist
3.0.2
3.2.1
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
@ -5294,7 +5556,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The above BSD License Applies to all code, even that also covered by Apache 2.0.
python-decouple
3.6
3.8
MIT License
The MIT License
@ -5351,7 +5613,7 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pytz
2022.7.1
2023.3
MIT License
Copyright (c) 2003-2019 Stuart Bishop <stuart@stuartbishop.net>
@ -5375,7 +5637,7 @@ DEALINGS IN THE SOFTWARE.
qrcode
7.3.1
7.4.2
BSD License
Copyright (c) 2011, Lincoln Loop
All rights reserved.
@ -5428,7 +5690,7 @@ from (http://code.google.com/p/pyqrnative):
requests
2.28.2
2.30.0
Apache Software License
Apache License
@ -5626,7 +5888,7 @@ limitations under the License.
s3transfer
0.6.0
0.6.1
Apache Software License
Apache License
@ -5864,7 +6126,7 @@ made under the terms of *both* these licenses.
sqlparse
0.4.3
0.4.4
BSD License
Copyright (c) 2016, Andi Albrecht <albrecht.andi@gmail.com>
All rights reserved.
@ -6239,7 +6501,7 @@ SOFTWARE.
uvicorn
0.20.0
0.21.1
BSD License
Copyright © 2017-present, [Encode OSS Ltd](https://www.encode.io/).
All rights reserved.
@ -6328,7 +6590,7 @@ Footnotes
watchdog
2.2.0
3.0.0
Apache Software License
Copyright 2011 Yesudeep Mangalapilly <yesudeep@gmail.com>
Copyright 2012 Google, Inc & contributors.
@ -6386,7 +6648,7 @@ BSD License
UNKNOWN
whitenoise
6.2.0
6.4.0
MIT License
The MIT License (MIT)

View File

@ -11,6 +11,7 @@ allow_only="$allow_only;GNU General Public License v2 (GPLv2)"
allow_only="$allow_only;GNU General Public License v3 (GPLv3)"
allow_only="$allow_only;GNU Library or Lesser General Public License (LGPL)"
allow_only="$allow_only;GNU Lesser General Public License v2 or later (LGPLv2+)"
allow_only="$allow_only;GNU Lesser General Public License v3 (LGPLv3)"
allow_only="$allow_only;Mozilla Public License 1.0 (MPL)"
allow_only="$allow_only;Mozilla Public License 1.1 (MPL 1.1)"
allow_only="$allow_only;Mozilla Public License 2.0 (MPL 2.0)"

552
api/poetry.lock generated
View File

@ -69,22 +69,22 @@ tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"]
[[package]]
name = "attrs"
version = "22.2.0"
version = "23.1.0"
description = "Classes Without Boilerplate"
category = "main"
optional = false
python-versions = ">=3.6"
python-versions = ">=3.7"
files = [
{file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"},
{file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"},
{file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"},
{file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"},
]
[package.extras]
cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"]
dev = ["attrs[docs,tests]"]
docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"]
tests = ["attrs[tests-no-zope]", "zope.interface"]
tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"]
cov = ["attrs[tests]", "coverage[toml] (>=5.3)"]
dev = ["attrs[docs,tests]", "pre-commit"]
docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"]
tests = ["attrs[tests-no-zope]", "zope-interface"]
tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
[[package]]
name = "authlib"
@ -103,30 +103,30 @@ cryptography = ">=3.2"
[[package]]
name = "billiard"
version = "3.6.4.0"
version = "4.1.0"
description = "Python multiprocessing fork with improvements and bugfixes"
category = "main"
optional = false
python-versions = "*"
python-versions = ">=3.7"
files = [
{file = "billiard-3.6.4.0-py3-none-any.whl", hash = "sha256:87103ea78fa6ab4d5c751c4909bcff74617d985de7fa8b672cf8618afd5a875b"},
{file = "billiard-3.6.4.0.tar.gz", hash = "sha256:299de5a8da28a783d51b197d496bef4f1595dd023a93a4f59dde1886ae905547"},
{file = "billiard-4.1.0-py3-none-any.whl", hash = "sha256:0f50d6be051c6b2b75bfbc8bfd85af195c5739c281d3f5b86a5640c65563614a"},
{file = "billiard-4.1.0.tar.gz", hash = "sha256:1ad2eeae8e28053d729ba3373d34d9d6e210f6e4d8bf0a9c64f92bd053f1edf5"},
]
[[package]]
name = "boto3"
version = "1.26.110"
version = "1.26.131"
description = "The AWS SDK for Python"
category = "main"
optional = false
python-versions = ">= 3.7"
files = [
{file = "boto3-1.26.110-py3-none-any.whl", hash = "sha256:8972a5e0a04ea6f477c41e390765a46ec7bcffb62f99d4a0774ce70fb87bea59"},
{file = "boto3-1.26.110.tar.gz", hash = "sha256:97d942d958cac28687187b89ee88ac760e0fa3007094cb1d6b16e241144306f3"},
{file = "boto3-1.26.131-py3-none-any.whl", hash = "sha256:5b2b13d9f3430e3d5e768bf32097d5d6d16f47a4719f2656de67da49dd3e4de1"},
{file = "boto3-1.26.131.tar.gz", hash = "sha256:061d3270472b9be09901bb08a45e9871ac8f86a9b1c9c615535ca0223acd7582"},
]
[package.dependencies]
botocore = ">=1.29.110,<1.30.0"
botocore = ">=1.29.131,<1.30.0"
jmespath = ">=0.7.1,<2.0.0"
s3transfer = ">=0.6.0,<0.7.0"
@ -135,14 +135,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"]
[[package]]
name = "botocore"
version = "1.29.110"
version = "1.29.131"
description = "Low-level, data-driven core of boto 3."
category = "main"
optional = false
python-versions = ">= 3.7"
files = [
{file = "botocore-1.29.110-py3-none-any.whl", hash = "sha256:39879fcc3d263513f9ba92cc5060b5a4dbe54f758a917be29c7a71132e34f399"},
{file = "botocore-1.29.110.tar.gz", hash = "sha256:9d5054159782b19f27bff3e5a65bc494dc323255e889ea3abec002711a1fb0c0"},
{file = "botocore-1.29.131-py3-none-any.whl", hash = "sha256:d0dea23bccdfd7c2f6d0cd3216cfbd7065bc3e9e7b1ef6fee0952b04f5d2cffd"},
{file = "botocore-1.29.131.tar.gz", hash = "sha256:ffbd85915b2624c545438a33c2624a809593720a10648f6e757fe50be4893188"},
]
[package.dependencies]
@ -290,70 +290,70 @@ cffi = ">=1.0.0"
[[package]]
name = "celery"
version = "5.2.7"
version = "5.3.0b2"
description = "Distributed Task Queue."
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "celery-5.2.7-py3-none-any.whl", hash = "sha256:138420c020cd58d6707e6257b6beda91fd39af7afde5d36c6334d175302c0e14"},
{file = "celery-5.2.7.tar.gz", hash = "sha256:fafbd82934d30f8a004f81e8f7a062e31413a23d444be8ee3326553915958c6d"},
{file = "celery-5.3.0b2-py3-none-any.whl", hash = "sha256:b034f1e6475a90cf3e8c47357f132d0ed23fede22206ef5fc78b91f40f43ad67"},
{file = "celery-5.3.0b2.tar.gz", hash = "sha256:9ca1c46c40a5fd0946783d3a5a1ee532e283a586b1eeebd88a40a17af757a875"},
]
[package.dependencies]
billiard = ">=3.6.4.0,<4.0"
click = ">=8.0.3,<9.0"
click-didyoumean = ">=0.0.3"
billiard = ">=4.1.0,<5.0"
click = ">=8.1.2,<9.0"
click-didyoumean = ">=0.3.0"
click-plugins = ">=1.1.1"
click-repl = ">=0.2.0"
kombu = ">=5.2.3,<6.0"
kombu = ">=5.3.0b2,<6.0"
librabbitmq = {version = ">=1.5.0", optional = true, markers = "extra == \"librabbitmq\""}
pytz = ">=2021.3"
vine = ">=5.0.0,<6.0"
[package.extras]
arangodb = ["pyArango (>=1.3.2)"]
auth = ["cryptography"]
azureblockblob = ["azure-storage-blob (==12.9.0)"]
arangodb = ["pyArango (>=2.0.1)"]
auth = ["cryptography (==39.0.0)"]
azureblockblob = ["azure-storage-blob (>=12.11.0)"]
brotli = ["brotli (>=1.0.0)", "brotlipy (>=0.7.0)"]
cassandra = ["cassandra-driver (<3.21.0)"]
consul = ["python-consul2"]
cosmosdbsql = ["pydocumentdb (==2.3.2)"]
cassandra = ["cassandra-driver (>=3.25.0,<4)"]
consul = ["python-consul2 (==0.1.5)"]
cosmosdbsql = ["pydocumentdb (==2.3.5)"]
couchbase = ["couchbase (>=3.0.0)"]
couchdb = ["pycouchdb"]
couchdb = ["pycouchdb (==1.14.2)"]
django = ["Django (>=1.11)"]
dynamodb = ["boto3 (>=1.9.178)"]
elasticsearch = ["elasticsearch"]
dynamodb = ["boto3 (>=1.22.2)"]
elasticsearch = ["elasticsearch (<8.0)"]
eventlet = ["eventlet (>=0.32.0)"]
gevent = ["gevent (>=1.5.0)"]
librabbitmq = ["librabbitmq (>=1.5.0)"]
memcache = ["pylibmc"]
mongodb = ["pymongo[srv] (>=3.11.1)"]
msgpack = ["msgpack"]
pymemcache = ["python-memcached"]
pyro = ["pyro4"]
pytest = ["pytest-celery"]
redis = ["redis (>=3.4.1,!=4.0.0,!=4.0.1)"]
memcache = ["pylibmc (==1.6.3)"]
mongodb = ["pymongo[srv] (>=4.0.2)"]
msgpack = ["msgpack (==1.0.4)"]
pymemcache = ["python-memcached (==1.59)"]
pyro = ["pyro4 (==4.82)"]
pytest = ["pytest-celery (==0.0.0)"]
redis = ["redis (>=4.2.2,<4.4.0)"]
s3 = ["boto3 (>=1.9.125)"]
slmq = ["softlayer-messaging (>=1.0.3)"]
solar = ["ephem"]
sqlalchemy = ["sqlalchemy"]
sqs = ["kombu[sqs]"]
solar = ["ephem (>=4.1.3,<4.2.0)"]
sqlalchemy = ["sqlalchemy (==1.4.45)"]
sqs = ["kombu[sqs] (>=5.2.4,<5.3.0)"]
tblib = ["tblib (>=1.3.0)", "tblib (>=1.5.0)"]
yaml = ["PyYAML (>=3.10)"]
zookeeper = ["kazoo (>=1.3.1)"]
zstd = ["zstandard"]
zstd = ["zstandard (==0.19.0)"]
[[package]]
name = "certifi"
version = "2022.12.7"
version = "2023.5.7"
description = "Python package for providing Mozilla's CA Bundle."
category = "main"
optional = false
python-versions = ">=3.6"
files = [
{file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"},
{file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"},
{file = "certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"},
{file = "certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"},
]
[[package]]
@ -597,63 +597,63 @@ files = [
[[package]]
name = "coverage"
version = "7.2.3"
version = "7.2.5"
description = "Code coverage measurement for Python"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "coverage-7.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e58c0d41d336569d63d1b113bd573db8363bc4146f39444125b7f8060e4e04f5"},
{file = "coverage-7.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:344e714bd0fe921fc72d97404ebbdbf9127bac0ca1ff66d7b79efc143cf7c0c4"},
{file = "coverage-7.2.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:974bc90d6f6c1e59ceb1516ab00cf1cdfbb2e555795d49fa9571d611f449bcb2"},
{file = "coverage-7.2.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0743b0035d4b0e32bc1df5de70fba3059662ace5b9a2a86a9f894cfe66569013"},
{file = "coverage-7.2.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d0391fb4cfc171ce40437f67eb050a340fdbd0f9f49d6353a387f1b7f9dd4fa"},
{file = "coverage-7.2.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4a42e1eff0ca9a7cb7dc9ecda41dfc7cbc17cb1d02117214be0561bd1134772b"},
{file = "coverage-7.2.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:be19931a8dcbe6ab464f3339966856996b12a00f9fe53f346ab3be872d03e257"},
{file = "coverage-7.2.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:72fcae5bcac3333a4cf3b8f34eec99cea1187acd55af723bcbd559adfdcb5535"},
{file = "coverage-7.2.3-cp310-cp310-win32.whl", hash = "sha256:aeae2aa38395b18106e552833f2a50c27ea0000122bde421c31d11ed7e6f9c91"},
{file = "coverage-7.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:83957d349838a636e768251c7e9979e899a569794b44c3728eaebd11d848e58e"},
{file = "coverage-7.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dfd393094cd82ceb9b40df4c77976015a314b267d498268a076e940fe7be6b79"},
{file = "coverage-7.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:182eb9ac3f2b4874a1f41b78b87db20b66da6b9cdc32737fbbf4fea0c35b23fc"},
{file = "coverage-7.2.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bb1e77a9a311346294621be905ea8a2c30d3ad371fc15bb72e98bfcfae532df"},
{file = "coverage-7.2.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca0f34363e2634deffd390a0fef1aa99168ae9ed2af01af4a1f5865e362f8623"},
{file = "coverage-7.2.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55416d7385774285b6e2a5feca0af9652f7f444a4fa3d29d8ab052fafef9d00d"},
{file = "coverage-7.2.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:06ddd9c0249a0546997fdda5a30fbcb40f23926df0a874a60a8a185bc3a87d93"},
{file = "coverage-7.2.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fff5aaa6becf2c6a1699ae6a39e2e6fb0672c2d42eca8eb0cafa91cf2e9bd312"},
{file = "coverage-7.2.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ea53151d87c52e98133eb8ac78f1206498c015849662ca8dc246255265d9c3c4"},
{file = "coverage-7.2.3-cp311-cp311-win32.whl", hash = "sha256:8f6c930fd70d91ddee53194e93029e3ef2aabe26725aa3c2753df057e296b925"},
{file = "coverage-7.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:fa546d66639d69aa967bf08156eb8c9d0cd6f6de84be9e8c9819f52ad499c910"},
{file = "coverage-7.2.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2317d5ed777bf5a033e83d4f1389fd4ef045763141d8f10eb09a7035cee774c"},
{file = "coverage-7.2.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be9824c1c874b73b96288c6d3de793bf7f3a597770205068c6163ea1f326e8b9"},
{file = "coverage-7.2.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c3b2803e730dc2797a017335827e9da6da0e84c745ce0f552e66400abdfb9a1"},
{file = "coverage-7.2.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f69770f5ca1994cb32c38965e95f57504d3aea96b6c024624fdd5bb1aa494a1"},
{file = "coverage-7.2.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1127b16220f7bfb3f1049ed4a62d26d81970a723544e8252db0efde853268e21"},
{file = "coverage-7.2.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:aa784405f0c640940595fa0f14064d8e84aff0b0f762fa18393e2760a2cf5841"},
{file = "coverage-7.2.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3146b8e16fa60427e03884301bf8209221f5761ac754ee6b267642a2fd354c48"},
{file = "coverage-7.2.3-cp37-cp37m-win32.whl", hash = "sha256:1fd78b911aea9cec3b7e1e2622c8018d51c0d2bbcf8faaf53c2497eb114911c1"},
{file = "coverage-7.2.3-cp37-cp37m-win_amd64.whl", hash = "sha256:0f3736a5d34e091b0a611964c6262fd68ca4363df56185902528f0b75dbb9c1f"},
{file = "coverage-7.2.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:981b4df72c93e3bc04478153df516d385317628bd9c10be699c93c26ddcca8ab"},
{file = "coverage-7.2.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0045f8f23a5fb30b2eb3b8a83664d8dc4fb58faddf8155d7109166adb9f2040"},
{file = "coverage-7.2.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f760073fcf8f3d6933178d67754f4f2d4e924e321f4bb0dcef0424ca0215eba1"},
{file = "coverage-7.2.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c86bd45d1659b1ae3d0ba1909326b03598affbc9ed71520e0ff8c31a993ad911"},
{file = "coverage-7.2.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:172db976ae6327ed4728e2507daf8a4de73c7cc89796483e0a9198fd2e47b462"},
{file = "coverage-7.2.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d2a3a6146fe9319926e1d477842ca2a63fe99af5ae690b1f5c11e6af074a6b5c"},
{file = "coverage-7.2.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f649dd53833b495c3ebd04d6eec58479454a1784987af8afb77540d6c1767abd"},
{file = "coverage-7.2.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7c4ed4e9f3b123aa403ab424430b426a1992e6f4c8fd3cb56ea520446e04d152"},
{file = "coverage-7.2.3-cp38-cp38-win32.whl", hash = "sha256:eb0edc3ce9760d2f21637766c3aa04822030e7451981ce569a1b3456b7053f22"},
{file = "coverage-7.2.3-cp38-cp38-win_amd64.whl", hash = "sha256:63cdeaac4ae85a179a8d6bc09b77b564c096250d759eed343a89d91bce8b6367"},
{file = "coverage-7.2.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:20d1a2a76bb4eb00e4d36b9699f9b7aba93271c9c29220ad4c6a9581a0320235"},
{file = "coverage-7.2.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ea748802cc0de4de92ef8244dd84ffd793bd2e7be784cd8394d557a3c751e21"},
{file = "coverage-7.2.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21b154aba06df42e4b96fc915512ab39595105f6c483991287021ed95776d934"},
{file = "coverage-7.2.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd214917cabdd6f673a29d708574e9fbdb892cb77eb426d0eae3490d95ca7859"},
{file = "coverage-7.2.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c2e58e45fe53fab81f85474e5d4d226eeab0f27b45aa062856c89389da2f0d9"},
{file = "coverage-7.2.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:87ecc7c9a1a9f912e306997ffee020297ccb5ea388421fe62a2a02747e4d5539"},
{file = "coverage-7.2.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:387065e420aed3c71b61af7e82c7b6bc1c592f7e3c7a66e9f78dd178699da4fe"},
{file = "coverage-7.2.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ea3f5bc91d7d457da7d48c7a732beaf79d0c8131df3ab278e6bba6297e23c6c4"},
{file = "coverage-7.2.3-cp39-cp39-win32.whl", hash = "sha256:ae7863a1d8db6a014b6f2ff9c1582ab1aad55a6d25bac19710a8df68921b6e30"},
{file = "coverage-7.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:3f04becd4fcda03c0160d0da9c8f0c246bc78f2f7af0feea1ec0930e7c93fa4a"},
{file = "coverage-7.2.3-pp37.pp38.pp39-none-any.whl", hash = "sha256:965ee3e782c7892befc25575fa171b521d33798132692df428a09efacaffe8d0"},
{file = "coverage-7.2.3.tar.gz", hash = "sha256:d298c2815fa4891edd9abe5ad6e6cb4207104c7dd9fd13aea3fdebf6f9b91259"},
{file = "coverage-7.2.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:883123d0bbe1c136f76b56276074b0c79b5817dd4238097ffa64ac67257f4b6c"},
{file = "coverage-7.2.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d2fbc2a127e857d2f8898aaabcc34c37771bf78a4d5e17d3e1f5c30cd0cbc62a"},
{file = "coverage-7.2.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f3671662dc4b422b15776cdca89c041a6349b4864a43aa2350b6b0b03bbcc7f"},
{file = "coverage-7.2.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780551e47d62095e088f251f5db428473c26db7829884323e56d9c0c3118791a"},
{file = "coverage-7.2.5-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:066b44897c493e0dcbc9e6a6d9f8bbb6607ef82367cf6810d387c09f0cd4fe9a"},
{file = "coverage-7.2.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b9a4ee55174b04f6af539218f9f8083140f61a46eabcaa4234f3c2a452c4ed11"},
{file = "coverage-7.2.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:706ec567267c96717ab9363904d846ec009a48d5f832140b6ad08aad3791b1f5"},
{file = "coverage-7.2.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ae453f655640157d76209f42c62c64c4d4f2c7f97256d3567e3b439bd5c9b06c"},
{file = "coverage-7.2.5-cp310-cp310-win32.whl", hash = "sha256:f81c9b4bd8aa747d417407a7f6f0b1469a43b36a85748145e144ac4e8d303cb5"},
{file = "coverage-7.2.5-cp310-cp310-win_amd64.whl", hash = "sha256:dc945064a8783b86fcce9a0a705abd7db2117d95e340df8a4333f00be5efb64c"},
{file = "coverage-7.2.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:40cc0f91c6cde033da493227797be2826cbf8f388eaa36a0271a97a332bfd7ce"},
{file = "coverage-7.2.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a66e055254a26c82aead7ff420d9fa8dc2da10c82679ea850d8feebf11074d88"},
{file = "coverage-7.2.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c10fbc8a64aa0f3ed136b0b086b6b577bc64d67d5581acd7cc129af52654384e"},
{file = "coverage-7.2.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a22cbb5ede6fade0482111fa7f01115ff04039795d7092ed0db43522431b4f2"},
{file = "coverage-7.2.5-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:292300f76440651529b8ceec283a9370532f4ecba9ad67d120617021bb5ef139"},
{file = "coverage-7.2.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7ff8f3fb38233035028dbc93715551d81eadc110199e14bbbfa01c5c4a43f8d8"},
{file = "coverage-7.2.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:a08c7401d0b24e8c2982f4e307124b671c6736d40d1c39e09d7a8687bddf83ed"},
{file = "coverage-7.2.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef9659d1cda9ce9ac9585c045aaa1e59223b143f2407db0eaee0b61a4f266fb6"},
{file = "coverage-7.2.5-cp311-cp311-win32.whl", hash = "sha256:30dcaf05adfa69c2a7b9f7dfd9f60bc8e36b282d7ed25c308ef9e114de7fc23b"},
{file = "coverage-7.2.5-cp311-cp311-win_amd64.whl", hash = "sha256:97072cc90f1009386c8a5b7de9d4fc1a9f91ba5ef2146c55c1f005e7b5c5e068"},
{file = "coverage-7.2.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bebea5f5ed41f618797ce3ffb4606c64a5de92e9c3f26d26c2e0aae292f015c1"},
{file = "coverage-7.2.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:828189fcdda99aae0d6bf718ea766b2e715eabc1868670a0a07bf8404bf58c33"},
{file = "coverage-7.2.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e8a95f243d01ba572341c52f89f3acb98a3b6d1d5d830efba86033dd3687ade"},
{file = "coverage-7.2.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8834e5f17d89e05697c3c043d3e58a8b19682bf365048837383abfe39adaed5"},
{file = "coverage-7.2.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d1f25ee9de21a39b3a8516f2c5feb8de248f17da7eead089c2e04aa097936b47"},
{file = "coverage-7.2.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1637253b11a18f453e34013c665d8bf15904c9e3c44fbda34c643fbdc9d452cd"},
{file = "coverage-7.2.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8e575a59315a91ccd00c7757127f6b2488c2f914096077c745c2f1ba5b8c0969"},
{file = "coverage-7.2.5-cp37-cp37m-win32.whl", hash = "sha256:509ecd8334c380000d259dc66feb191dd0a93b21f2453faa75f7f9cdcefc0718"},
{file = "coverage-7.2.5-cp37-cp37m-win_amd64.whl", hash = "sha256:12580845917b1e59f8a1c2ffa6af6d0908cb39220f3019e36c110c943dc875b0"},
{file = "coverage-7.2.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b5016e331b75310610c2cf955d9f58a9749943ed5f7b8cfc0bb89c6134ab0a84"},
{file = "coverage-7.2.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:373ea34dca98f2fdb3e5cb33d83b6d801007a8074f992b80311fc589d3e6b790"},
{file = "coverage-7.2.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a063aad9f7b4c9f9da7b2550eae0a582ffc7623dca1c925e50c3fbde7a579771"},
{file = "coverage-7.2.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38c0a497a000d50491055805313ed83ddba069353d102ece8aef5d11b5faf045"},
{file = "coverage-7.2.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2b3b05e22a77bb0ae1a3125126a4e08535961c946b62f30985535ed40e26614"},
{file = "coverage-7.2.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0342a28617e63ad15d96dca0f7ae9479a37b7d8a295f749c14f3436ea59fdcb3"},
{file = "coverage-7.2.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf97ed82ca986e5c637ea286ba2793c85325b30f869bf64d3009ccc1a31ae3fd"},
{file = "coverage-7.2.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c2c41c1b1866b670573657d584de413df701f482574bad7e28214a2362cb1fd1"},
{file = "coverage-7.2.5-cp38-cp38-win32.whl", hash = "sha256:10b15394c13544fce02382360cab54e51a9e0fd1bd61ae9ce012c0d1e103c813"},
{file = "coverage-7.2.5-cp38-cp38-win_amd64.whl", hash = "sha256:a0b273fe6dc655b110e8dc89b8ec7f1a778d78c9fd9b4bda7c384c8906072212"},
{file = "coverage-7.2.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c587f52c81211d4530fa6857884d37f514bcf9453bdeee0ff93eaaf906a5c1b"},
{file = "coverage-7.2.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4436cc9ba5414c2c998eaedee5343f49c02ca93b21769c5fdfa4f9d799e84200"},
{file = "coverage-7.2.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6599bf92f33ab041e36e06d25890afbdf12078aacfe1f1d08c713906e49a3fe5"},
{file = "coverage-7.2.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:857abe2fa6a4973f8663e039ead8d22215d31db613ace76e4a98f52ec919068e"},
{file = "coverage-7.2.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6f5cab2d7f0c12f8187a376cc6582c477d2df91d63f75341307fcdcb5d60303"},
{file = "coverage-7.2.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:aa387bd7489f3e1787ff82068b295bcaafbf6f79c3dad3cbc82ef88ce3f48ad3"},
{file = "coverage-7.2.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:156192e5fd3dbbcb11cd777cc469cf010a294f4c736a2b2c891c77618cb1379a"},
{file = "coverage-7.2.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bd3b4b8175c1db502adf209d06136c000df4d245105c8839e9d0be71c94aefe1"},
{file = "coverage-7.2.5-cp39-cp39-win32.whl", hash = "sha256:ddc5a54edb653e9e215f75de377354e2455376f416c4378e1d43b08ec50acc31"},
{file = "coverage-7.2.5-cp39-cp39-win_amd64.whl", hash = "sha256:338aa9d9883aaaad53695cb14ccdeb36d4060485bb9388446330bef9c361c252"},
{file = "coverage-7.2.5-pp37.pp38.pp39-none-any.whl", hash = "sha256:8877d9b437b35a85c18e3c6499b23674684bf690f5d96c1006a1ef61f9fdf0f3"},
{file = "coverage-7.2.5.tar.gz", hash = "sha256:f99ef080288f09ffc687423b8d60978cf3a465d3f404a18d1a05474bd8575a47"},
]
[package.dependencies]
@ -664,31 +664,31 @@ toml = ["tomli"]
[[package]]
name = "cryptography"
version = "40.0.1"
version = "40.0.2"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
category = "main"
optional = false
python-versions = ">=3.6"
files = [
{file = "cryptography-40.0.1-cp36-abi3-macosx_10_12_universal2.whl", hash = "sha256:918cb89086c7d98b1b86b9fdb70c712e5a9325ba6f7d7cfb509e784e0cfc6917"},
{file = "cryptography-40.0.1-cp36-abi3-macosx_10_12_x86_64.whl", hash = "sha256:9618a87212cb5200500e304e43691111570e1f10ec3f35569fdfcd17e28fd797"},
{file = "cryptography-40.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a4805a4ca729d65570a1b7cac84eac1e431085d40387b7d3bbaa47e39890b88"},
{file = "cryptography-40.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63dac2d25c47f12a7b8aa60e528bfb3c51c5a6c5a9f7c86987909c6c79765554"},
{file = "cryptography-40.0.1-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:0a4e3406cfed6b1f6d6e87ed243363652b2586b2d917b0609ca4f97072994405"},
{file = "cryptography-40.0.1-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1e0af458515d5e4028aad75f3bb3fe7a31e46ad920648cd59b64d3da842e4356"},
{file = "cryptography-40.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:d8aa3609d337ad85e4eb9bb0f8bcf6e4409bfb86e706efa9a027912169e89122"},
{file = "cryptography-40.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cf91e428c51ef692b82ce786583e214f58392399cf65c341bc7301d096fa3ba2"},
{file = "cryptography-40.0.1-cp36-abi3-win32.whl", hash = "sha256:650883cc064297ef3676b1db1b7b1df6081794c4ada96fa457253c4cc40f97db"},
{file = "cryptography-40.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:a805a7bce4a77d51696410005b3e85ae2839bad9aa38894afc0aa99d8e0c3160"},
{file = "cryptography-40.0.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cd033d74067d8928ef00a6b1327c8ea0452523967ca4463666eeba65ca350d4c"},
{file = "cryptography-40.0.1-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d36bbeb99704aabefdca5aee4eba04455d7a27ceabd16f3b3ba9bdcc31da86c4"},
{file = "cryptography-40.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:32057d3d0ab7d4453778367ca43e99ddb711770477c4f072a51b3ca69602780a"},
{file = "cryptography-40.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:f5d7b79fa56bc29580faafc2ff736ce05ba31feaa9d4735048b0de7d9ceb2b94"},
{file = "cryptography-40.0.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7c872413353c70e0263a9368c4993710070e70ab3e5318d85510cc91cce77e7c"},
{file = "cryptography-40.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:28d63d75bf7ae4045b10de5413fb1d6338616e79015999ad9cf6fc538f772d41"},
{file = "cryptography-40.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6f2bbd72f717ce33100e6467572abaedc61f1acb87b8d546001328d7f466b778"},
{file = "cryptography-40.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cc3a621076d824d75ab1e1e530e66e7e8564e357dd723f2533225d40fe35c60c"},
{file = "cryptography-40.0.1.tar.gz", hash = "sha256:2803f2f8b1e95f614419926c7e6f55d828afc614ca5ed61543877ae668cc3472"},
{file = "cryptography-40.0.2-cp36-abi3-macosx_10_12_universal2.whl", hash = "sha256:8f79b5ff5ad9d3218afb1e7e20ea74da5f76943ee5edb7f76e56ec5161ec782b"},
{file = "cryptography-40.0.2-cp36-abi3-macosx_10_12_x86_64.whl", hash = "sha256:05dc219433b14046c476f6f09d7636b92a1c3e5808b9a6536adf4932b3b2c440"},
{file = "cryptography-40.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4df2af28d7bedc84fe45bd49bc35d710aede676e2a4cb7fc6d103a2adc8afe4d"},
{file = "cryptography-40.0.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dcca15d3a19a66e63662dc8d30f8036b07be851a8680eda92d079868f106288"},
{file = "cryptography-40.0.2-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:a04386fb7bc85fab9cd51b6308633a3c271e3d0d3eae917eebab2fac6219b6d2"},
{file = "cryptography-40.0.2-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:adc0d980fd2760c9e5de537c28935cc32b9353baaf28e0814df417619c6c8c3b"},
{file = "cryptography-40.0.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:d5a1bd0e9e2031465761dfa920c16b0065ad77321d8a8c1f5ee331021fda65e9"},
{file = "cryptography-40.0.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:a95f4802d49faa6a674242e25bfeea6fc2acd915b5e5e29ac90a32b1139cae1c"},
{file = "cryptography-40.0.2-cp36-abi3-win32.whl", hash = "sha256:aecbb1592b0188e030cb01f82d12556cf72e218280f621deed7d806afd2113f9"},
{file = "cryptography-40.0.2-cp36-abi3-win_amd64.whl", hash = "sha256:b12794f01d4cacfbd3177b9042198f3af1c856eedd0a98f10f141385c809a14b"},
{file = "cryptography-40.0.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:142bae539ef28a1c76794cca7f49729e7c54423f615cfd9b0b1fa90ebe53244b"},
{file = "cryptography-40.0.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:956ba8701b4ffe91ba59665ed170a2ebbdc6fc0e40de5f6059195d9f2b33ca0e"},
{file = "cryptography-40.0.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4f01c9863da784558165f5d4d916093737a75203a5c5286fde60e503e4276c7a"},
{file = "cryptography-40.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3daf9b114213f8ba460b829a02896789751626a2a4e7a43a28ee77c04b5e4958"},
{file = "cryptography-40.0.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48f388d0d153350f378c7f7b41497a54ff1513c816bcbbcafe5b829e59b9ce5b"},
{file = "cryptography-40.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c0764e72b36a3dc065c155e5b22f93df465da9c39af65516fe04ed3c68c92636"},
{file = "cryptography-40.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:cbaba590180cba88cb99a5f76f90808a624f18b169b90a4abb40c1fd8c19420e"},
{file = "cryptography-40.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7a38250f433cd41df7fcb763caa3ee9362777fdb4dc642b9a349721d2bf47404"},
{file = "cryptography-40.0.2.tar.gz", hash = "sha256:c33c0d32b8594fa647d2e01dbccc303478e16fdd7cf98652d5b3ed11aa5e5c99"},
]
[package.dependencies]
@ -769,14 +769,14 @@ packaging = "*"
[[package]]
name = "django"
version = "4.2"
version = "4.2.1"
description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
category = "main"
optional = false
python-versions = ">=3.8"
files = [
{file = "Django-4.2-py3-none-any.whl", hash = "sha256:ad33ed68db9398f5dfb33282704925bce044bef4261cd4fb59e4e7f9ae505a78"},
{file = "Django-4.2.tar.gz", hash = "sha256:c36e2ab12824e2ac36afa8b2515a70c53c7742f0d6eaefa7311ec379558db997"},
{file = "Django-4.2.1-py3-none-any.whl", hash = "sha256:066b6debb5ac335458d2a713ed995570536c8b59a580005acb0732378d5eb1ee"},
{file = "Django-4.2.1.tar.gz", hash = "sha256:7efa6b1f781a6119a10ac94b4794ded90db8accbe7802281cd26f8664ffed59c"},
]
[package.dependencies]
@ -825,14 +825,14 @@ sqlparse = ">=0.2"
[[package]]
name = "django-filter"
version = "23.1"
version = "23.2"
description = "Django-filter is a reusable Django application for allowing users to filter querysets dynamically."
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "django-filter-23.1.tar.gz", hash = "sha256:dee5dcf2cea4d7f767e271b6d01f767fce7500676d5e5dc58dac8154000b87df"},
{file = "django_filter-23.1-py3-none-any.whl", hash = "sha256:e3c52ad83c32fb5882125105efb5fea2a1d6a85e7dc64b04ef52edbf14451b6c"},
{file = "django-filter-23.2.tar.gz", hash = "sha256:2fe15f78108475eda525692813205fa6f9e8c1caf1ae65daa5862d403c6dbf00"},
{file = "django_filter-23.2-py3-none-any.whl", hash = "sha256:d12d8e0fc6d3eb26641e553e5d53b191eb8cec611427d4bdce0becb1f7c172b5"},
]
[package.dependencies]
@ -840,14 +840,14 @@ Django = ">=3.2"
[[package]]
name = "django-phonenumber-field"
version = "7.0.2"
version = "7.1.0"
description = "An international phone number field for django models."
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "django-phonenumber-field-7.0.2.tar.gz", hash = "sha256:de3e47b986b4959949762c16fd8fe26b3e462ef3e5531ed00950bd20c698576a"},
{file = "django_phonenumber_field-7.0.2-py3-none-any.whl", hash = "sha256:9edad2b2602af25f2aefc73c4cf53eaf7abf9e17d73c1c4372bd3052bebb26f9"},
{file = "django-phonenumber-field-7.1.0.tar.gz", hash = "sha256:63721dbdc7424cd594a08d80f550e790cf6e7c903cbc0fb4dd9d86baac8b8c51"},
{file = "django_phonenumber_field-7.1.0-py3-none-any.whl", hash = "sha256:4eaab35fe9a163046dc3a47188771385c56a788e0e11b7bbcc662e1e6b7b9104"},
]
[package.dependencies]
@ -1251,35 +1251,36 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-
[[package]]
name = "kombu"
version = "5.2.4"
version = "5.3.0b3"
description = "Messaging library for Python."
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "kombu-5.2.4-py3-none-any.whl", hash = "sha256:8b213b24293d3417bcf0d2f5537b7f756079e3ea232a8386dcc89a59fd2361a4"},
{file = "kombu-5.2.4.tar.gz", hash = "sha256:37cee3ee725f94ea8bb173eaab7c1760203ea53bbebae226328600f9d2799610"},
{file = "kombu-5.3.0b3-py3-none-any.whl", hash = "sha256:4ad23178dcd11192672d1fad598ace737d1044dbf31edf335a800ed26a9fb2fb"},
{file = "kombu-5.3.0b3.tar.gz", hash = "sha256:316df5e840f284d0671b9000bbf747da2b00f3b81433c720de66a5f659e5711d"},
]
[package.dependencies]
amqp = ">=5.0.9,<6.0.0"
amqp = ">=5.1.1,<6.0.0"
vine = "*"
[package.extras]
azureservicebus = ["azure-servicebus (>=7.0.0)"]
azurestoragequeues = ["azure-storage-queue"]
consul = ["python-consul (>=0.6.0)"]
azureservicebus = ["azure-servicebus (>=7.8.3)"]
azurestoragequeues = ["azure-identity (>=1.12.0)", "azure-storage-queue (>=12.6.0)"]
confluentkafka = ["confluent-kafka (>=1.9.0,<1.10.0)"]
consul = ["python-consul2"]
librabbitmq = ["librabbitmq (>=2.0.0)"]
mongodb = ["pymongo (>=3.3.0,<3.12.1)"]
mongodb = ["pymongo (>=4.1.1)"]
msgpack = ["msgpack"]
pyro = ["pyro4"]
pyro = ["pyro5"]
qpid = ["qpid-python (>=0.26)", "qpid-tools (>=0.26)"]
redis = ["redis (>=3.4.1,!=4.0.0,!=4.0.1)"]
redis = ["redis (>=4.2.2,<4.4.0)"]
slmq = ["softlayer-messaging (>=1.0.3)"]
sqlalchemy = ["sqlalchemy"]
sqs = ["boto3 (>=1.9.12)", "pycurl (>=7.44.1,<7.45.0)", "urllib3 (>=1.26.7)"]
sqlalchemy = ["sqlalchemy (>=1.4.47,<2.1)"]
sqs = ["boto3 (>=1.22.2)", "pycurl (>=7.44.1,<7.45.0)", "urllib3 (>=1.26.9)"]
yaml = ["PyYAML (>=3.10)"]
zookeeper = ["kazoo (>=1.3.1)"]
zookeeper = ["kazoo (>=2.8.0)"]
[[package]]
name = "librabbitmq"
@ -1411,69 +1412,69 @@ source = ["Cython (>=0.29.7)"]
[[package]]
name = "packaging"
version = "23.0"
version = "23.1"
description = "Core utilities for Python packages"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"},
{file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"},
{file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"},
{file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"},
]
[[package]]
name = "phonenumberslite"
version = "8.13.9"
version = "8.13.11"
description = "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers."
category = "main"
optional = false
python-versions = "*"
files = [
{file = "phonenumberslite-8.13.9-py2.py3-none-any.whl", hash = "sha256:20ea42c4fa86fd032200692587cb45bf2028ac5ec1e756d1c4b76b42fa4370bf"},
{file = "phonenumberslite-8.13.9.tar.gz", hash = "sha256:f5f2333e8a3a2e45917796c258ce1742341c731feb4dd92dab3e773118ab24d0"},
{file = "phonenumberslite-8.13.11-py2.py3-none-any.whl", hash = "sha256:90e7ad011dc571c9ba76a0816d7fc92a7de8944dcb273f074edfb48f20f18f75"},
{file = "phonenumberslite-8.13.11.tar.gz", hash = "sha256:9d8162427baa4a0fdcb4902c5ca5936d2c165374c0dc6693227c68e5852d5c88"},
]
[[package]]
name = "pikepdf"
version = "7.1.2"
version = "7.2.0"
description = "Read and write PDFs with Python, powered by qpdf"
category = "main"
optional = false
python-versions = ">=3.8"
files = [
{file = "pikepdf-7.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:81950bde71eeaa1fbef72164cf4c78f408250bdb2346e4a69aebe1fe0631c47b"},
{file = "pikepdf-7.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c7b5c328dda0f0f3de4fbfbf3f1f68a85cb957eed00a4bd2f7683a465dc5b5a"},
{file = "pikepdf-7.1.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:51a9272db7a468476f74c39c0fa5dc6b501e298c709a4b8df8e4b393929d644a"},
{file = "pikepdf-7.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b21521fc51194869027edbdcaf46cf20396344518b122085133c68ddd1dd770f"},
{file = "pikepdf-7.1.2-cp310-cp310-win32.whl", hash = "sha256:3d88c0ecbfd0df33144cbe348a765f9a82bcc86a7cf18fb19df0d9eab6186398"},
{file = "pikepdf-7.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:7c7b8f74b144ee0c384a7b82e34d84da89821e0d3f0cf207c5af039c563dce06"},
{file = "pikepdf-7.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4dd60ae07332b126a4d814955230f1852fcbd905ff72f1d3dde37ab7be192dfa"},
{file = "pikepdf-7.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:641beb42fdf82cd15e079dd081ba410b54ea552ea81b884cc98885ac5541f73d"},
{file = "pikepdf-7.1.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df2a99208cb426d675faaa578a96d6f9b76eee76cb473a267b9ae85078176443"},
{file = "pikepdf-7.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2400574cf79481683f6ce537ee5d1d7925b71ff4d863a026246cbc34be8aeef0"},
{file = "pikepdf-7.1.2-cp311-cp311-win32.whl", hash = "sha256:d75dfaf6df6e7394d7865878eaf9f2dca1900ebcf1ab9e681672a12d6c7b329b"},
{file = "pikepdf-7.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:bb5ec2e06b3085413b69dbf3045a9a05a84d24ed8118221854c5465f6190ab35"},
{file = "pikepdf-7.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:de41f314fa61ab4d2368ab63b7e0f1ad72aab3115cfc90c8e123201fb5c2bcb5"},
{file = "pikepdf-7.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3af17fac243f6e5fef49c57dc99f858957e4210f1b408e1433aa6be29bc49dfd"},
{file = "pikepdf-7.1.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4122e2786d8a21eeb47cb9e2eb3a6fd758280e6b3e873844f44e01a3bb5fda1a"},
{file = "pikepdf-7.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24719a4d1a154afb5fac55920154928f4a68e9c38e30ab0218c632f4fbf448cc"},
{file = "pikepdf-7.1.2-cp38-cp38-win32.whl", hash = "sha256:966008bbe04ac3f282bc026e8f66903c254c048c01f8a5a06e4f55b4d36605df"},
{file = "pikepdf-7.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:ca1a654a97d3d0f3340f934420c8c3a5522e43bb97ed25e31f06b618da9d64cd"},
{file = "pikepdf-7.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17656a15b9ff5868869a79ff40765689a6705d2584e8ab63aff1d0365652b6f1"},
{file = "pikepdf-7.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e87b6a149e39598451d526493ec16f50b67ea899888ee96c14c1545eb1115c53"},
{file = "pikepdf-7.1.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8a8d24fef8802899f8a6aa89ab2d119da7c6acfaa978bdfdc76854854680a7f"},
{file = "pikepdf-7.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0cca81a93b9486d98335b310fd1352ec62197bf9e3bf2774b822d5d862bde41"},
{file = "pikepdf-7.1.2-cp39-cp39-win32.whl", hash = "sha256:db2e4e37a226aac13f6000b22612a8ccfb5764f34ad2b48c39eb38b3bb7cfb35"},
{file = "pikepdf-7.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:1b64ae8d9b35713b317d7a4f429c14202ff9a2c5d63c8200b4fc1401e52c7e10"},
{file = "pikepdf-7.1.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:09e142c484179873249f5c8fc50b8a5e66801feb81fc5111463b36b8396faf13"},
{file = "pikepdf-7.1.2-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7cfd1bc95fdcece892b2506a9b9229d82a72845e74aa13c6e9578f767da41d1"},
{file = "pikepdf-7.1.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e95d872385d7226f48ced00b2f56f1c6fd963d1729fa48baf697f6e98748163"},
{file = "pikepdf-7.1.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5c5ec0c28b0b01aa5a306fc4be45e9948a4f9699f250c68495e279f02fdee0d0"},
{file = "pikepdf-7.1.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1937f88458f183346d863cca71d9c4ea31792db38feba331fde8342473654330"},
{file = "pikepdf-7.1.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:98ccba51e3a0575d7ffaedc61b58fc10fca28151e2429825a36461253485f45d"},
{file = "pikepdf-7.1.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac00e736ee8bc5e59ab7c72498bb895c43cd72bae3fa0cadc163663d578fefd4"},
{file = "pikepdf-7.1.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e35056389134d8ed7d85dce798f9f4b498221c9b640fad4f8f2f8462aaade512"},
{file = "pikepdf-7.1.2.tar.gz", hash = "sha256:b177e8437fe8efdfb7a30c57f361cae1bf2054117856459ca6565c94d32cb5b5"},
{file = "pikepdf-7.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:70f1161dd22ccfcbfd1c460873c95b68b79cf234f0a4e9f37cb565bf436fd85e"},
{file = "pikepdf-7.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cc8d0be5a62ed9011bb519abc34907b5965b392995043719effc4b6a00e2052"},
{file = "pikepdf-7.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d410028ef3435a459e55de520d29010ee91e4a40872d9eb2dab86e6730a24e9d"},
{file = "pikepdf-7.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db8270c940f94d0049420f1a6c05b1f7d326d2abb20493c83f64fde3949404e"},
{file = "pikepdf-7.2.0-cp310-cp310-win32.whl", hash = "sha256:ebc1b30d646ded58721a5594a5ca457e098fedfd9bcab28de79ad79a119e3537"},
{file = "pikepdf-7.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:6790cf10da642d72703cbe887afb923daa2e0f7cb9467a79fe449dbe228f8942"},
{file = "pikepdf-7.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6670efe5b9c1548d60348cdd5ce84ca363a3cde22e9cf695f1ce3b3f818e498d"},
{file = "pikepdf-7.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27a1aea4cae5484cffe4fc5fa761af11f384ca0fd4b2f9114f9ba9717fe4746"},
{file = "pikepdf-7.2.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3c97acce9b66a41b2759dc30ef57de8f38c7239c9b0e7a5febc196b764a2567"},
{file = "pikepdf-7.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7246789dd9071ebcf8c90baebe1eee34ac627e2ea22bf241eff31d32f5ca5df9"},
{file = "pikepdf-7.2.0-cp311-cp311-win32.whl", hash = "sha256:9fadd1a99754dcd925e37721485d4d1259c7ad3c9073c6b3b0ed12c6e2d2234c"},
{file = "pikepdf-7.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:26b9bfb99265dfb6deb72574f8cd30e7ffbc2f53237988bb4e167e18d813f510"},
{file = "pikepdf-7.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b148959f1ad51d236cf6bbc5343beef72c4c60569151221ec06b1d787909222e"},
{file = "pikepdf-7.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c30776791fad8d57a43c392d8e190afded857c61e49dac471ab74e9e716c441"},
{file = "pikepdf-7.2.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e21bce4760c6e64c90b17601a8ce000219677adb264a3c038d2522de032169ca"},
{file = "pikepdf-7.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:371eb23ac14e6c9947e59e5cea15ea93e61a5714c6b1f99fba948927809605ea"},
{file = "pikepdf-7.2.0-cp38-cp38-win32.whl", hash = "sha256:f458c4161e76a882a15ade4125a2f92faa7e5ce120d2e6530dd995aa3308971c"},
{file = "pikepdf-7.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:7a07f73f2aac48af46a546e285360d6e595b499075ab78c3b8ca9f5f13d9e876"},
{file = "pikepdf-7.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6dbe2b62e12ff2b47d4e56ebbe16697d0e25bc2c608f4ee5230cf179ebd2a8ab"},
{file = "pikepdf-7.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7451f176eb9828d8dd7cb3d4e00d4e0aa7f7d7d00331fe640bc20cf3328deb5"},
{file = "pikepdf-7.2.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99e483e037f6991be3c4c655454d57324c10ccf41960acd1edd899ebe9a314dd"},
{file = "pikepdf-7.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3efe4dd2cb417f42865b11e6fc9adb1b6252241bd7a8d891afcaeb2191c285c2"},
{file = "pikepdf-7.2.0-cp39-cp39-win32.whl", hash = "sha256:f325af78bfb63e305be7f31a3afea47fd33ba035ccb08e89d608d2e88b367349"},
{file = "pikepdf-7.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:d0698a429948e613f810b487318ce88112bc71a67fd76645be140532130e6c86"},
{file = "pikepdf-7.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:677f04f02535ac398806970544c43c1e2b120d82b027437c467923a16c81d528"},
{file = "pikepdf-7.2.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc6a653f0f98076a1e86e4fe58fe36dcf403963ae55c65bfcd28aa1d2d9b1b18"},
{file = "pikepdf-7.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5155e1127dfe3aacf77a33552f128e9c04e8b61bf585ab2b155d062a524bfd06"},
{file = "pikepdf-7.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:c99838e86c0fc5a215a0588011344477e8f6ec2c5faf48ee3a9da1ba2c2cac5b"},
{file = "pikepdf-7.2.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b24b7520c7f40bba4f437ba5111dca99dbd0cca9d3cab0f0a33afa6150091ee3"},
{file = "pikepdf-7.2.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4559941b359beb0e90b7d0b8016397ab4700f075f7aa11f2561958a7ce0f8ea"},
{file = "pikepdf-7.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a150160f7ed97769f3c0e60de5cb031bce04e1f6708916ac1c936774a65cc0c"},
{file = "pikepdf-7.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0e1607fda03a53a29a4a8e3fbacbde788804c78167ff251e1c1006f89539f306"},
{file = "pikepdf-7.2.0.tar.gz", hash = "sha256:ad82b836faed0376c725e19d0f8a7c7bef389e8c46683c11bbfc70410bc2e3ee"},
]
[package.dependencies]
@ -1638,19 +1639,19 @@ tests-min = ["defusedxml", "packaging", "pytest"]
[[package]]
name = "playwright"
version = "1.32.1"
version = "1.33.0"
description = "A high-level API to automate web browsers"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "playwright-1.32.1-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:e2f919e8611f598d6e81bd12ab24c5987955b05fc663c98b862034a955387300"},
{file = "playwright-1.32.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5dbf28b8256c2f570a66d6a7c04cd0bfb5225e696e01f85cf5aa49e29ea95b42"},
{file = "playwright-1.32.1-py3-none-macosx_11_0_universal2.whl", hash = "sha256:42473495f8af0279d868cc541d0c6d3733a8adb117253499dae85203104b0824"},
{file = "playwright-1.32.1-py3-none-manylinux1_x86_64.whl", hash = "sha256:83123330e2913a28d11bb8846f7c81a4736553c80f3e9748d213bcaa24fafe91"},
{file = "playwright-1.32.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d56a743f7d88a313b25a88422779c64e5d5a95baa805b9dfd1c5785aa01d217d"},
{file = "playwright-1.32.1-py3-none-win32.whl", hash = "sha256:274bfdd413a979346ce66e99c993c105a123e48da591a65638e5cdf518c90172"},
{file = "playwright-1.32.1-py3-none-win_amd64.whl", hash = "sha256:32bb5645904b5ba3096a4696c70ce3213eb2310c77273140dc5de14498a84134"},
{file = "playwright-1.33.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:b3f6f27f67ec4ef32216a6fab3ffd8a4e1100383be0e863ff86707e617bec1b6"},
{file = "playwright-1.33.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:69f90c23c3906837bbbce4cb80774df72adc2e35c43b9744e13638d37049d970"},
{file = "playwright-1.33.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:08a9cd792a65c7e5f2bb68580f669a706d867fecabc8686098a2fabe3e34f5f8"},
{file = "playwright-1.33.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:84dc9ac79ac828d823161fd6903ffbaf9d3843f4ced2fc2e3414b91b15624d0c"},
{file = "playwright-1.33.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a749f5f2fafc85c5b2a849226cbfdbca4fa047dec3ae20900494e84a390dd0c"},
{file = "playwright-1.33.0-py3-none-win32.whl", hash = "sha256:0671dbb767422621b980b4545eeb2910c73f4e2aabe376a58e4a1ac03990bcec"},
{file = "playwright-1.33.0-py3-none-win_amd64.whl", hash = "sha256:030b273370bcfdec22317ca9fbdd8b66f7493462fb3bf2fce144e3cc82899ae4"},
]
[package.dependencies]
@ -1690,91 +1691,91 @@ wcwidth = "*"
[[package]]
name = "psycopg"
version = "3.1.8"
version = "3.1.9"
description = "PostgreSQL database adapter for Python"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "psycopg-3.1.8-py3-none-any.whl", hash = "sha256:b1500c42063abaa01d30b056f0b300826b8dd8d586900586029a294ce74af327"},
{file = "psycopg-3.1.8.tar.gz", hash = "sha256:59b4a71536b146925513c0234dfd1dc42b81e65d56ce5335dff4813434dbc113"},
{file = "psycopg-3.1.9-py3-none-any.whl", hash = "sha256:fbbac339274d8733ee70ba9822297af3e8871790a26e967b5ea53e30a4b74dcc"},
{file = "psycopg-3.1.9.tar.gz", hash = "sha256:ab400f207a8c120bafdd8077916d8f6c0106e809401378708485b016508c30c9"},
]
[package.dependencies]
psycopg-binary = {version = ">=3.1.6,<=3.1.8", optional = true, markers = "extra == \"binary\""}
psycopg-binary = {version = "3.1.9", optional = true, markers = "extra == \"binary\""}
typing-extensions = ">=4.1"
tzdata = {version = "*", markers = "sys_platform == \"win32\""}
[package.extras]
binary = ["psycopg-binary (>=3.1.6,<=3.1.8)"]
c = ["psycopg-c (>=3.1.6,<=3.1.8)"]
dev = ["black (>=22.3.0)", "dnspython (>=2.1)", "flake8 (>=4.0)", "mypy (>=0.990)", "types-setuptools (>=57.4)", "wheel (>=0.37)"]
binary = ["psycopg-binary (==3.1.9)"]
c = ["psycopg-c (==3.1.9)"]
dev = ["black (>=23.1.0)", "dnspython (>=2.1)", "flake8 (>=4.0)", "mypy (>=1.2)", "types-setuptools (>=57.4)", "wheel (>=0.37)"]
docs = ["Sphinx (>=5.0)", "furo (==2022.6.21)", "sphinx-autobuild (>=2021.3.14)", "sphinx-autodoc-typehints (>=1.12)"]
pool = ["psycopg-pool"]
test = ["mypy (>=0.990)", "pproxy (>=2.7)", "pytest (>=6.2.5)", "pytest-asyncio (>=0.17)", "pytest-cov (>=3.0)", "pytest-randomly (>=3.5)"]
test = ["anyio (>=3.6.2)", "mypy (>=1.2)", "pproxy (>=2.7)", "pytest (>=6.2.5)", "pytest-cov (>=3.0)", "pytest-randomly (>=3.5)"]
[[package]]
name = "psycopg-binary"
version = "3.1.8"
version = "3.1.9"
description = "PostgreSQL database adapter for Python -- C optimisation distribution"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "psycopg_binary-3.1.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f32684b4fc3863190c4b9c141342b2cbdb81632731b9c68e6946d772ba0560f2"},
{file = "psycopg_binary-3.1.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37212244817b3cc7193ee4b5d60765c020ead5e53589c935d249bfb96452878b"},
{file = "psycopg_binary-3.1.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32f2563db6e44372f593a76c94452ce476306e0fb508e092f3fab4d9091a9974"},
{file = "psycopg_binary-3.1.8-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b36fcc67d8b23935ee871a6331c9631ecfdb11452a64f34b8ecb9642de43aec8"},
{file = "psycopg_binary-3.1.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8bb9f577a09e799322008e574a1671c5b2645e990f954be2b7dae669e3779750"},
{file = "psycopg_binary-3.1.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ac81e68262b03163ca977f34448b4cadbc49db929146406b4706fe2141d76d1"},
{file = "psycopg_binary-3.1.8-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fbfc9ae4edfb76c14d09bd70d6f399eb935008bbb3bc4cd6a4ab76645ba3443e"},
{file = "psycopg_binary-3.1.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8602836138bc209aa5f9821c8e8439466f151c3ec4fcdbc740697e49cff1b920"},
{file = "psycopg_binary-3.1.8-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:9cf94411f5a9064cf4ab1066976a7bce44f970f9603a01585c1040465eb312f9"},
{file = "psycopg_binary-3.1.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a8fee8d846f9614331bd764850b4c1363730d36e88e14aa28ec4639318fd2093"},
{file = "psycopg_binary-3.1.8-cp310-cp310-win_amd64.whl", hash = "sha256:2d5ae85c6037e45862e304d39ec24a24ddebc7d2b5b3601155dddc07c19c0cdc"},
{file = "psycopg_binary-3.1.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17d187743d8ca63d24fa724bfee76e50b6473f1fef998cebcd35348b0d5936de"},
{file = "psycopg_binary-3.1.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3762e73b6743139c5258d8b3a294edb309c691ba4f172c9f272315501390e7c2"},
{file = "psycopg_binary-3.1.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87973d064a72bc2716309381b713f49f57c48100fb1f046943b780a04bc011f6"},
{file = "psycopg_binary-3.1.8-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f8400d400f64f659a897d1ef67212012524cc44882bd24387515df9bb723364"},
{file = "psycopg_binary-3.1.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f45766ce8e74eb456d8672116e936391e67290c50fd0cc1b41876b61261869b6"},
{file = "psycopg_binary-3.1.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33ecf37c6348232073ea62b0630655479021f855635f72b4170693032993cdaf"},
{file = "psycopg_binary-3.1.8-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:10b8f1f96f5e8f02a60ba76dab315d3e71cb76c18ff49aa18bbf48a8089c3202"},
{file = "psycopg_binary-3.1.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:58cb0d007768dbccb67783baacf1c4016c7be8a494339a514321edee3d3b787a"},
{file = "psycopg_binary-3.1.8-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:59d8dbea1bc3dbbc819c0320cb2b641dc362389b096098c62172f49605f58284"},
{file = "psycopg_binary-3.1.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4325cee1641c25719bcf063f7683e909cb8cc9932ace3f8bf20ce112e47ce743"},
{file = "psycopg_binary-3.1.8-cp311-cp311-win_amd64.whl", hash = "sha256:064502d191d7bc32a48670cc605ce49abcdb5e01e2697ee3fe546cff330fb8ae"},
{file = "psycopg_binary-3.1.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5fd8492931865cc7181169b2dbf472377a5b5808f001e73f5c25b05bb61e9622"},
{file = "psycopg_binary-3.1.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4d1a4ea2ca20f0bc944bc28e4addb80e6a22ac60a85fc7035e57c88e96f3a18"},
{file = "psycopg_binary-3.1.8-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c27be5ddf4a05146ae7fb8429e9367dad0dc278a7d0e2f5094dd533195c4f8a1"},
{file = "psycopg_binary-3.1.8-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa8ca48a35be0f9880ed2093c213f07d318fa9389a2b9194196c239e41a77841"},
{file = "psycopg_binary-3.1.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf59e1d06f420930fc4c16a42ed6476c60c83976c82e53012dbca45f009d5978"},
{file = "psycopg_binary-3.1.8-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:cb3013b76cbab4a903f3b9c87f4518335627cb05fd89f9e04520c1743c2b919b"},
{file = "psycopg_binary-3.1.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:db84eaa9e2d13e37a97dcd39d2fe78e0a3052c9aa67b5f0b4f3d346a155f4d21"},
{file = "psycopg_binary-3.1.8-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:2c3d268cf2dbb79e52a555c2e7b26c6df2d014f3fb918d512ffc25ecc9c54582"},
{file = "psycopg_binary-3.1.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0fe6205af5f63ee6e4816b267bf06add5934a259cddcf7dfdfc8ed738f5127b2"},
{file = "psycopg_binary-3.1.8-cp37-cp37m-win_amd64.whl", hash = "sha256:f99806a5b9a5ba5cb5f46a0fa0440cd721556e0af09a7cadcc39e27ae9b1807e"},
{file = "psycopg_binary-3.1.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0cc5d5a9b0acbf38e0b4de1c701d235f0cb750ef3de528dedfdbab1a367f2396"},
{file = "psycopg_binary-3.1.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:478ecbb774398e5df6ee365a4d0a77f382a65f140e76720909804255c7801d4a"},
{file = "psycopg_binary-3.1.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b40b56c5b3ffa8481f7bebb08473602ddb8e2e86ba25bf9261ba428eb7887175"},
{file = "psycopg_binary-3.1.8-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:37df8714837d2c701ba4c54462a189b95d1a4439d4d147fb71018560e9a60547"},
{file = "psycopg_binary-3.1.8-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29a38b48cbec8484d83efea4d1d0707e49a3c51a2273cfbaa3d9ba280d3df7d9"},
{file = "psycopg_binary-3.1.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1a2209ef4df25f4ed8d91924bd4d9c7028d254e61216366c4b894c8a6ea4f88"},
{file = "psycopg_binary-3.1.8-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:858a794c2d5e984627503581f03cc68cef97ee080993b7b6a0b7b30cb4fac107"},
{file = "psycopg_binary-3.1.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:574c8b7b51e8d5c06f27125fc218d1328c018c0c1ad8f1202033aa6897b8ee99"},
{file = "psycopg_binary-3.1.8-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:e3dc783eedde10f966039ecc5f96f7df25c288ea4f6795d28b990f312c33ff09"},
{file = "psycopg_binary-3.1.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:94f9e7ccbfdba1c4f5de80b615187eb47a351ab64a9123d87aea4bf347c1e1d8"},
{file = "psycopg_binary-3.1.8-cp38-cp38-win_amd64.whl", hash = "sha256:1425c2cc4cfd4778d9dee578541f11546a93fc2f5c558a0411c94026a1cf94c7"},
{file = "psycopg_binary-3.1.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e68e8b8077cd45dd2683fcd9a384e7672b400e26c0c7d04dac0cf0763c12be78"},
{file = "psycopg_binary-3.1.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:60b22dd46e4e4f678379cf3388468171c2ecea74e90b1332d173ffa8cd83315f"},
{file = "psycopg_binary-3.1.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61a1ccef7e0bf6128a7818c9d22cc850cf7649cee9541e82e4a8c080a734024d"},
{file = "psycopg_binary-3.1.8-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e7a7b41eba96c7b9648efee57298f1aa0d96e081dea76489f52113536981712"},
{file = "psycopg_binary-3.1.8-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a161785b1c8e26cd8e8d5436fa39ba2a8af590c17f1741aae11f8076a08485e6"},
{file = "psycopg_binary-3.1.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a978d2bea09265eb6ebcd1b8a3aa05ea4118aa4013cb9669e12a8656975385cd"},
{file = "psycopg_binary-3.1.8-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:251d2e6dca112dd359c029f422a025d75e78f2f2af4a2aceff506fdc5120f5f9"},
{file = "psycopg_binary-3.1.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a1f052642a54eda53786fa8b72fca2e48ceaf0fc2f3e8709c87694fd7c45ac50"},
{file = "psycopg_binary-3.1.8-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:73747e6a5dfb05500ff3857f9b9ee50e4f4f663250454d773b98d818545f10fa"},
{file = "psycopg_binary-3.1.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:811d870ca9e97875db92f9b346492c4fa7a9edd74dce3604015dd13389fef46a"},
{file = "psycopg_binary-3.1.8-cp39-cp39-win_amd64.whl", hash = "sha256:8a0f425171e95379f1fe93b41d67c6dfe85b6b635944facf07ca26ff7fa8ab1d"},
{file = "psycopg_binary-3.1.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:284038cbe3f5a0f3de417af9b5eaa2a9524a3a06211523cf245111c71b566506"},
{file = "psycopg_binary-3.1.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d2cea4bb0b19245c83486868d7c66f73238c4caa266b5b3c3d664d10dab2ab56"},
{file = "psycopg_binary-3.1.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfe5c5c31f59ccb1d1f473466baa93d800138186286e80e251f930e49c80d208"},
{file = "psycopg_binary-3.1.9-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82704a899d57c29beba5399d41eab5ef5c238b810d7e25e2d1916d2b34c4b1a3"},
{file = "psycopg_binary-3.1.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eab449e39db1c429cac79b7aa27e6827aad4995f32137e922db7254f43fed7b5"},
{file = "psycopg_binary-3.1.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87e0c97733b11eeca3d24e56df70f3f9d792b2abd46f48be2fb2348ffc3e7e39"},
{file = "psycopg_binary-3.1.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:81e34d6df54329424944d5ca91b1cc77df6b8a9130cb5480680d56f53d4e485c"},
{file = "psycopg_binary-3.1.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e2f463079d99568a343ed0b766150b30627e9ed41de99fd82e945e7e2bec764a"},
{file = "psycopg_binary-3.1.9-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f2cbdef6568da21c39dfd45c2074e85eabbd00e1b721832ba94980f01f582dd4"},
{file = "psycopg_binary-3.1.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:53afb0cc2ebe74651f339e22d05ec082a0f44939715d9138d357852f074fcf55"},
{file = "psycopg_binary-3.1.9-cp310-cp310-win_amd64.whl", hash = "sha256:09167f106e7685591b4cdf58eff0191fb7435d586f384133a0dd30df646cf409"},
{file = "psycopg_binary-3.1.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a8aaa47c1791fc05c0229ec1003dd49e13238fba9434e1fc3b879632f749c3c4"},
{file = "psycopg_binary-3.1.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3d91ee0d33ac7b42d0488a9be2516efa2ec00901b81d69566ff34a7a94b66c0b"},
{file = "psycopg_binary-3.1.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5e36504373e5bcdc954b1da1c6fe66379007fe1e329790e8fb72b879a01e097"},
{file = "psycopg_binary-3.1.9-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c1def6c2d28e257325b3b208cf1966343b498282a0f4d390fda7b7e0577da64"},
{file = "psycopg_binary-3.1.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:055537a9c20efe9bf17cb72bd879602eda71de6f737ebafa1953e017c6a37fbe"},
{file = "psycopg_binary-3.1.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b164355d023a91b23dcc4bb3112bc7d6e9b9c938fb5abcb6e54457d2da1f317"},
{file = "psycopg_binary-3.1.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:03b08545ce1c627f4d5e6384eda2946660c4ba6ceb0a09ae47de07419f725669"},
{file = "psycopg_binary-3.1.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1e31bac3d2d41e6446b20b591f638943328c958f4d1ce13d6f1c5db97c3a8dee"},
{file = "psycopg_binary-3.1.9-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:a274c63c8fb9d419509bed2ef72befc1fd04243972e17e7f5afc5725cb13a560"},
{file = "psycopg_binary-3.1.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:98d9d156b9ada08c271a79662fc5fcc1731b4d7c1f651ef5843d818d35f15ba0"},
{file = "psycopg_binary-3.1.9-cp311-cp311-win_amd64.whl", hash = "sha256:c3a13aa022853891cadbc7256a9804e5989def760115c82334bddf0d19783b0b"},
{file = "psycopg_binary-3.1.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1a321ef3579a8de0545ade6ff1edfde0c88b8847d58c5615c03751c76054796"},
{file = "psycopg_binary-3.1.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5833bda4c14f24c6a8ac08d3c5712acaa4f35aab31f9ccd2265e9e9a7d0151c8"},
{file = "psycopg_binary-3.1.9-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a207d5a7f4212443b7452851c9ccd88df9c6d4d58fa2cea2ead4dd9cb328e578"},
{file = "psycopg_binary-3.1.9-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:07414daa86662f7657e9fabe49af85a32a975e92e6568337887d9c9ffedc224f"},
{file = "psycopg_binary-3.1.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17c5d4936c746f5125c6ef9eb43655e27d4d0c9ffe34c3073878b43c3192511d"},
{file = "psycopg_binary-3.1.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5cdc13c8ec1437240801e43d07e27ff6479ac9dd8583ecf647345bfd2e8390e4"},
{file = "psycopg_binary-3.1.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3836bdaf030a5648bd5f5b452e4b068b265e28f9199060c5b70dbf4a218cde6e"},
{file = "psycopg_binary-3.1.9-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:96725d9691a84a21eb3e81c884a2e043054e33e176801a57a05e9ac38d142c6e"},
{file = "psycopg_binary-3.1.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:dade344aa90bb0b57d1cfc13304ed83ab9a36614b8ddd671381b2de72fe1483d"},
{file = "psycopg_binary-3.1.9-cp37-cp37m-win_amd64.whl", hash = "sha256:db866cc557d9761036771d666d17fa4176c537af7e6098f42a6bf8f64217935f"},
{file = "psycopg_binary-3.1.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3b62545cc64dd69ea0ae5ffe18d7c97e03660ab8244aa8c5172668a21c41daa0"},
{file = "psycopg_binary-3.1.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:058ab0d79be0b229338f0e61fec6f475077518cba63c22c593645a69f01c3e23"},
{file = "psycopg_binary-3.1.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2340ca2531f69e5ebd9d18987362ba57ed6ab6a271511d8026814a46a2a87b59"},
{file = "psycopg_binary-3.1.9-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b816ce0e27a2a8786d34b61d3e36e01029245025879d64b88554326b794a4f0"},
{file = "psycopg_binary-3.1.9-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7b36fe4314a784fbe45c9fd71c902b9bf57341aff9b97c0cbd22f8409a271e2f"},
{file = "psycopg_binary-3.1.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b246fed629482b06f938b23e9281c4af592329daa3ec2cd4a6841ccbfdeb4d68"},
{file = "psycopg_binary-3.1.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:90787ac05b932c0fc678cbf470ccea9c385b8077583f0490136b4569ed3fb652"},
{file = "psycopg_binary-3.1.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9c114f678e8f4a96530fa79cfd84f65f26358ecfc6cca70cfa2d5e3ae5ef217a"},
{file = "psycopg_binary-3.1.9-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3a82e77400d1ef6c5bbcf3e600e8bdfacf1a554512f96c090c43ceca3d1ce3b6"},
{file = "psycopg_binary-3.1.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c7d990f14a37345ca05a5192cd5ac938c9cbedca9c929872af6ae311158feb0e"},
{file = "psycopg_binary-3.1.9-cp38-cp38-win_amd64.whl", hash = "sha256:e0ca74fd85718723bb9f08e0c6898e901a0c365aef20b3c3a4ef8709125d6210"},
{file = "psycopg_binary-3.1.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ce8f4dea5934aa6c4933e559c74bef4beb3413f51fbcf17f306ce890216ac33a"},
{file = "psycopg_binary-3.1.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f41a9e0de4db194c053bcc7c00c35422a4d19d92a8187e8065b1c560626efe35"},
{file = "psycopg_binary-3.1.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f94a7985135e084e122b143956c6f589d17aef743ecd0a434a3d3a222631d5a"},
{file = "psycopg_binary-3.1.9-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bb86d58b90faefdc0bbedf08fdea4cc2afcb1cfa4340f027d458bfd01d8b812"},
{file = "psycopg_binary-3.1.9-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c696dc84f9ff155761df15779181d8e4af7746b98908e130add8259912e4bb7"},
{file = "psycopg_binary-3.1.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4213953da44324850c8f789301cf665f46fb94301ba403301e7af58546c3a428"},
{file = "psycopg_binary-3.1.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:25e3ce947aaaa1bd9f1920fca76d7281660646304f9ea5bc036b201dd8790655"},
{file = "psycopg_binary-3.1.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9c75be2a9b986139e3ff6bc0a2852081ac00811040f9b82d3aa539821311122e"},
{file = "psycopg_binary-3.1.9-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:63e8d1dbe253657c70dbfa9c59423f4654d82698fc5ed6868b8dc0765abe20b6"},
{file = "psycopg_binary-3.1.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f4da4ca9b2365fc1d3fc741c3bbd3efccd892ce813444b884c8911a1acf1c932"},
{file = "psycopg_binary-3.1.9-cp39-cp39-win_amd64.whl", hash = "sha256:c0b8d6bbeff1dba760a208d8bc205a05b745e6cee02b839f969f72cf56a8b80d"},
]
[[package]]
@ -1942,14 +1943,14 @@ files = [
[[package]]
name = "pytest"
version = "7.3.0"
version = "7.3.1"
description = "pytest: simple powerful testing with Python"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "pytest-7.3.0-py3-none-any.whl", hash = "sha256:933051fa1bfbd38a21e73c3960cebdad4cf59483ddba7696c48509727e17f201"},
{file = "pytest-7.3.0.tar.gz", hash = "sha256:58ecc27ebf0ea643ebfdf7fb1249335da761a00c9f955bcd922349bcb68ee57d"},
{file = "pytest-7.3.1-py3-none-any.whl", hash = "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362"},
{file = "pytest-7.3.1.tar.gz", hash = "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"},
]
[package.dependencies]
@ -2100,21 +2101,21 @@ test = ["coverage", "pytest"]
[[package]]
name = "requests"
version = "2.28.2"
version = "2.30.0"
description = "Python HTTP for Humans."
category = "main"
optional = false
python-versions = ">=3.7, <4"
python-versions = ">=3.7"
files = [
{file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"},
{file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"},
{file = "requests-2.30.0-py3-none-any.whl", hash = "sha256:10e94cc4f3121ee6da529d358cdaeaff2f1c409cd377dbc72b825852f2f7e294"},
{file = "requests-2.30.0.tar.gz", hash = "sha256:239d7d4458afcb28a692cdd298d87542235f4ca8d36d03a15bfc128a6559a2f4"},
]
[package.dependencies]
certifi = ">=2017.4.17"
charset-normalizer = ">=2,<4"
idna = ">=2.5,<4"
urllib3 = ">=1.21.1,<1.27"
urllib3 = ">=1.21.1,<3"
[package.extras]
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
@ -2140,14 +2141,14 @@ idna2008 = ["idna"]
[[package]]
name = "s3transfer"
version = "0.6.0"
version = "0.6.1"
description = "An Amazon S3 Transfer Manager"
category = "main"
optional = false
python-versions = ">= 3.7"
files = [
{file = "s3transfer-0.6.0-py3-none-any.whl", hash = "sha256:06176b74f3a15f61f1b4f25a1fc29a4429040b7647133a463da8fa5bd28d5ecd"},
{file = "s3transfer-0.6.0.tar.gz", hash = "sha256:2ed07d3866f523cc561bf4a00fc5535827981b117dd7876f036b0c1aca42c947"},
{file = "s3transfer-0.6.1-py3-none-any.whl", hash = "sha256:3c0da2d074bf35d6870ef157158641178a4204a6e689e82546083e31e0311346"},
{file = "s3transfer-0.6.1.tar.gz", hash = "sha256:640bb492711f4c0c0905e1f62b6aaeb771881935ad27884852411f8e9cacbca9"},
]
[package.dependencies]
@ -2158,14 +2159,14 @@ crt = ["botocore[crt] (>=1.20.29,<2.0a.0)"]
[[package]]
name = "setuptools"
version = "67.6.1"
version = "67.7.2"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "setuptools-67.6.1-py3-none-any.whl", hash = "sha256:e728ca814a823bf7bf60162daf9db95b93d532948c4c0bea762ce62f60189078"},
{file = "setuptools-67.6.1.tar.gz", hash = "sha256:257de92a9d50a60b8e22abfcbb771571fde0dbf3ec234463212027a4eeecbe9a"},
{file = "setuptools-67.7.2-py3-none-any.whl", hash = "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b"},
{file = "setuptools-67.7.2.tar.gz", hash = "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990"},
]
[package.extras]
@ -2199,16 +2200,21 @@ files = [
[[package]]
name = "sqlparse"
version = "0.4.3"
version = "0.4.4"
description = "A non-validating SQL parser."
category = "main"
optional = false
python-versions = ">=3.5"
files = [
{file = "sqlparse-0.4.3-py3-none-any.whl", hash = "sha256:0323c0ec29cd52bceabc1b4d9d579e311f3e4961b98d174201d5622a23b85e34"},
{file = "sqlparse-0.4.3.tar.gz", hash = "sha256:69ca804846bb114d2ec380e4360a8a340db83f0ccf3afceeb1404df028f57268"},
{file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"},
{file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"},
]
[package.extras]
dev = ["build", "flake8"]
doc = ["sphinx"]
test = ["pytest", "pytest-cov"]
[[package]]
name = "tinycss2"
version = "1.2.1"
@ -2592,4 +2598,4 @@ test = ["pytest"]
[metadata]
lock-version = "2.0"
python-versions = "~3.10"
content-hash = "ff64a49ae635ff9df41bd009b770a32a005be2d9d7cf7a420f25257c35c25efb"
content-hash = "184e78c3eb28a1dc210851e219bffd1bc19ae62f3de957136de58a3589de8e94"

View File

@ -7,7 +7,7 @@ packages = [{include = "reportcreator_api"}]
[tool.poetry.dependencies]
python = "~3.10"
django = "4.2"
django = "~4.2"
djangorestframework = "3.14.0"
adrf = "0.1.0"
# check weasyprint performance before updating: https://kozea.github.io/WeasyPerf/
@ -43,7 +43,7 @@ boto3 = "^1.26.5"
pillow-heif = "^0.10.1"
playwright = "^1.32.1"
pikepdf = "^7.1.2"
celery = { extras = ["librabbitmq"], version = "^5.2.7" }
celery = { extras = ["librabbitmq"], version = "^5.3b2" }
django-debug-toolbar = "^4.0.0"
debugpy = "^1.6.7"

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
import json
import logging
import httpx
from functools import cached_property
from base64 import b64decode
from urllib.parse import urljoin
from django.conf import settings
@ -42,25 +43,40 @@ class LanguageToolSerializerBase(serializers.Serializer):
if not settings.SPELLCHECK_URL:
raise exceptions.PermissionDenied('Spell checker not configured')
async with httpx.AsyncClient(timeout=10) as client:
res = await client.post(
url=urljoin(settings.SPELLCHECK_URL, path),
data=self.languagetool_auth() | data
)
return res.json()
try:
async with httpx.AsyncClient(timeout=10) as client:
res = await client.post(
url=urljoin(settings.SPELLCHECK_URL, path),
data=self.languagetool_auth() | data
)
if res.status_code != 200:
raise exceptions.APIException(detail='Spellcheck error', code='spellcheck')
return res.json()
except httpx.ReadTimeout:
logging.exception('LanguageTool timeout')
raise exceptions.APIException(detail='Spellcheck timeout', code='spellcheck')
class LanguageToolSerializer(LanguageToolSerializerBase):
language = serializers.ChoiceField(choices=Language.choices + [('auto', 'auto')])
data = TextDataField()
@cached_property
def spellcheck_languages(self):
return [l for l in Language if l.spellcheck and (not settings.PREFERRED_LANGUAGES or l.value in settings.PREFERRED_LANGUAGES)]
def validate_language(self, value):
if value not in self.spellcheck_languages and value != 'auto':
raise serializers.ValidationError('Spellchcking is not supported for this language')
return value
async def spellcheck(self):
data = self.validated_data
return await self.languagetool_request('/v2/check', {
'language': data['language'],
'data': json.dumps(data['data'], ensure_ascii=False),
**({
'preferredVariants': Language.values
'preferredVariants': self.spellcheck_languages,
} if data['language'] == 'auto' else {}),
})

View File

@ -20,7 +20,7 @@ from reportcreator_api.utils import license
from reportcreator_api.pentests.models import Language
from reportcreator_api.pentests.models import ProjectMemberRole
from reportcreator_api.tasks.models import PeriodicTask
from reportcreator_api.utils.utils import copy_keys
from reportcreator_api.utils.utils import copy_keys, remove_duplicates
log = logging.getLogger(__name__)
@ -49,8 +49,15 @@ class UtilsViewSet(viewsets.ViewSet):
@action(detail=False, url_name='settings', url_path='settings', authentication_classes=[], permission_classes=[])
def settings_endpoint(self, *args, **kwargs):
languages = [{
'code': l.value,
'name': l.label,
'spellcheck': l.spellcheck,
'enabled': not settings.PREFERRED_LANGUAGES or l.value in settings.PREFERRED_LANGUAGES
} for l in remove_duplicates(list(map(Language, settings.PREFERRED_LANGUAGES)) + list(Language))]
return Response({
'languages': [{'code': l[0], 'name': l[1]} for l in Language.choices],
'languages': languages,
'project_member_roles': [{'role': r.role, 'default': r.default} for r in ProjectMemberRole.predefined_roles],
'auth_providers': [{'id': k, 'name': v.get('label', k)} for k, v in settings.AUTHLIB_OAUTH_CLIENTS.items()] if license.is_professional() else [],
'elastic_apm_rum_config': settings.ELASTIC_APM_RUM_CONFIG if settings.ELASTIC_APM_RUM_ENABLED else None,
@ -95,6 +102,7 @@ class UtilsViewSet(viewsets.ViewSet):
def license(self, request, *args, **kwargs):
return Response(data=license.check_license() | {
'active_users': PentestUser.objects.get_licensed_user_count(),
'software_version': settings.VERSION,
})

View File

@ -147,7 +147,7 @@ def import_archive(archive_file, serializer_class: Type[serializers.Serializer])
for f in context.get('storage_files', []):
try:
f.delete()
f.delete(save=False)
except Exception:
log.exception(f'Failed to delete imported file "{f.name}" during rollback')
raise ex

View File

@ -11,7 +11,7 @@ https://docs.djangoproject.com/en/4.0/ref/settings/
"""
from datetime import timedelta
from decouple import config
from decouple import config, Csv
from pathlib import Path
import json
from urllib.parse import urljoin
@ -385,6 +385,7 @@ CELERY_WORKER_HIJACK_ROOT_LOGGER=False
CELERY_WORKER_SEND_TASK_EVENTS = False
CELERY_TASK_TIME_LIMIT = 60 * 5
CELERY_TASK_SOFT_TIME_LIMIT = 60 * 5 + 10
CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP = True
# Execute tasks locally, if no broker is configured
CELERY_TASK_ALWAYS_EAGER = not CELERY_BROKER_URL
@ -451,7 +452,7 @@ HEALTH_CHECKS = {
# Notifications
VERSION = config('VERSION', default='dev')
INSTANCE_TAGS = config('INSTANCE_TAGS', default='on-premise').split(';')
INSTANCE_TAGS = config('INSTANCE_TAGS', cast=Csv(delimiter=';'), default='on-premise')
NOTIFICATION_IMPORT_URL = config('NOTIFICATION_IMPORT_URL', default='https://cloud.sysreptor.com/api/v1/notifications/')
@ -464,6 +465,10 @@ LICENSE_VALIDATION_KEYS = [
LICENSE_COMMUNITY_MAX_USERS = 3
# Languages
PREFERRED_LANGUAGES = config('PREFERRED_LANGUAGES', cast=Csv(), default=None)
# Elastic APM
ELASTIC_APM_ENABLED = config('ELASTIC_APM_ENABLED', cast=bool, default=False)
ELASTIC_APM = {

View File

@ -21,6 +21,7 @@ NOTIFICATION_IMPORT_URL = None
ENABLE_PRIVATE_DESIGNS = True
ARCHIVING_THRESHOLD = 1
PREFERRED_LANGUAGES = ['en-US', 'de-DE']
BACKUP_KEY = 'dummy-backup-key-used-in-unit-test'

View File

@ -3,10 +3,9 @@
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import pathlib
import reportcreator_api.archive.crypto.fields
import reportcreator_api.utils.models
import reportcreator_api.utils.storages
import reportcreator_api.pentests.storages
import uuid
@ -26,7 +25,7 @@ class Migration(migrations.Migration):
('updated', models.DateTimeField(auto_now=True)),
('name', models.CharField(db_index=True, max_length=255)),
('threshold', models.PositiveIntegerField()),
('file', models.FileField(storage=reportcreator_api.utils.storages.UnencryptedFileSystemStorage(access_key='', bucket_name='', endpoint_url='', location=pathlib.PurePosixPath('/data/archivedfiles'), secret_key=''), upload_to='')),
('file', models.FileField(storage=reportcreator_api.pentests.storages.get_archive_file_storage, upload_to='')),
],
options={
'ordering': ['-created'],

View File

@ -0,0 +1,29 @@
# Generated by Django 4.2 on 2023-05-03 16:37
from django.db import migrations, models
import reportcreator_api.pentests.models.common
class Migration(migrations.Migration):
dependencies = [
('pentests', '0032_archivedproject_archivedprojectkeypart_userpublickey_and_more'),
]
operations = [
migrations.AlterField(
model_name='findingtemplate',
name='language',
field=models.CharField(choices=[('en-US', 'English'), ('de-DE', 'German'), ('es-ES', 'Spanish'), ('fr-FR', 'French'), ('pt-PT', 'Portuguese'), ('it-IT', 'Italian'), ('nl-NL', 'Dutch'), ('da-DK', 'Danish'), ('pl-PL', 'Polish'), ('uk-UA', 'Ukrainian'), ('ro-RO', 'Romanian'), ('sk-SK', 'Slovak'), ('sl-SI', 'Slovenian'), ('el-GR', 'Greek'), ('sv-SE', 'Swedish'), ('sq-AL', 'Albanian'), ('bg-BG', 'Bulgarian'), ('hr-HR', 'Croatian'), ('et-EE', 'Estonian'), ('fi-FI', 'Finnish'), ('hu-HU', 'Hungarian'), ('lv-LV', 'Latvian'), ('lt-LT', 'Lithuanian'), ('mt-MT', 'Maltese'), ('nb-NO', 'Norwegian'), ('sr-SP', 'Serbian'), ('tr-TR', 'Turkish')], db_index=True, default=reportcreator_api.pentests.models.common.get_default_language, max_length=5),
),
migrations.AlterField(
model_name='pentestproject',
name='language',
field=models.CharField(choices=[('en-US', 'English'), ('de-DE', 'German'), ('es-ES', 'Spanish'), ('fr-FR', 'French'), ('pt-PT', 'Portuguese'), ('it-IT', 'Italian'), ('nl-NL', 'Dutch'), ('da-DK', 'Danish'), ('pl-PL', 'Polish'), ('uk-UA', 'Ukrainian'), ('ro-RO', 'Romanian'), ('sk-SK', 'Slovak'), ('sl-SI', 'Slovenian'), ('el-GR', 'Greek'), ('sv-SE', 'Swedish'), ('sq-AL', 'Albanian'), ('bg-BG', 'Bulgarian'), ('hr-HR', 'Croatian'), ('et-EE', 'Estonian'), ('fi-FI', 'Finnish'), ('hu-HU', 'Hungarian'), ('lv-LV', 'Latvian'), ('lt-LT', 'Lithuanian'), ('mt-MT', 'Maltese'), ('nb-NO', 'Norwegian'), ('sr-SP', 'Serbian'), ('tr-TR', 'Turkish')], db_index=True, default=reportcreator_api.pentests.models.common.get_default_language, max_length=5),
),
migrations.AlterField(
model_name='projecttype',
name='language',
field=models.CharField(choices=[('en-US', 'English'), ('de-DE', 'German'), ('es-ES', 'Spanish'), ('fr-FR', 'French'), ('pt-PT', 'Portuguese'), ('it-IT', 'Italian'), ('nl-NL', 'Dutch'), ('da-DK', 'Danish'), ('pl-PL', 'Polish'), ('uk-UA', 'Ukrainian'), ('ro-RO', 'Romanian'), ('sk-SK', 'Slovak'), ('sl-SI', 'Slovenian'), ('el-GR', 'Greek'), ('sv-SE', 'Swedish'), ('sq-AL', 'Albanian'), ('bg-BG', 'Bulgarian'), ('hr-HR', 'Croatian'), ('et-EE', 'Estonian'), ('fi-FI', 'Finnish'), ('hu-HU', 'Hungarian'), ('lv-LV', 'Latvian'), ('lt-LT', 'Lithuanian'), ('mt-MT', 'Maltese'), ('nb-NO', 'Norwegian'), ('sr-SP', 'Serbian'), ('tr-TR', 'Turkish')], db_index=True, default=reportcreator_api.pentests.models.common.get_default_language, max_length=5),
),
]

View File

@ -28,7 +28,7 @@ class ArchivedProject(BaseModel):
"""
name = models.CharField(max_length=255, null=False, blank=False, db_index=True)
threshold = models.PositiveIntegerField()
file = models.FileField(storage=storages.get_archive_file_storage())
file = models.FileField(storage=storages.get_archive_file_storage)
objects = querysets.ArchivedProjectManager()

View File

@ -1,6 +1,6 @@
import enum
from django.conf import settings
from django.db import models, transaction, IntegrityError
from django.db import DatabaseError, models, transaction, IntegrityError
from django.contrib.contenttypes.models import ContentType
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
@ -37,7 +37,7 @@ class LockInfo(BaseModel):
self.last_ping = timezone.now()
self.save(force_update=True)
return LockStatus.REFRESHED
except self.DoesNotExist:
except (self.DoesNotExist, DatabaseError):
return LockStatus.FAILED
@ -120,12 +120,55 @@ class ReviewStatus(models.TextChoices):
class Language(models.TextChoices):
ENGLISH = 'en-US', 'English'
GERMAN = 'de-DE', 'German'
ENGLISH = 'en-US', True, 'English'
GERMAN = 'de-DE', True, 'German'
SPANISH = 'es-ES', True, 'Spanish'
FRENCH = 'fr-FR', True, 'French'
PORTUGUESE = 'pt-PT', True, 'Portuguese'
ITALIAN = 'it-IT', True, 'Italian'
DUTCH = 'nl-NL', True, 'Dutch'
DANISH = 'da-DK', True, 'Danish'
POLISH = 'pl-PL', True, 'Polish'
UKRAINIAN = 'uk-UA', True, 'Ukrainian'
# RUSSIAN = 'ru-RU', True, 'Russian'
ROMANIAN = 'ro-RO', True, 'Romanian'
SLOVAK = 'sk-SK', True, 'Slovak'
SLOVENIAN = 'sl-SI', True, 'Slovenian'
GREEK = 'el-GR', True, 'Greek'
SWEDISH = 'sv-SE', True, 'Swedish'
# Languages without LanguageTool support
ALBANIAN = 'sq-AL', False, 'Albanian'
BULGARIAN = 'bg-BG', False, 'Bulgarian'
CROATIAN = 'hr-HR', False, 'Croatian'
ESTONIAN = 'et-EE', False, 'Estonian'
FINNISH = 'fi-FI', False, 'Finnish'
HUNGARIAN = 'hu-HU', False, 'Hungarian'
LATVIAN = 'lv-LV', False, 'Latvian'
LITHUANIAN = 'lt-LT', False, 'Lithuanian'
MALTESE = 'mt-MT', False, 'Maltese'
NORWEGIAN = 'nb-NO', False, 'Norwegian'
SERBIAN = 'sr-SP', False, 'Serbian'
TURKISH = 'tr-TR', False, 'Turkish'
def __new__(cls, value, spellcheck):
obj = str.__new__(cls, value)
obj._value_ = value
obj.spellcheck = spellcheck
return obj
# TODO: hide some languages via env variable (if unset, enable all) => api_utils/settings excludes them in frontend
# if language is disabled: do not show in dropdowns in frontend
def get_default_language():
if settings.PREFERRED_LANGUAGES:
return Language(settings.PREFERRED_LANGUAGES[0])
return Language.ENGLISH
class LanguageMixin(models.Model):
language = models.CharField(choices=Language.choices, default=Language.GERMAN, max_length=5, db_index=True)
language = models.CharField(choices=Language.choices, default=get_default_language, max_length=5, db_index=True)
class Meta:
abstract = True

View File

@ -210,8 +210,8 @@ class ProjectMemberRole(BaseModel):
class ProjectMemberInfo(BaseModel):
project = models.ForeignKey(PentestProject, on_delete=models.CASCADE, related_name='members')
user = models.ForeignKey(PentestUser, on_delete=models.CASCADE)
project = models.ForeignKey(to=PentestProject, on_delete=models.CASCADE, related_name='members')
user = models.ForeignKey(to=PentestUser, on_delete=models.PROTECT)
roles = ArrayField(base_field=models.CharField(max_length=50, null=False, blank=False), default=list, blank=True)

View File

@ -38,14 +38,13 @@ async def cleanup_project_files(task_info):
Prefetch('files', UploadedProjectFile.objects.filter(updated__lt=older_than), to_attr='files_cleanup'),
)
# Only check projects that changed since the last cleanup
if last_run := task_info['model'].last_success:
projects = projects.filter(
if last_run := task_info['model'].last_success:
projects = projects.filter(id__in=projects.filter(
Q(updated__gt=last_run) |
Q(findings__updated__gt=last_run) |
Q(sections__updated__gt=last_run) |
Q(notes__updated__gt=last_run)
)
projects = projects.distinct()
).values_list('id'))
# Check if files are referenced
# Requires checking in python because of DB encryption

View File

@ -122,12 +122,7 @@ async def render_pdf_task(project_type: ProjectType, report_template: str, repor
res = await get_celery_result_async(task)
if not res.get('pdf'):
raise PdfRenderingError([ErrorMessage(
level=MessageLevel(m.get('level')),
location=MessageLocationInfo(type=MessageLocationType.DESIGN, id=str(project_type.id), name=project_type.name),
message=m.get('message'),
details=m.get('details')
) for m in res.get('messages', [])])
raise PdfRenderingError([ErrorMessage.from_dict(m) for m in res.get('messages', [])])
return b64decode(res.get('pdf'))
@ -149,6 +144,12 @@ async def render_pdf(project: PentestProject, project_type: Optional[ProjectType
'created': str(f.created),
**f.data,
} async for f in project.findings.all()],
'sections': dict([(s.section_id, {
'id': str(s.section_id),
'created': str(s.created),
'label': s.section_label,
**s.data,
}) async for s in project.sections.all()]),
'pentesters': [await sync_to_async(format_template_field_user)(u) async for u in project.members.all()],
}
data = await sync_to_async(format_template_data)(data=data, project_type=project_type, imported_members=project.imported_members)

View File

@ -11,9 +11,10 @@ from weasyprint import HTML, CSS, default_url_fetcher
from weasyprint.text.fonts import FontConfiguration
from weasyprint.urls import URLFetchingError
from django.core.serializers.json import DjangoJSONEncoder
from django.conf import settings
from reportcreator_api.utils.logging import log_timing
from reportcreator_api.utils.error_messages import ErrorMessage, MessageLevel, MessageLocationInfo, MessageLocationType
@contextmanager
@ -45,8 +46,16 @@ def render_to_html(template: str, data: dict, language: str) -> tuple[Optional[s
with get_page() as page:
console_output = []
page.on('console', lambda l: console_output.append(l))
page.on('pageerror', lambda exc: messages.append({'level': 'error', 'message': 'Uncaught error during template rendering', 'details': str(exc)}))
page.on('requestfailed', lambda request: messages.append({'level': 'error', 'message': 'Request failed', 'details': f'Request to URL {request.url} failed: {request.failure.error_text}'}))
page.on('pageerror', lambda exc: messages.append(ErrorMessage(
level=MessageLevel.ERROR,
message='Uncaught error during template rendering',
details=str(exc)
)))
page.on('requestfailed', lambda request: messages.append(ErrorMessage(
level=MessageLevel.ERROR,
message='Request failed',
details=f'Request to URL {request.url} failed: {request.failure.error_text}'
)))
page.set_content(f"""
<!DOCTYPE html>
<html lang="{html_escape(language)}">
@ -74,7 +83,8 @@ def render_to_html(template: str, data: dict, language: str) -> tuple[Optional[s
msg = {
'level': m.type,
'message': m.text,
'details': None
'details': None,
'location': None,
}
if len(m.args) == 2 and (error_data := m.args[1].json_value()) and 'message' in error_data:
msg |= {
@ -82,19 +92,18 @@ def render_to_html(template: str, data: dict, language: str) -> tuple[Optional[s
'details': error_data.get('details'),
}
if msg['level'] in ['error', 'warning', 'info']:
messages.append(msg)
messages.append(ErrorMessage(**msg | {'level': MessageLevel(msg['level'])}))
if not any(map(lambda m: m['level'] == 'error', messages)):
if not any(map(lambda m: m.level == MessageLevel.ERROR, messages)):
# Remove script tag from HTML output
page.evaluate("""() => document.head.querySelectorAll('script').forEach(s => s.remove())""")
# Get rendered HTML
html = page.content()
except Exception as ex:
messages.append({
'level': 'error',
'message': 'Error rendering HTML template',
'details': None,
})
messages.append(ErrorMessage(
level=MessageLevel.ERROR,
message='Error rendering HTML template',
))
if messages:
logging.info(f'Chromium messages: {messages}')
@ -102,13 +111,35 @@ def render_to_html(template: str, data: dict, language: str) -> tuple[Optional[s
return html, messages
def get_location_info(content: str, objs: list[dict], type: MessageLocationType, get_name=None) -> Optional[MessageLocationInfo]:
def check_field(val, path, **kwargs):
if isinstance(val, dict):
return check_obj(val, path, **kwargs)
elif isinstance(val, list):
for idx, item in enumerate(val):
if res := check_field(val=item, path=path + [f'[{idx}]'], **kwargs):
return res
elif isinstance(val, str):
if content in val:
return MessageLocationInfo(type=type, **kwargs).for_path(path)
def check_obj(obj, path, **kwargs):
for k, v in obj.items():
if res := check_field(val=v, path=path + [k], **kwargs):
return res
for o in objs:
if res := check_field(val=o, path=[], id=o.get('id'), name=get_name(o) if get_name else None):
return res
def weasyprint_strip_pdf_metadata(doc, pdf):
# remove Producer meta-data info from PDF
del pdf.info['Producer']
@log_timing
def render_to_pdf(html_content: str, css_styles: str, resources: dict[str, str]) -> tuple[Optional[bytes], list[dict]]:
def render_to_pdf(html_content: str, css_styles: str, resources: dict[str, str], data: dict) -> tuple[Optional[bytes], list[dict]]:
messages = []
def weasyprint_url_fetcher(url, timeout=10, ssl_context=None):
@ -122,19 +153,22 @@ def render_to_pdf(html_content: str, css_styles: str, resources: dict[str, str])
'file_obj': BytesIO(b64decode(resources[url])),
}
elif url.startswith('/'):
messages.append({
'level': 'error',
'message': 'Resource not found',
'details': f'Could not find resource for URL "{url}". Check if the URL is correct and the resource exists on the server.',
})
messages.append(ErrorMessage(
level=MessageLevel.ERROR,
message='Resource not found',
details=f'Could not find resource for URL "{url}". Check if the URL is correct and the resource exists on the server.',
location=get_location_info(content=url, objs=data.get('findings', []), type=MessageLocationType.FINDING, get_name=lambda f: f.get('title')) or
get_location_info(content=url, objs=data.get('sections', {}).values(), type=MessageLocationType.SECTION, get_name=lambda s: s.get('label')) or
None,
))
raise URLFetchingError('Resource not found')
else:
# block all external requests
messages.append({
'level': 'error',
'message': 'Blocked request to external URL',
'details': f'Block request to URL "{url}". Requests to external systems are forbidden for security reasons.\nUpload this resource as assset and include it via its asset URL.',
})
messages.append(ErrorMessage(
level=MessageLevel.ERROR,
message='Blocked request to external URL',
details=f'Block request to URL "{url}". Requests to external systems are forbidden for security reasons.\nUpload this resource as assset and include it via its asset URL.',
))
raise URLFetchingError('External requests not allowed')
font_config = FontConfiguration()
@ -143,8 +177,9 @@ def render_to_pdf(html_content: str, css_styles: str, resources: dict[str, str])
rendered = html.render(stylesheets=[css], font_config=font_config, optimize_size=[], presentational_hints=True)
res = None
if not any(map(lambda m: m['level'] == 'error', messages)):
if not any(map(lambda m: m.level == MessageLevel.ERROR, messages)):
res = rendered.write_pdf(finisher=weasyprint_strip_pdf_metadata)
logging.warning(str(messages))
return res, messages
@ -164,14 +199,14 @@ def encrypt_pdf(pdf_data: bytes, password: Optional[str]) -> bytes:
return out.getvalue()
def render_pdf(template: str, styles: str, data: dict, resources: dict, language: str, password: Optional[str] = None) -> tuple[Optional[bytes], list[dict]]:
def render_pdf(template: str, styles: str, data: dict, resources: dict, language: str, password: Optional[str] = None) -> tuple[Optional[bytes], list[ErrorMessage]]:
msgs = []
html, html_msgs = render_to_html(
template=template,
data=data,
language=language,
)
msgs += html_msgs
msgs += [m.to_dict() for m in html_msgs]
if html is None:
return None, msgs
@ -179,8 +214,9 @@ def render_pdf(template: str, styles: str, data: dict, resources: dict, language
html_content=html,
css_styles=styles,
resources=resources,
data=data
)
msgs += pdf_msgs
msgs += [m.to_dict() for m in pdf_msgs]
if pdf is None:
return None, msgs

View File

@ -34,7 +34,7 @@ def assert_db_field_encrypted(query, expected):
with connection.cursor() as cursor:
cursor.execute(*query.query.as_sql(compiler=query.query.compiler, connection=connection))
row = cursor.fetchone()
assert row[0].tobytes().startswith(crypto.MAGIC) == expected
assert row[0].startswith(crypto.MAGIC) == expected
def assert_storage_file_encrypted(file, expected):

View File

@ -126,6 +126,7 @@ class TestImportExport:
archive = archive_to_file(export_projects([self.project]))
old_user_id = self.user.id
old_user_roles = self.project.members.all()[0].roles
self.project.members.all().delete()
self.user.delete()
p = import_projects(archive)[0]

View File

@ -7,6 +7,7 @@ from rest_framework import viewsets, status, filters, mixins, serializers, excep
from rest_framework.decorators import action
from rest_framework.settings import api_settings
from django_filters.rest_framework import DjangoFilterBackend
from django.db.models import ProtectedError
from django.conf import settings
from django.forms import model_to_dict
from django.core.serializers.json import DjangoJSONEncoder
@ -95,6 +96,13 @@ class PentestUserViewSet(viewsets.ModelViewSet):
@action(detail=True, url_path='reset-password', methods=['post'])
def reset_password(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def perform_destroy(self, instance):
try:
instance.delete()
except ProtectedError:
raise serializers.ValidationError(
detail='Cannot delete user because it is a member of one or more projects.')
class MFAMethodViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, viewsets.GenericViewSet):

View File

@ -60,8 +60,17 @@ class ErrorMessage:
'level': self.level.value,
'location': dataclasses.asdict(self.location) | {
'type': self.location.type.value,
},
} if self.location else None,
}
@classmethod
def from_dict(cls, data):
location = data.get('location')
return cls(**data | {
'level': MessageLevel(data.get('level')),
'location': MessageLocationInfo(**location | {'type': MessageLocationType(location.get('type'))}) if location else None,
})
def format_messages(lst: list[ErrorMessage]):

View File

@ -1 +1 @@
SYSREPTOR_VERSION=0.76
SYSREPTOR_VERSION=0.83

View File

@ -29,20 +29,21 @@
<v-col v-for="asset in assets.data" :key="asset.id" :cols="12" :md="3">
<s-card>
<s-data-img v-if="isImage(asset)" :src="imageUrl(asset)" aspect-ratio="2" />
<!-- TODO: image via API URL, not base64 -->
<v-img v-if="isImage(asset)" :src="imageUrl(asset)" aspect-ratio="2" />
<v-card-title>{{ asset.name }}</v-card-title>
<v-card-text class="text--small">
{{ assetUrl(asset) }}
</v-card-text>
<v-card-actions>
<s-tooltip>
<template #activator="{on, attrs}">
<s-btn @click="copyAssetUrl(asset)" v-bind="attrs" v-on="on" icon>
<v-icon>mdi-clipboard-outline</v-icon>
<s-btn @click="copyAssetUrl(asset)" v-bind="attrs" v-on="on" icon small>
<v-icon small>mdi-clipboard-outline</v-icon>
</s-btn>
</template>
<span>Copy URL to clipboard</span>
<span>Copy path to clipboard</span>
</s-tooltip>
</v-card-text>
<v-card-actions>
<s-tooltip>
<template #activator="{on, attrs}">
<s-btn @click="downloadAsset(asset)" v-bind="attrs" v-on="on" icon>
@ -51,7 +52,14 @@
</template>
<span>Download asset</span>
</s-tooltip>
<s-tooltip v-if="isImage(asset)">
<template #activator="{on, attrs}">
<s-btn :to="imageUrl(asset)" target="_blank" v-bind="attrs" v-on="on" icon>
<v-icon>mdi-open-in-new</v-icon>
</s-btn>
</template>
<span>Show image in new tab</span>
</s-tooltip>
<v-spacer />
<btn-delete icon :delete="() => performDelete(asset)" :disabled="disabled" />
</v-card-actions>
@ -83,7 +91,7 @@ import FileDownload from 'js-file-download';
import urlJoin from 'url-join';
import PageLoader from './PageLoader.vue';
import { uploadFileHelper } from '~/utils/upload';
import { CursorPaginationFetcher } from '~/utils/urls';
import { absoluteApiUrl, CursorPaginationFetcher } from '~/utils/urls';
export default {
components: { PageLoader },
@ -119,7 +127,7 @@ export default {
return `/assets/name/${asset.name}`;
},
imageUrl(asset) {
return urlJoin(this.projectTypeBaseUrl, this.assetUrl(asset));
return absoluteApiUrl(urlJoin(this.projectTypeBaseUrl, this.assetUrl(asset)), this.$axios);
},
async uploadSingleFile(file) {
try {

View File

@ -22,11 +22,11 @@
<v-expansion-panel-content class="pl-8">
<div v-for="msg, entryIdx in msgGroup.entries" :key="'group-' + groupIdx + '-' + entryIdx" class="mb-2">
<!-- {{ msg.message }} -->
{{ msg.message }}
<span v-if="msg.location" class="error-location">
<slot name="location" :msg="msg">
in {{ msg.location.type }}
<template v-if="msg.location.name">{{ msg.location.name }}"</template>
<template v-if="msg.location.name">"{{ msg.location.name }}"</template>
<template v-if="msg.location.path">{{ msg.location.path }}</template>
</slot>
</span>
@ -45,8 +45,9 @@
<slot name="message" :msg="msg">
{{ msg.message }}
<span v-if="msg.location && msg.location.name" class="error-location">
in "{{ msg.location.name }}"
<template v-if="msg.location.path">{{ msg.location.path }}</template>
in {{ msg.location.type }}
<template v-if="msg.location.name">"{{ msg.location.name }}"</template>
<template v-if="msg.location.path">field {{ msg.location.path }}</template>
</span>
</slot>
</p>

View File

@ -1,10 +1,10 @@
<template>
<s-select
<s-autocomplete
v-bind="$attrs"
:value="value" @change="$emit('input', $event)"
:items="languageInfos"
item-value="code"
item-text="name"
:item-text="l => l.name + ' (' + l.code + ')'"
label="Language"
class="mt-4"
/>
@ -15,12 +15,17 @@ export default {
props: {
value: {
type: String,
required: true,
default: null,
},
},
data() {
return {
initialLanguage: this.value,
};
},
computed: {
languageInfos() {
return this.$store.getters['apisettings/settings'].languages;
return this.$store.getters['apisettings/settings'].languages.filter(l => l.enabled || l.code === this.initialLanguage);
}
}
}

View File

@ -6,6 +6,7 @@
:disabled="disabled"
:upload-files="uploadFile ? uploadFiles : null"
:file-upload-in-progress="fileUploadInProgress"
:lang="lang"
/>
<v-divider />

View File

@ -6,6 +6,7 @@
:disabled="disabled"
:upload-files="uploadFile ? uploadFiles : null"
:file-upload-in-progress="fileUploadInProgress"
:lang="lang"
/>
<v-divider />

View File

@ -54,7 +54,6 @@ export default {
renderMarkdown() {
// Render markdown to HTML
this.renderedMarkdownRaw = renderMarkdownToHtml(this.value || '', {
to: 'html',
preview: true,
rewriteFileSource: this.rewriteFileSource,
});

View File

@ -45,7 +45,8 @@ export default {
},
spellcheckEnabled() {
return this.lang !== null && !this.disabled && this.spellcheckSupported &&
this.$store.state.settings.spellcheckEnabled && this.$store.getters['apisettings/settings'].features.spellcheck;
this.$store.state.settings.spellcheckEnabled && this.$store.getters['apisettings/settings'].features.spellcheck &&
this.$store.getters['apisettings/settings'].languages.find(l => l.code === this.lang)?.spellcheck;
},
},
watch: {

View File

@ -48,6 +48,10 @@ export default {
type: Boolean,
default: false
},
lang: {
type: String,
default: null,
},
},
computed: {
editorMode: {
@ -59,7 +63,8 @@ export default {
},
},
spellcheckSupported() {
return this.$store.getters['apisettings/settings'].features.spellcheck;
return this.$store.getters['apisettings/settings'].features.spellcheck &&
this.$store.getters['apisettings/settings'].languages.find(l => l.code === this.lang)?.spellcheck;
},
spellcheckEnabled: {
get() {

View File

@ -69,10 +69,11 @@ export default {
label: this.label,
itemValue: 'id',
itemText: u => (u.username && u.name) ? `${u.username} (${u.name})` : (u.username || u.name || ''),
itemDisabled: u => this.preventUnselectingSelf && u.id === this.$auth.user.id && !!this.value.find(v => v.id === u.id),
itemDisabled: u => this.preventUnselectingSelf && u.id === this.$auth.user.id && this.value.some(v => v.id === u.id),
disabled: this.disabled,
returnObject: true,
outlined: this.outlined,
clearable: this.clearable,
},
this.selectableUsers ? {
items: this.selectableUsers,
@ -87,15 +88,13 @@ export default {
} : {},
this.required ? {
rules: this.multiple ? this.rules.multiple : this.rules.single,
} : {
clearable: this.clearable,
});
} : {});
}
},
mounted() {
if (this.value) {
this.items.fetchNextPage();
}
}
},
}
</script>
</script>

View File

@ -105,6 +105,16 @@ export default {
'$fetchState.pending'(val) {
if (!val && this.data) {
this.updateInStore(cloneDeep(this.data));
// Scroll to element
this.$nextTick(() => {
if (this.$route.hash) {
const el = document.querySelector(this.$route.hash);
if (el) {
el.scrollIntoView();
}
}
});
}
}
},

View File

@ -49,7 +49,8 @@ export default {
},
spellcheckEnabled() {
return this.lang !== null && !this.disabled &&
this.$store.state.settings.spellcheckEnabled && this.$store.getters['apisettings/settings'].features.spellcheck;
this.$store.state.settings.spellcheckEnabled && this.$store.getters['apisettings/settings'].features.spellcheck &&
this.$store.getters['apisettings/settings'].languages.find(l => l.code === this.lang)?.spellcheck;
},
},
watch: {
@ -184,7 +185,7 @@ export default {
}
},
async performSpellcheckRequest(data) {
if (!this.lang || !data) {
if (!this.spellcheckEnabled || !data) {
return {
matches: []
};

View File

@ -6,7 +6,7 @@
</s-sub-menu>
<list-view url="/projecttypes/?scope=global&ordering=name">
<template #title>Report Designs</template>
<template #title>Global Designs</template>
<template #actions v-if="$auth.hasScope('designer')">
<create-design-dialog project-type-scope="global" />
<btn-import :import="performImport" />

View File

@ -50,6 +50,10 @@
</v-chip>
</td>
</tr>
<tr>
<td>Software Version:</td>
<td>{{ license.software_version }}</td>
</tr>
</tbody>
</v-simple-table>
</v-container>

View File

@ -64,6 +64,7 @@
:prevent-unselecting-self="true"
:error-messages="serverErrors?.members"
:disabled="project.readonly"
:required="true"
label="Members"
/>

View File

@ -1,6 +1,13 @@
<template>
<v-form ref="form">
<edit-toolbar :data="user" :form="$refs.form" :edit-mode="canEdit ? 'EDIT' : 'READONLY'" :save="performSave" />
<edit-toolbar
:data="user"
:form="$refs.form"
:edit-mode="canEdit ? 'EDIT' : 'READONLY'"
:save="performSave"
:delete="performDelete"
:delete-confirm-input="user.username"
/>
<user-info-form v-model="user" :errors="serverErrors" :can-edit-permissions="canEdit" :can-edit-username="canEdit">
<template #login-information>
@ -78,6 +85,11 @@ export default {
}
throw error;
}
},
async performDelete(data) {
await this.$axios.$delete(getUserUrl({ userId: data.id }));
this.$toast.success('User deleted');
this.$router.push('/users/');
}
}
}

View File

@ -40,6 +40,7 @@ export default {
is_template_editor: false,
is_guest: false,
is_system_user: false,
is_global_archiver: false,
},
serverErrors: null,
}

View File

@ -9,7 +9,7 @@ function codeBlock(content, language = null) {
}
describe('Markdown extensions', () => {
for (const [md, html] of Object.entries({
for (const [md, expected] of Object.entries({
// Footnote
'text^[footnote] text': '<p>text<footnote>footnote</footnote> text</p>',
'text^[**foot**[note](#ref)] text': '<p>text<footnote><strong>foot</strong><a href="#ref">note</a></footnote> text</p>',
@ -47,11 +47,17 @@ describe('Markdown extensions', () => {
'```python highlight-manual\npr§<mark><strong>BEGIN</strong><em>§int("hel§</em><strong>END</strong></mark>§lo world")\n```': codeBlock('<span class="hljs-built_in">pr</span><mark><strong>BEGIN</strong><em><span class="hljs-built_in">int</span>(<span class="hljs-string">"hel</span></em><strong>END</strong></mark><span class="hljs-string">lo world"</span>)', 'python'),
'```\npr§§int("hel§§lo world")\n```': codeBlock('pr§§int("hel§§lo world")'),
'```none highlight-manual="|"\npr||int("hel||lo world")\n```': codeBlock('pr<mark>int("hel</mark>lo world")', 'none'),
})) {
// Nested elements
'![caption^[footnote [link](https://example.com)]](/img.png)': '<p></p><figure><img src="/img.png" alt="captionfootnote link"><figcaption>caption<footnote>footnote <a href="https://example.com" target="_blank" rel="nofollow noopener noreferrer">link</a></footnote></figcaption></figure><p></p>',
'![caption^[footnote [partial]](/img.png)': {
html: '<p></p><figure><img src="/img.png" alt="captionfootnote [partial"><figcaption>caption<footnote>footnote [partial</footnote></figcaption></figure><p></p>',
formatted: '![caption^[footnote \\[partial]](/img.png)',
},
}).map(([md, expected]) => [md, typeof expected === 'string' ? { html: expected, formatted: md } : expected])) {
test(md, () => {
expect(renderMarkdownToHtml(md).trim()).toBe(html);
expect(renderMarkdownToHtml(md).trim()).toBe(expected.html);
const formattedMd = formatMarkdown(md).trim('\n');
expect(formattedMd).toBe(md);
expect(formattedMd).toBe(expected.formatted);
});
}
});

View File

@ -2,7 +2,7 @@ import { sortBy } from "lodash";
import { scoreFromVector } from "./cvss";
export function sortFindings(findings) {
return sortBy(findings, [f => -scoreFromVector(f.data ? f.data.cvss : f.cvss), f => f.data ? f.data.created : f.id]);
return sortBy(findings, [f => -scoreFromVector(f.data ? f.data.cvss : f.cvss), f => f.created, f => f.id]);
}
export const EditMode = Object.freeze({

View File

@ -7,7 +7,6 @@ languagetool_cacheSize=${languagetool_cacheSize:-1000}
languagetool_cacheTTLSeconds=${languagetool_cacheTTLSeconds:-300}
languagetool_pipelineCaching=${languagetool_pipelineCaching:-true}
languagetool_localApiMode=${languagetool_localApiMode:-true}
languagetool_preferredLanguages=${languagetool_preferredLanguages:-en,de}
languagetool_dbDriver=${languagetool_dbDriver:-org.postgresql.Driver}
languagetool_dbPort=${languagetool_dbPort:-5432}

View File

@ -16,9 +16,10 @@ import { annotatedTextParse } from './editor/annotatedtext.js';
import { remarkTemplateVariables } from './mdext/templates.js';
import { remarkTodoMarker } from './mdext/todo.js';
import { rehypeHighlightCode } from './mdext/codeHighlight.js';
import { remarkLabelEnd } from './mdext/label-end.js';
import remarkStringify from 'remark-stringify';
import rehypeSanitize, { defaultSchema } from 'rehype-sanitize';
import { defaults, merge } from 'lodash';
import { merge } from 'lodash';
const rehypeSanitizeSchema = merge({}, defaultSchema, {
@ -38,6 +39,7 @@ export function markdownParser() {
// * enable autolinks?
return unified()
.use(remarkFootnotes)
.use(remarkLabelEnd)
.use(remarkTables)
.use(remarkTableCaptions)
.use(remarkStrikethrough)

View File

@ -10,6 +10,10 @@ export function addRemarkExtension(self, micromarkExtensions, fromMarkdownExtens
* @param {unknown} value
*/
function add(field, value) {
if (!value) {
return;
}
const list = /** @type {unknown[]} */ (
// Other extensions
/* c8 ignore next 2 */

View File

@ -0,0 +1,547 @@
/**
* @typedef {import('micromark-util-types').Construct} Construct
* @typedef {import('micromark-util-types').Resolver} Resolver
* @typedef {import('micromark-util-types').Tokenizer} Tokenizer
* @typedef {import('micromark-util-types').TokenizeContext} TokenizeContext
* @typedef {import('micromark-util-types').Event} Event
* @typedef {import('micromark-util-types').Token} Token
* @typedef {import('micromark-util-types').State} State
*/
import {factoryDestination} from 'micromark-factory-destination'
import {factoryLabel} from 'micromark-factory-label'
import {factoryTitle} from 'micromark-factory-title'
import {factoryWhitespace} from 'micromark-factory-whitespace'
import {markdownLineEndingOrSpace} from 'micromark-util-character'
import {push, splice} from 'micromark-util-chunked'
import {normalizeIdentifier} from 'micromark-util-normalize-identifier'
import {resolveAll} from 'micromark-util-resolve-all'
import {codes} from 'micromark-util-symbol/codes.js'
import {constants} from 'micromark-util-symbol/constants.js'
import {types} from 'micromark-util-symbol/types.js'
import { addRemarkExtension, assert } from './helpers'
/** @type {Construct} */
const labelEnd = {
name: 'labelEndCustom',
tokenize: tokenizeLabelEnd,
resolveTo: resolveToLabelEnd,
resolveAll: resolveAllLabelEnd
}
/** @type {Construct} */
const resourceConstruct = {tokenize: tokenizeResource}
/** @type {Construct} */
const fullReferenceConstruct = {tokenize: tokenizeFullReference}
/** @type {Construct} */
const collapsedReferenceConstruct = {tokenize: tokenizeCollapsedReference}
/** @type {Resolver} */
function resolveAllLabelEnd(events) {
let index = -1
while (++index < events.length) {
const token = events[index][1]
if (
token.type === types.labelImage ||
token.type === types.labelLink ||
token.type === types.labelEnd ||
token.type === 'inlineFootnoteStart' ||
token.type === 'inlineFootnoteEnd'
) {
// Remove the marker.
events.splice(index + 1, (token.type === types.labelImage || token.type === 'inlineFootnoteStart') ? 4 : 2)
token.type = types.data
index++
}
}
return events
}
/** @type {Resolver} */
function resolveToLabelEnd(events, context) {
let index = events.length
let offset = 0
/** @type {Token} */
let token
/** @type {number|undefined} */
let open
/** @type {number|undefined} */
let close
/** @type {Array<Event>} */
let media
// Find an opening.
while (index--) {
token = events[index][1]
if (open) {
// If we see another link, or inactive link label, weve been here before.
if (
token.type === types.link ||
(token.type === types.labelLink && token._inactive)
) {
break
}
// Mark other link openings as inactive, as we cant have links in
// links.
if (events[index][0] === 'enter' && token.type === types.labelLink) {
token._inactive = true
}
} else if (close) {
if (
events[index][0] === 'enter' &&
(token.type === types.labelImage || token.type === types.labelLink || token.type === 'inlineFootnoteStart') &&
!token._labelEnd_balanced
) {
open = index
if (token.type !== types.labelLink) {
offset = 2
break
}
}
} else if (token.type === types.labelEnd || token.type === 'inlineFootnoteEnd') {
close = index
}
}
assert(open !== undefined, '`open` is supposed to be found')
assert(close !== undefined, '`close` is supposed to be found')
const group = {
type: events[open][1].type === types.labelLink ? types.link : types.image,
start: Object.assign({}, events[open][1].start),
end: Object.assign({}, events[events.length - 1][1].end)
}
const label = {
type: types.label,
start: Object.assign({}, events[open][1].start),
end: Object.assign({}, events[close][1].end)
}
const text = {
type: types.labelText,
start: Object.assign({}, events[open + offset + 2][1].end),
end: Object.assign({}, events[close - 2][1].start)
}
media = [
['enter', group, context],
['enter', label, context]
]
// Opening marker.
media = push(media, events.slice(open + 1, open + offset + 3))
// Text open.
media = push(media, [['enter', text, context]])
// Between.
media = push(
media,
resolveAll(
context.parser.constructs.insideSpan.null,
events.slice(open + offset + 4, close - 3),
context
)
)
// Text close, marker close, label close.
media = push(media, [
['exit', text, context],
events[close - 2],
events[close - 1],
['exit', label, context]
])
// Reference, resource, or so.
media = push(media, events.slice(close + 1))
// Media close.
media = push(media, [['exit', group, context]])
splice(events, open, events.length, media)
return events
}
/**
* @this {TokenizeContext}
* @type {Tokenizer}
*/
function tokenizeLabelEnd(effects, ok, nok) {
const self = this
let index = self.events.length
/** @type {Token} */
let labelStart
/** @type {boolean} */
let defined
// Find an opening.
while (index--) {
if (
(self.events[index][1].type === types.labelImage ||
self.events[index][1].type === types.labelLink ||
self.events[index][1].type === 'inlineFootnoteStart') &&
!self.events[index][1]._labelEnd_balanced
) {
labelStart = self.events[index][1]
break
}
}
return start
/**
* Start of label end.
*
* ```markdown
* > | [a](b) c
* ^
* > | [a][b] c
* ^
* > | [a][] b
* ^
* > | [a] b
* ```
*
* @type {State}
*/
function start(code) {
assert(code === codes.rightSquareBracket, 'expected `]`')
if (!labelStart) {
return nok(code)
}
// Its a balanced bracket, but contains a link.
if (labelStart._inactive) return balanced(code)
defined = self.parser.defined.includes(
normalizeIdentifier(
self.sliceSerialize({start: labelStart.end, end: self.now()})
)
)
effects.enter(types.labelEnd)
effects.enter(types.labelMarker)
effects.consume(code)
effects.exit(types.labelMarker)
effects.exit(types.labelEnd)
return afterLabelEnd
}
/**
* After `]`.
*
* ```markdown
* > | [a](b) c
* ^
* > | [a][b] c
* ^
* > | [a][] b
* ^
* > | [a] b
* ^
* ```
*
* @type {State}
*/
function afterLabelEnd(code) {
// Resource (`[asd](fgh)`)?
if (code === codes.leftParenthesis) {
return effects.attempt(
resourceConstruct,
ok,
defined ? ok : balanced
)(code)
}
// Full (`[asd][fgh]`) or collapsed (`[asd][]`) reference?
if (code === codes.leftSquareBracket) {
return effects.attempt(
fullReferenceConstruct,
ok,
defined
? effects.attempt(collapsedReferenceConstruct, ok, balanced)
: balanced
)(code)
}
// Shortcut (`[asd]`) reference?
return defined ? ok(code) : balanced(code)
}
/**
* Done, its nothing.
*
* There was an okay opening, but we didnt match anything.
*
* ```markdown
* > | [a](b c
* ^
* > | [a][b c
* ^
* > | [a] b
* ^
* ```
*
* @type {State}
*/
function balanced(code) {
labelStart._labelEnd_balanced = true
return nok(code)
}
}
/**
* @this {TokenizeContext}
* @type {Tokenizer}
*/
function tokenizeResource(effects, ok, nok) {
return start
/**
* Before a resource, at `(`.
*
* ```markdown
* > | [a](b) c
* ^
* ```
*
* @type {State}
*/
function start(code) {
assert(code === codes.leftParenthesis, 'expected left paren')
effects.enter(types.resource)
effects.enter(types.resourceMarker)
effects.consume(code)
effects.exit(types.resourceMarker)
return factoryWhitespace(effects, open)
}
/**
* At the start of a resource, after optional whitespace.
*
* ```markdown
* > | [a](b) c
* ^
* ```
*
* @type {State}
*/
function open(code) {
if (code === codes.rightParenthesis) {
return end(code)
}
return factoryDestination(
effects,
destinationAfter,
nok,
types.resourceDestination,
types.resourceDestinationLiteral,
types.resourceDestinationLiteralMarker,
types.resourceDestinationRaw,
types.resourceDestinationString,
constants.linkResourceDestinationBalanceMax
)(code)
}
/**
* In a resource, after a destination, before optional whitespace.
*
* ```markdown
* > | [a](b) c
* ^
* ```
*
* @type {State}
*/
function destinationAfter(code) {
return markdownLineEndingOrSpace(code)
? factoryWhitespace(effects, between)(code)
: end(code)
}
/**
* In a resource, after a destination, after whitespace.
*
* ```markdown
* > | [a](b ) c
* ^
* ```
*
* @type {State}
*/
function between(code) {
if (
code === codes.quotationMark ||
code === codes.apostrophe ||
code === codes.leftParenthesis
) {
return factoryTitle(
effects,
factoryWhitespace(effects, end),
nok,
types.resourceTitle,
types.resourceTitleMarker,
types.resourceTitleString
)(code)
}
return end(code)
}
/**
* In a resource, at the `)`.
*
* ```markdown
* > | [a](b) d
* ^
* ```
*
* @type {State}
*/
function end(code) {
if (code === codes.rightParenthesis) {
effects.enter(types.resourceMarker)
effects.consume(code)
effects.exit(types.resourceMarker)
effects.exit(types.resource)
return ok
}
return nok(code)
}
}
/**
* @this {TokenizeContext}
* @type {Tokenizer}
*/
function tokenizeFullReference(effects, ok, nok) {
const self = this
return start
/**
* In a reference (full), at the `[`.
*
* ```markdown
* > | [a][b] d
* ^
* ```
*
* @type {State}
*/
function start(code) {
assert(code === codes.leftSquareBracket, 'expected left bracket')
return factoryLabel.call(
self,
effects,
afterLabel,
nok,
types.reference,
types.referenceMarker,
types.referenceString
)(code)
}
/**
* In a reference (full), after `]`.
*
* ```markdown
* > | [a][b] d
* ^
* ```
*
* @type {State}
*/
function afterLabel(code) {
return self.parser.defined.includes(
normalizeIdentifier(
self.sliceSerialize(self.events[self.events.length - 1][1]).slice(1, -1)
)
)
? ok(code)
: nok(code)
}
}
/**
* @this {TokenizeContext}
* @type {Tokenizer}
*/
function tokenizeCollapsedReference(effects, ok, nok) {
return start
/**
* In a reference (collapsed), at the `[`.
*
* > 👉 **Note**: we only get here if the label is defined.
*
* ```markdown
* > | [a][] d
* ^
* ```
*
* @type {State}
*/
function start(code) {
assert(code === codes.leftSquareBracket, 'expected left bracket')
effects.enter(types.reference)
effects.enter(types.referenceMarker)
effects.consume(code)
effects.exit(types.referenceMarker)
return open
}
/**
* In a reference (collapsed), at the `]`.
*
* > 👉 **Note**: we only get here if the label is defined.
*
* ```markdown
* > | [a][] d
* ^
* ```
*
* @type {State}
*/
function open(code) {
if (code === codes.rightSquareBracket) {
effects.enter(types.referenceMarker)
effects.consume(code)
effects.exit(types.referenceMarker)
effects.exit(types.reference)
return ok
}
return nok(code)
}
}
const labelEndSyntax = {
text: {
[codes.rightSquareBracket]: labelEnd,
}
};
/**
* Override default labelEnd handler to support parsing nested labels in image captions and footnotes.
*/
export function remarkLabelEnd() {
addRemarkExtension(this, {disable: {null: ['labelEnd']}});
addRemarkExtension(this, labelEndSyntax, null, null);
}

View File

@ -29,6 +29,5 @@ export default {
}
.code-block code {
display: block;
width: 100%;
}
</style>