Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • ziirish/burp-ui
  • root42/burp-ui
  • waddles/burp-ui
  • pbrideau/burp-ui
  • malevolent/burp-ui
  • deajan/burp-ui
  • pedro.domingues/burp-ui
  • pablodav/burp-ui
8 results
Show changes
Commits on Source (141)
Showing with 1335 additions and 322 deletions
[MASTER]
# Specify a configuration file.
#rcfile=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Add files or directories to the blacklist. They should be base names, not
# paths.
ignore=CVS
# Pickle collected data for later comparisons.
persistent=yes
# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=
# Use multiple processes to speed up Pylint.
jobs=1
# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code
extension-pkg-whitelist=
# Allow optimization of some AST trees. This will activate a peephole AST
# optimizer, which will apply various small optimizations. For instance, it can
# be used to obtain the result of joining multiple strings with the addition
# operator. Joining a lot of strings can lead to a maximum recursion error in
# Pylint and this flag can prevent that. It has one side effect, the resulting
# AST will be different than the one from reality.
optimize-ast=no
[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
confidence=
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time. See also the "--disable" option for examples.
#enable=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once).You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
disable=import-star-module-level,old-octal-literal,oct-method,print-statement,unpacking-in-except,parameter-unpacking,backtick,old-raise-syntax,old-ne-operator,long-suffix,dict-view-method,dict-iter-method,metaclass-assignment,next-method-called,raising-string,indexing-exception,raw_input-builtin,long-builtin,file-builtin,execfile-builtin,coerce-builtin,cmp-builtin,buffer-builtin,basestring-builtin,apply-builtin,filter-builtin-not-iterating,line-too-long,using-cmp-argument,useless-suppression,range-builtin-not-iterating,suppressed-message,no-absolute-import,old-division,cmp-method,reload-builtin,zip-builtin-not-iterating,intern-builtin,unichr-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,input-builtin,round-builtin,hex-method,nonzero-method,map-builtin-not-iterating
[REPORTS]
# Set the output format. Available formats are text, parseable, colorized, msvs
# (visual studio) and html. You can also give a reporter class, eg
# mypackage.mymodule.MyReporterClass.
output-format=text
# Put messages in a separate file for each module / package specified on the
# command line instead of printing them on stdout. Reports (if any) will be
# written in a file name "pylint_global.[txt|html]".
files-output=no
# Tells whether to display a full report or only the messages
reports=yes
# Python expression which should return a note less than 10 (10 is the highest
# note). You have access to the variables errors warning, statement which
# respectively contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details
#msg-template=
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=FIXME,XXX,TODO
[SPELLING]
# Spelling dictionary name. Available dictionaries: none. To make it working
# install python-enchant package.
spelling-dict=
# List of comma separated words that should not be checked.
spelling-ignore-words=
# A path to a file that contains private dictionary; one word per line.
spelling-private-dict-file=
# Tells whether to store unknown words to indicated private dictionary in
# --spelling-private-dict-file option instead of raising a message.
spelling-store-unknown-words=no
[TYPECHECK]
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis. It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=
# List of classes names for which member attributes should not be checked
# (useful for classes with attributes dynamically set). This supports can work
# with qualified names.
ignored-classes=
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=
[FORMAT]
# Maximum number of characters on a single line.
max-line-length=100
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=no
# List of optional constructs for which whitespace checking is disabled. `dict-
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
# `empty-line` allows space-only lines.
no-space-check=trailing-comma,dict-separator
# Maximum number of lines in a module
max-module-lines=1000
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '
# Number of spaces of indent required inside a hanging or continued line.
indent-after-paren=4
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
expected-line-ending-format=
[SIMILARITIES]
# Minimum lines number of a similarity.
min-similarity-lines=4
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
# Ignore imports when computing similarities.
ignore-imports=no
[LOGGING]
# Logging modules to check that the string format arguments are in logging
# function parameter format
logging-modules=logging
[VARIABLES]
# Tells whether we should check for unused import in __init__ files.
init-import=no
# A regular expression matching the name of dummy variables (i.e. expectedly
# not used).
dummy-variables-rgx=_$|dummy
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,_cb
[BASIC]
# List of builtins function names that should not be used, separated by a comma
bad-functions=map,filter,input
# Good variable names which should always be accepted, separated by a comma
good-names=i,j,k,ex,Run,_
# Bad variable names which should always be refused, separated by a comma
bad-names=foo,bar,baz,toto,tutu,tata
# Colon-delimited sets of names that determine each other's naming style when
# the name regexes allow several styles.
name-group=
# Include a hint for the correct naming format with invalid-name
include-naming-hint=no
# Regular expression matching correct function names
function-rgx=[a-z_][a-z0-9_]{2,30}$
# Naming hint for function names
function-name-hint=[a-z_][a-z0-9_]{2,30}$
# Regular expression matching correct variable names
variable-rgx=[a-z_][a-z0-9_]{2,30}$
# Naming hint for variable names
variable-name-hint=[a-z_][a-z0-9_]{2,30}$
# Regular expression matching correct constant names
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
# Naming hint for constant names
const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$
# Regular expression matching correct attribute names
attr-rgx=[a-z_][a-z0-9_]{2,30}$
# Naming hint for attribute names
attr-name-hint=[a-z_][a-z0-9_]{2,30}$
# Regular expression matching correct argument names
argument-rgx=[a-z_][a-z0-9_]{2,30}$
# Naming hint for argument names
argument-name-hint=[a-z_][a-z0-9_]{2,30}$
# Regular expression matching correct class attribute names
class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
# Naming hint for class attribute names
class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
# Regular expression matching correct inline iteration names
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
# Naming hint for inline iteration names
inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$
# Regular expression matching correct class names
class-rgx=[A-Z_][a-zA-Z0-9]+$
# Naming hint for class names
class-name-hint=[A-Z_][a-zA-Z0-9]+$
# Regular expression matching correct module names
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
# Naming hint for module names
module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
# Regular expression matching correct method names
method-rgx=[a-z_][a-z0-9_]{2,30}$
# Naming hint for method names
method-name-hint=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=^_
# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=-1
[ELIF]
# Maximum number of nested blocks for function / method body
max-nested-blocks=5
[IMPORTS]
# Deprecated modules which should not be used, separated by a comma
deprecated-modules=regsub,TERMIOS,Bastion,rexec
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled)
import-graph=
# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled)
ext-import-graph=
# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled)
int-import-graph=
[CLASSES]
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__,setUp
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls
# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=mcs
# List of member names, which should be excluded from the protected access
# warning.
exclude-protected=_asdict,_fields,_replace,_source,_make
[DESIGN]
# Maximum number of arguments for function / method
max-args=5
# Argument names that match this expression will be ignored. Default to name
# with leading underscore
ignored-argument-names=_.*
# Maximum number of locals for function / method body
max-locals=15
# Maximum number of return / yield for function / method body
max-returns=6
# Maximum number of branch for function / method body
max-branches=12
# Maximum number of statements in function / method body
max-statements=50
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of attributes for a class (see R0902).
max-attributes=7
# Minimum number of public methods for a class (see R0903).
min-public-methods=2
# Maximum number of public methods for a class (see R0904).
max-public-methods=20
# Maximum number of boolean expressions in a if statement
max-bool-expr=5
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to
# "Exception"
overgeneral-exceptions=Exception
Changelog Changelog
========= =========
Current 0.2.0 (05/17/2016)
------- ------------------
- Add `python 3 support <https://git.ziirish.me/ziirish/burp-ui/issues/75>`_ - Add: allow to `edit a server-initiated restoration <https://git.ziirish.me/ziirish/burp-ui/issues/125>`_
- Add new fields in `backup reports <https://git.ziirish.me/ziirish/burp-ui/issues/48>`_ - Add: allow to `cancel a server-initiated restoration <https://git.ziirish.me/ziirish/burp-ui/issues/112>`_
- Add `server-side initiated restoration <https://git.ziirish.me/ziirish/burp-ui/issues/12>`_ - Add: support for `Burp labels <https://git.ziirish.me/ziirish/burp-ui/issues/116>`_
- Add percent done in `overview <https://git.ziirish.me/ziirish/burp-ui/issues/55>`_ - Add: `server-initiated backups <https://git.ziirish.me/ziirish/burp-ui/issues/119>`_
- Add the ability to `chain multiple authentication backends <https://git.ziirish.me/ziirish/burp-ui/issues/79>`_ - Add: support `sub-root path <https://git.ziirish.me/ziirish/burp-ui/issues/128>`_
- Add display versions `within the interface <https://git.ziirish.me/ziirish/burp-ui/issues/89>`_ - Add: new Burp 2 settings
- Add support for `zip64 <https://git.ziirish.me/ziirish/burp-ui/issues/97>`_ - Improvement: `better logging system <https://git.ziirish.me/ziirish/burp-ui/issues/118>`_
- Add new `report <https://git.ziirish.me/ziirish/burp-ui/issues/15>`_ - Improvement: `new security options <https://git.ziirish.me/ziirish/burp-ui/issues/86>`_
- Add new `calendar view <https://git.ziirish.me/ziirish/burp-ui/issues/61>`_ - Fix: issue `#109 <https://git.ziirish.me/ziirish/burp-ui/issues/109>`_
- Add "restart" option to debian init script thanks to @Larsen - Fix: issue `#113 <https://git.ziirish.me/ziirish/burp-ui/issues/113>`_
- Add Basic HTTP Authentication (mostly for the API) - Fix: issue `#114 <https://git.ziirish.me/ziirish/burp-ui/issues/114>`_
- Add self-documented API - Fix: issue `#117 <https://git.ziirish.me/ziirish/burp-ui/issues/117>`_
- Fix issue `#81 <https://git.ziirish.me/ziirish/burp-ui/issues/81>`_ - Fix: issue `#123 <https://git.ziirish.me/ziirish/burp-ui/issues/123>`_
- Fix issue `#87 <https://git.ziirish.me/ziirish/burp-ui/issues/87>`_ - Doc
- Fix issue `#88 <https://git.ziirish.me/ziirish/burp-ui/issues/88>`_ - `Full changelog <https://git.ziirish.me/ziirish/burp-ui/compare/v0.1.0...v0.2.0>`__
- Fix issue `#92 <https://git.ziirish.me/ziirish/burp-ui/issues/92>`_
- Fix issue `#95 <https://git.ziirish.me/ziirish/burp-ui/issues/95>`_ 0.1.3 (02/20/2016)
- Fix issue `#99 <https://git.ziirish.me/ziirish/burp-ui/issues/99>`_ ------------------
- Fix issue `#100 <https://git.ziirish.me/ziirish/burp-ui/issues/100>`_
- Fix issue `#101 <https://git.ziirish.me/ziirish/burp-ui/issues/101>`_ - Fix: issue `#107 <https://git.ziirish.me/ziirish/burp-ui/issues/107>`_
- Fix: issue `#108 <https://git.ziirish.me/ziirish/burp-ui/issues/108>`_
0.1.2 (02/18/2016)
------------------
- Fix: duration computation
- Fix: issue `#104 <https://git.ziirish.me/ziirish/burp-ui/issues/104>`_
- Fix: issue `#105 <https://git.ziirish.me/ziirish/burp-ui/issues/105>`_
- Fix: issue `#106 <https://git.ziirish.me/ziirish/burp-ui/issues/106>`_
0.1.1 (02/17/2016)
------------------
- Fix: burp2 backend issue
- Fix: Debian wheezy compatibility
- Fix: sample configuration files location
- Better calendar readability
0.1.0 (02/15/2016)
------------------
- Add: `python 3 support <https://git.ziirish.me/ziirish/burp-ui/issues/75>`_
- Add: new fields in `backup reports <https://git.ziirish.me/ziirish/burp-ui/issues/48>`_
- Add: `server-side initiated restoration <https://git.ziirish.me/ziirish/burp-ui/issues/12>`_
- Add: percent done in `overview <https://git.ziirish.me/ziirish/burp-ui/issues/55>`_
- Add: ability to `chain multiple authentication backends <https://git.ziirish.me/ziirish/burp-ui/issues/79>`_
- Add: display versions `within the interface <https://git.ziirish.me/ziirish/burp-ui/issues/89>`_
- Add: support for `zip64 <https://git.ziirish.me/ziirish/burp-ui/issues/97>`_
- Add: new `report <https://git.ziirish.me/ziirish/burp-ui/issues/15>`_
- Add: new `calendar view <https://git.ziirish.me/ziirish/burp-ui/issues/61>`_
- Add: "restart" option to debian init script thanks to @Larsen
- Add: Basic HTTP Authentication (mostly for the API)
- Add: self-documented API
- Fix: issue `#81 <https://git.ziirish.me/ziirish/burp-ui/issues/81>`_
- Fix: issue `#87 <https://git.ziirish.me/ziirish/burp-ui/issues/87>`_
- Fix: issue `#88 <https://git.ziirish.me/ziirish/burp-ui/issues/88>`_
- Fix: issue `#92 <https://git.ziirish.me/ziirish/burp-ui/issues/92>`_
- Fix: issue `#95 <https://git.ziirish.me/ziirish/burp-ui/issues/95>`_
- Fix: issue `#99 <https://git.ziirish.me/ziirish/burp-ui/issues/99>`_
- Fix: issue `#100 <https://git.ziirish.me/ziirish/burp-ui/issues/100>`_
- Fix: issue `#101 <https://git.ziirish.me/ziirish/burp-ui/issues/101>`_
- `demo <https://demo.ziirish.me/>`_ - `demo <https://demo.ziirish.me/>`_
- API refactoring - API refactoring
- Security fixes - Security fixes
- Bugfixes - Bugfixes
- `Full changelog <https://git.ziirish.me/ziirish/burp-ui/compare/0.0.7...master>`__
0.0.7.3 (09/26/2015) 0.0.7.3 (09/26/2015)
-------------------- --------------------
- Fix issue `#77 <https://git.ziirish.me/ziirish/burp-ui/issues/77>`_ - Fix: issue `#77 <https://git.ziirish.me/ziirish/burp-ui/issues/77>`_
- Doc - Doc
0.0.7.2 (09/01/2015) 0.0.7.2 (09/01/2015)
-------------------- --------------------
- Fix issue `#73 <https://git.ziirish.me/ziirish/burp-ui/issues/72>`_ - Fix: issue `#73 <https://git.ziirish.me/ziirish/burp-ui/issues/72>`_
- Fix issue `#74 <https://git.ziirish.me/ziirish/burp-ui/issues/74>`_ - Fix: issue `#74 <https://git.ziirish.me/ziirish/burp-ui/issues/74>`_
- Doc - Doc
0.0.7.1 (08/22/2015) 0.0.7.1 (08/22/2015)
-------------------- --------------------
- Add `Burp-2 backend <https://git.ziirish.me/ziirish/burp-ui/issues/52>`_ - Add: `Burp-2 backend <https://git.ziirish.me/ziirish/burp-ui/issues/52>`_
- Add `sortable tables <https://git.ziirish.me/ziirish/burp-ui/issues/51>`_ - Add: `sortable tables <https://git.ziirish.me/ziirish/burp-ui/issues/51>`_
- Add `ACL support <https://git.ziirish.me/ziirish/burp-ui/issues/47>`_ - Add: `ACL support <https://git.ziirish.me/ziirish/burp-ui/issues/47>`_
- Add `support client-side encrypted backups while performing an online restoration <https://git.ziirish.me/ziirish/burp-ui/issues/44>`_ - Add: `support client-side encrypted backups while performing an online restoration <https://git.ziirish.me/ziirish/burp-ui/issues/44>`_
- Add `multiple archive format <https://git.ziirish.me/ziirish/burp-ui/issues/31>`_ - Add: `multiple archive format <https://git.ziirish.me/ziirish/burp-ui/issues/31>`_
- Add `better Active Directory support <https://git.ziirish.me/ziirish/burp-ui/issues/64>`__ - Add: `better Active Directory support <https://git.ziirish.me/ziirish/burp-ui/issues/64>`__
- Improvement: `better config file parser <https://git.ziirish.me/ziirish/burp-ui/issues/50>`_ - Improvement: `better config file parser <https://git.ziirish.me/ziirish/burp-ui/issues/50>`_
- Improvement: `better logging with Gunicorn <https://git.ziirish.me/ziirish/burp-ui/issues/65>`_ - Improvement: `better logging with Gunicorn <https://git.ziirish.me/ziirish/burp-ui/issues/65>`_
- Improvement: `full support of server configuration file + clientconfdir <https://git.ziirish.me/ziirish/burp-ui/issues/13>`_ - Improvement: `full support of server configuration file + clientconfdir <https://git.ziirish.me/ziirish/burp-ui/issues/13>`_
- Fix issue `#35 <https://git.ziirish.me/ziirish/burp-ui/issues/35>`_ - Fix: issue `#35 <https://git.ziirish.me/ziirish/burp-ui/issues/35>`_
- Fix issue `#37 <https://git.ziirish.me/ziirish/burp-ui/issues/37>`_ - Fix: issue `#37 <https://git.ziirish.me/ziirish/burp-ui/issues/37>`_
- Fix issue `#41 <https://git.ziirish.me/ziirish/burp-ui/issues/41>`_ - Fix: issue `#41 <https://git.ziirish.me/ziirish/burp-ui/issues/41>`_
- Fix issue `#42 <https://git.ziirish.me/ziirish/burp-ui/issues/42>`_ - Fix: issue `#42 <https://git.ziirish.me/ziirish/burp-ui/issues/42>`_
- Fix issue `#46 <https://git.ziirish.me/ziirish/burp-ui/issues/46>`_ - Fix: issue `#46 <https://git.ziirish.me/ziirish/burp-ui/issues/46>`_
- Fix issue `#49 <https://git.ziirish.me/ziirish/burp-ui/issues/49>`_ - Fix: issue `#49 <https://git.ziirish.me/ziirish/burp-ui/issues/49>`_
- Fix issue `#53 <https://git.ziirish.me/ziirish/burp-ui/issues/53>`_ - Fix: issue `#53 <https://git.ziirish.me/ziirish/burp-ui/issues/53>`_
- Fix issue `#54 <https://git.ziirish.me/ziirish/burp-ui/issues/54>`_ - Fix: issue `#54 <https://git.ziirish.me/ziirish/burp-ui/issues/54>`_
- Fix issue `#59 <https://git.ziirish.me/ziirish/burp-ui/issues/59>`_ - Fix: issue `#59 <https://git.ziirish.me/ziirish/burp-ui/issues/59>`_
- Fix issue `#62 <https://git.ziirish.me/ziirish/burp-ui/issues/62>`_ - Fix: issue `#62 <https://git.ziirish.me/ziirish/burp-ui/issues/62>`_
- Fix issue `#68 <https://git.ziirish.me/ziirish/burp-ui/issues/68>`_ - Fix: issue `#68 <https://git.ziirish.me/ziirish/burp-ui/issues/68>`_
- Fix issue `#69 <https://git.ziirish.me/ziirish/burp-ui/issues/69>`_ - Fix: issue `#69 <https://git.ziirish.me/ziirish/burp-ui/issues/69>`_
- Fix issue `#70 <https://git.ziirish.me/ziirish/burp-ui/issues/70>`_ - Fix: issue `#70 <https://git.ziirish.me/ziirish/burp-ui/issues/70>`_
- Fix issue `#71 <https://git.ziirish.me/ziirish/burp-ui/issues/71>`_ - Fix: issue `#71 <https://git.ziirish.me/ziirish/burp-ui/issues/71>`_
- Fix issue `#72 <https://git.ziirish.me/ziirish/burp-ui/issues/72>`_ - Fix: issue `#72 <https://git.ziirish.me/ziirish/burp-ui/issues/72>`_
- doc on `readthedocs <http://burp-ui.readthedocs.org/en/latest/>`_ - doc on `readthedocs <http://burp-ui.readthedocs.io/en/latest/>`_
- Two merge requests from Wade Fitzpatrick (`!1 <https://git.ziirish.me/ziirish/burp-ui/merge_requests/1>`_ and `!2 <https://git.ziirish.me/ziirish/burp-ui/merge_requests/2>`_) - Two merge requests from Wade Fitzpatrick (`!1 <https://git.ziirish.me/ziirish/burp-ui/merge_requests/1>`_ and `!2 <https://git.ziirish.me/ziirish/burp-ui/merge_requests/2>`_)
- API refactoring - API refactoring
- Security fixes - Security fixes
...@@ -80,19 +120,19 @@ Current ...@@ -80,19 +120,19 @@ Current
0.0.6 (12/15/2014) 0.0.6 (12/15/2014)
------------------ ------------------
- Add `gunicorn support <https://git.ziirish.me/ziirish/burp-ui/commit/836f522f51ba0706ca94b379d93b20c75e71ecb1>`_ - Add: `gunicorn support <https://git.ziirish.me/ziirish/burp-ui/commit/836f522f51ba0706ca94b379d93b20c75e71ecb1>`_
- Add `init script for CentOS <https://git.ziirish.me/ziirish/burp-ui/issues/27>`_ - Add: `init script for CentOS <https://git.ziirish.me/ziirish/burp-ui/issues/27>`_
- Add `init script for Debian <https://git.ziirish.me/ziirish/burp-ui/issues/29>`_ - Add: `init script for Debian <https://git.ziirish.me/ziirish/burp-ui/issues/29>`_
- Add `autofocus login field on login page <https://git.ziirish.me/ziirish/burp-ui/commit/a559c3c2191991f1065ff15df4cd94757133e67d>`_ - Add: `autofocus login field on login page <https://git.ziirish.me/ziirish/burp-ui/commit/a559c3c2191991f1065ff15df4cd94757133e67d>`_
- Add `burp-server configuration panel <https://git.ziirish.me/ziirish/burp-ui/issues/13>`_ - Add: `burp-server configuration panel <https://git.ziirish.me/ziirish/burp-ui/issues/13>`_
- Fix issue `#25 <https://git.ziirish.me/ziirish/burp-ui/issues/25>`_ - Fix: issue `#25 <https://git.ziirish.me/ziirish/burp-ui/issues/25>`_
- Fix issue `#26 <https://git.ziirish.me/ziirish/burp-ui/issues/26>`_ - Fix: issue `#26 <https://git.ziirish.me/ziirish/burp-ui/issues/26>`_
- Fix issue `#30 <https://git.ziirish.me/ziirish/burp-ui/issues/30>`_ - Fix: issue `#30 <https://git.ziirish.me/ziirish/burp-ui/issues/30>`_
- Fix issue `#32 <https://git.ziirish.me/ziirish/burp-ui/issues/32>`_ - Fix: issue `#32 <https://git.ziirish.me/ziirish/burp-ui/issues/32>`_
- Fix issue `#33 <https://git.ziirish.me/ziirish/burp-ui/issues/33>`_ - Fix: issue `#33 <https://git.ziirish.me/ziirish/burp-ui/issues/33>`_
- Fix issue `#34 <https://git.ziirish.me/ziirish/burp-ui/issues/34>`_ - Fix: issue `#34 <https://git.ziirish.me/ziirish/burp-ui/issues/34>`_
- Fix issue `#35 <https://git.ziirish.me/ziirish/burp-ui/issues/35>`_ - Fix: issue `#35 <https://git.ziirish.me/ziirish/burp-ui/issues/35>`_
- Fix issue `#39 <https://git.ziirish.me/ziirish/burp-ui/issues/39>`_ - Fix: issue `#39 <https://git.ziirish.me/ziirish/burp-ui/issues/39>`_
- Code cleanup - Code cleanup
- Improve unit tests - Improve unit tests
- Bugfixes - Bugfixes
...@@ -101,20 +141,20 @@ Current ...@@ -101,20 +141,20 @@ Current
0.0.5 (09/22/2014) 0.0.5 (09/22/2014)
------------------ ------------------
- Add multi-server support - Add: multi-server support
- Fix bugs - Fix bugs
- `Full changelog <https://git.ziirish.me/ziirish/burp-ui/compare/v0.0.4...v0.0.5>`__ - `Full changelog <https://git.ziirish.me/ziirish/burp-ui/compare/v0.0.4...v0.0.5>`__
0.0.4 (09/07/2014) 0.0.4 (09/07/2014)
------------------ ------------------
- Add the ability to download files directly from the web interface - Add: ability to download files directly from the web interface
- `Full changelog <https://git.ziirish.me/ziirish/burp-ui/compare/v0.0.3...v0.0.4>`__ - `Full changelog <https://git.ziirish.me/ziirish/burp-ui/compare/v0.0.3...v0.0.4>`__
0.0.3 (09/02/2014) 0.0.3 (09/02/2014)
------------------ ------------------
- Add authentication - Add: authentication
- `Full changelog <https://git.ziirish.me/ziirish/burp-ui/compare/v0.0.2...v0.0.3>`__ - `Full changelog <https://git.ziirish.me/ziirish/burp-ui/compare/v0.0.2...v0.0.3>`__
0.0.2 (08/25/2014) 0.0.2 (08/25/2014)
......
...@@ -2,5 +2,5 @@ CONTRIBUTING ...@@ -2,5 +2,5 @@ CONTRIBUTING
============ ============
Please refer to the contributing Please refer to the contributing
`page <https://burp-ui.readthedocs.org/en/latest/contributing.html>`_ available `page <https://burp-ui.readthedocs.io/en/stable/contributing.html>`_ available
in the documentation. in the documentation.
This is a non-exhaustive list of people that have submitted patches or
contributed significantly to the project.
Sorted by surname (or nickname).
bedaes
Wade Fitzpatrick
Graham Keeling (main author of Burp)
larsen0815
Benjamin SANS (main author)
slarti5191
Badges Badges
====== ======
.. image:: https://ci.ziirish.me/projects/1/status.png?ref=stable .. image:: https://git.ziirish.me/ci/projects/1/status.png?ref=master
:target: https://ci.ziirish.me/projects/1?ref=stable :target: https://git.ziirish.me/ci/projects/1?ref=master
:alt: Build Status :alt: Build Status
.. image:: https://readthedocs.org/projects/burp-ui/badge/?version=stable .. image:: https://readthedocs.org/projects/burp-ui/badge/?version=stable
...@@ -58,14 +58,14 @@ Documentation ...@@ -58,14 +58,14 @@ Documentation
============= =============
The documentation is hosted on `readthedocs <https://readthedocs.org>`_ at the The documentation is hosted on `readthedocs <https://readthedocs.org>`_ at the
following address: `burp-ui.readthedocs.org following address: `burp-ui.readthedocs.io
<https://burp-ui.readthedocs.org/en/stable/>`_ <https://burp-ui.readthedocs.io/en/stable/>`_
FAQ FAQ
=== ===
A `FAQ <https://burp-ui.readthedocs.org/en/stable/faq.html>`_ is available with A `FAQ <https://burp-ui.readthedocs.io/en/stable/faq.html>`_ is available with
the documentation. the documentation.
...@@ -73,7 +73,7 @@ Community ...@@ -73,7 +73,7 @@ Community
========= =========
Please refer to the `Contributing Please refer to the `Contributing
<https://burp-ui.readthedocs.org/en/stable/contributing.html>`_ page. <https://burp-ui.readthedocs.io/en/stable/contributing.html>`_ page.
Notes Notes
...@@ -83,7 +83,7 @@ Feel free to report any issues on my `gitlab ...@@ -83,7 +83,7 @@ Feel free to report any issues on my `gitlab
<https://git.ziirish.me/ziirish/burp-ui/issues>`_. <https://git.ziirish.me/ziirish/burp-ui/issues>`_.
I have closed the *github tracker* to have a unique tracker system. I have closed the *github tracker* to have a unique tracker system.
Also please, read the `Contributing Also please, read the `Contributing
<https://burp-ui.readthedocs.org/en/stable/contributing.html>`_ <https://burp-ui.readthedocs.io/en/stable/contributing.html>`_
page before reporting any issue to make sure we have all the informations to page before reporting any issue to make sure we have all the informations to
help you. help you.
...@@ -120,6 +120,8 @@ Thanks ...@@ -120,6 +120,8 @@ Thanks
Thank you all for your feedbacks and bug reports those are making the project Thank you all for your feedbacks and bug reports those are making the project
moving forward. moving forward.
Thank you to the `Flask`_'s developers and community.
Special Thanks to Graham Keeling for its great piece of software! This project Special Thanks to Graham Keeling for its great piece of software! This project
would not exist without `Burp`_. would not exist without `Burp`_.
......
0.1.0 0.2.0
...@@ -13,6 +13,7 @@ jQuery/Bootstrap ...@@ -13,6 +13,7 @@ jQuery/Bootstrap
import os import os
import sys import sys
import logging import logging
from logging import Formatter
if sys.version_info < (3, 0): if sys.version_info < (3, 0):
reload(sys) reload(sys)
...@@ -22,7 +23,7 @@ __title__ = 'burp-ui' ...@@ -22,7 +23,7 @@ __title__ = 'burp-ui'
__author__ = 'Benjamin SANS (Ziirish)' __author__ = 'Benjamin SANS (Ziirish)'
__author_email__ = 'hi+burpui@ziirish.me' __author_email__ = 'hi+burpui@ziirish.me'
__url__ = 'https://git.ziirish.me/ziirish/burp-ui' __url__ = 'https://git.ziirish.me/ziirish/burp-ui'
__doc__ = 'https://burp-ui.readthedocs.org/en/latest/' __doc__ = 'https://burp-ui.readthedocs.io/en/stable/'
__description__ = ('Burp-UI is a web-ui for burp backup written in python with ' __description__ = ('Burp-UI is a web-ui for burp backup written in python with '
'Flask and jQuery/Bootstrap') 'Flask and jQuery/Bootstrap')
__license__ = 'BSD 3-clause' __license__ = 'BSD 3-clause'
...@@ -40,7 +41,7 @@ except: # pragma: no cover ...@@ -40,7 +41,7 @@ except: # pragma: no cover
def lookup_config(conf=None): def lookup_config(conf=None):
ret = None ret = None
if conf: if conf:
if os.path.isfile(conf): if os.path.isfile(conf) or conf == '/dev/null':
ret = conf ret = conf
else: else:
raise IOError('File not found: \'{0}\''.format(conf)) raise IOError('File not found: \'{0}\''.format(conf))
...@@ -58,12 +59,24 @@ def lookup_config(conf=None): ...@@ -58,12 +59,24 @@ def lookup_config(conf=None):
'burpui', 'burpui',
'etc' 'etc'
) )
root3 = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
'..',
'..',
'..',
'..',
'share',
'burpui',
'etc',
)
conf_files = [ conf_files = [
'/etc/burp/burpui.cfg', '/etc/burp/burpui.cfg',
os.path.join(root, 'burpui.cfg'), os.path.join(root, 'burpui.cfg'),
os.path.join(root, 'burpui.sample.cfg'), os.path.join(root, 'burpui.sample.cfg'),
os.path.join(root2, 'burpui.cfg'), os.path.join(root2, 'burpui.cfg'),
os.path.join(root2, 'burpui.sample.cfg') os.path.join(root2, 'burpui.sample.cfg'),
os.path.join(root3, 'burpui.cfg'),
os.path.join(root3, 'burpui.sample.cfg')
] ]
for p in conf_files: for p in conf_files:
if os.path.isfile(p): if os.path.isfile(p):
...@@ -73,14 +86,14 @@ def lookup_config(conf=None): ...@@ -73,14 +86,14 @@ def lookup_config(conf=None):
return ret return ret
def init(conf=None, debug=0, logfile=None, gunicorn=True, unittest=False): def init(conf=None, verbose=0, logfile=None, gunicorn=True, unittest=False, debug=False):
"""Initialize the whole application. """Initialize the whole application.
:param conf: Configuration file to use :param conf: Configuration file to use
:type conf: str :type conf: str
:param debug: Enable verbose output :param verbose: Set the verbosity level
:type debug: int :type verbose: int
:param logfile: Store the logs in the given file :param logfile: Store the logs in the given file
:type logfile: str :type logfile: str
...@@ -88,15 +101,84 @@ def init(conf=None, debug=0, logfile=None, gunicorn=True, unittest=False): ...@@ -88,15 +101,84 @@ def init(conf=None, debug=0, logfile=None, gunicorn=True, unittest=False):
:param gunicorn: Enable gunicorn engine instead of flask's default :param gunicorn: Enable gunicorn engine instead of flask's default
:type gunicorn: bool :type gunicorn: bool
:param unittest: Are we running tests (used for test only)
:type unittest: bool
:param debug: Enable debug mode
:type debug: bool
:returns: A :class:`burpui.server.BUIServer` object :returns: A :class:`burpui.server.BUIServer` object
""" """
from flask.ext.login import LoginManager from flask_login import LoginManager
from flask.ext.bower import Bower from flask_bower import Bower
from .utils import basic_login_from_request from .utils import basic_login_from_request, ReverseProxied
from .server import BUIServer as BurpUI from .server import BUIServer as BurpUI
from .routes import view from .routes import view
from .api import api, apibp from .api import api, apibp
logger = logging.getLogger('burp-ui')
# The debug argument used to be a boolean so we keep supporting this format
if isinstance(verbose, bool):
if verbose:
verbose = logging.DEBUG
else:
verbose = logging.CRITICAL
else:
levels = [
logging.CRITICAL,
logging.ERROR,
logging.WARNING,
logging.INFO,
logging.DEBUG
]
if verbose >= len(levels):
verbose = len(levels) - 1
if not verbose:
verbose = 0
verbose = levels[verbose]
if logfile:
from logging.handlers import RotatingFileHandler
handler = RotatingFileHandler(
logfile,
maxBytes=1024 * 1024 * 100,
backupCount=5
)
else:
from logging import StreamHandler
handler = StreamHandler()
if verbose > logging.DEBUG:
LOG_FORMAT = (
'[%(asctime)s] %(levelname)s in '
'%(module)s.%(funcName)s: %(message)s'
)
else:
LOG_FORMAT = (
'-' * 80 + '\n' +
'%(levelname)s in %(module)s.%(funcName)s ' +
'[%(pathname)s:%(lineno)d]:\n' +
'%(message)s\n' +
'-' * 80
)
handler.setLevel(verbose)
handler.setFormatter(Formatter(LOG_FORMAT))
logger.setLevel(verbose)
logger.addHandler(handler)
logger.debug(
'conf: {}\n'.format(conf) +
'verbose: {}\n'.format(logging.getLevelName(verbose)) +
'logfile: {}\n'.format(logfile) +
'gunicorn: {}\n'.format(gunicorn) +
'debug: {}\n'.format(debug) +
'unittest: {}'.format(unittest)
)
if not unittest: if not unittest:
from ._compat import patch_json from ._compat import patch_json
patch_json() patch_json()
...@@ -107,72 +189,47 @@ def init(conf=None, debug=0, logfile=None, gunicorn=True, unittest=False): ...@@ -107,72 +189,47 @@ def init(conf=None, debug=0, logfile=None, gunicorn=True, unittest=False):
# We initialize the core # We initialize the core
app = BurpUI() app = BurpUI()
app.enable_logger()
app.gunicorn = gunicorn app.gunicorn = gunicorn
app.config['CFG'] = None app.config['CFG'] = None
# FIXME: strange behavior when bundling errors
# app.config['BUNDLE_ERRORS'] = True
app.config['REMEMBER_COOKIE_HTTPONLY'] = True
app.secret_key = ('VpgOXNXAgcO81xFPyWj07ppN6kExNZeCDRShseNzFKV7ZCgmW2/eLn6x'
'Slt7pYAVBj12zx2Vv9Kw3Q3jd1266A==')
app.jinja_env.globals.update( app.jinja_env.globals.update(
isinstance=isinstance, isinstance=isinstance,
list=list, list=list,
version_id='{}-{}'.format(__version__, __release__) version_id='{}-{}'.format(__version__, __release__)
) )
# The debug argument used to be a boolean so we keep supporting this format if debug and not gunicorn: # pragma: no cover
if isinstance(debug, bool):
if debug:
debug = logging.DEBUG
else:
debug = logging.NOTSET
else:
levels = [
logging.NOTSET,
logging.ERROR,
logging.WARNING,
logging.INFO,
logging.DEBUG
]
if debug >= len(levels):
debug = len(levels) - 1
if not debug:
debug = 0
debug = levels[debug]
if debug != logging.NOTSET and not gunicorn: # pragma: no cover
app.config['DEBUG'] = True and not unittest app.config['DEBUG'] = True and not unittest
app.config['TESTING'] = True and not unittest app.config['TESTING'] = True and not unittest
if logfile:
from logging import Formatter
from logging.handlers import RotatingFileHandler
file_handler = RotatingFileHandler(
logfile,
maxBytes=1024 * 1024 * 100,
backupCount=20
)
if debug < logging.INFO:
LOG_FORMAT = (
'-' * 80 + '\n' +
'%(levelname)s in %(module)s.%(funcName)s ' +
'[%(pathname)s:%(lineno)d]:\n' +
'%(message)s\n' +
'-' * 80
)
else:
LOG_FORMAT = ('[%(asctime)s] %(levelname)s in '
'%(module)s.%(funcName)s: %(message)s')
file_handler.setLevel(debug)
file_handler.setFormatter(Formatter(LOG_FORMAT))
app.logger.addHandler(file_handler)
# Still need to test conf file here because the init function can be called # Still need to test conf file here because the init function can be called
# by gunicorn directly # by gunicorn directly
app.config['CFG'] = lookup_config(conf) app.config['CFG'] = lookup_config(conf)
logger.info('Using configuration: {}'.format(app.config['CFG']))
app.setup(app.config['CFG']) app.setup(app.config['CFG'])
# manage application secret key
if not app.secret_key or app.secret_key.lower() == 'random' and \
not gunicorn:
from base64 import b64encode
app.secret_key = b64encode(os.urandom(256))
elif app.secret_key.lower() == 'none' or \
(app.secret_key.lower() == 'random' and gunicorn):
app.secret_key = None
app.wsgi_app = ReverseProxied(app.wsgi_app, app)
# Manage gunicorn special tricks & improvements
if gunicorn: # pragma: no cover if gunicorn: # pragma: no cover
logger.info('Using gunicorn')
from werkzeug.contrib.fixers import ProxyFix from werkzeug.contrib.fixers import ProxyFix
if app.storage and app.storage.lower() == 'redis': if app.storage and app.storage.lower() == 'redis':
if app.redis: if app.redis:
...@@ -185,16 +242,19 @@ def init(conf=None, debug=0, logfile=None, gunicorn=True, unittest=False): ...@@ -185,16 +242,19 @@ def init(conf=None, debug=0, logfile=None, gunicorn=True, unittest=False):
else: else:
host = 'localhost' host = 'localhost'
port = 6379 port = 6379
logger.debug('Using redis {}:{}'.format(host, port))
try: try:
from redis import Redis from redis import Redis
from flask.ext.session import Session from flask_session import Session
red = Redis(host=host, port=port) red = Redis(host=host, port=port)
app.config['SESSION_TYPE'] = 'redis' app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = red app.config['SESSION_REDIS'] = red
app.config['SESSION_COOKIE_SECURE'] = app.scookie app.config['SESSION_USE_SIGNER'] = app.secret_key != None
app.config['SESSION_PERMANENT'] = False
ses = Session() ses = Session()
ses.init_app(app) ses.init_app(app)
except: except Exception as e:
logger.warning('Unable to initialize redis: {}'.format(str(e)))
pass pass
api.cache.init_app( api.cache.init_app(
app, app,
...@@ -215,12 +275,6 @@ def init(conf=None, debug=0, logfile=None, gunicorn=True, unittest=False): ...@@ -215,12 +275,6 @@ def init(conf=None, debug=0, logfile=None, gunicorn=True, unittest=False):
else: else:
api.cache.init_app(app) api.cache.init_app(app)
# Then we load our routes
view.init_bui(app)
view.__url__ = __url__
view.__doc__ = __doc__
app.register_blueprint(view)
# We initialize the API # We initialize the API
api.init_bui(app) api.init_bui(app)
api.version = __version__ api.version = __version__
...@@ -229,6 +283,12 @@ def init(conf=None, debug=0, logfile=None, gunicorn=True, unittest=False): ...@@ -229,6 +283,12 @@ def init(conf=None, debug=0, logfile=None, gunicorn=True, unittest=False):
api.__doc__ = __doc__ api.__doc__ = __doc__
app.register_blueprint(apibp) app.register_blueprint(apibp)
# Then we load our routes
view.init_bui(app)
view.__url__ = __url__
view.__doc__ = __doc__
app.register_blueprint(view)
# And the login_manager # And the login_manager
app.login_manager = LoginManager() app.login_manager = LoginManager()
app.login_manager.login_view = 'view.login' app.login_manager.login_view = 'view.login'
...@@ -244,12 +304,23 @@ def init(conf=None, debug=0, logfile=None, gunicorn=True, unittest=False): ...@@ -244,12 +304,23 @@ def init(conf=None, debug=0, logfile=None, gunicorn=True, unittest=False):
bower = Bower() bower = Bower()
bower.init_app(app) bower.init_app(app)
@app.before_request
def setup_request():
if app.scookie:
from flask import request
criteria = [
request.is_secure,
request.headers.get('X-Forwarded-Proto', 'http') == 'https'
]
app.config['SESSION_COOKIE_SECURE'] = \
app.config['REMEMBER_COOKIE_SECURE'] = any(criteria)
@app.login_manager.user_loader @app.login_manager.user_loader
def load_user(userid): def load_user(userid):
"""User loader callback""" """User loader callback"""
if app.auth != 'none': if app.auth != 'none':
return app.uhandler.user(userid) return app.uhandler.user(userid)
return None # pragma: no cover return None
@app.login_manager.request_loader @app.login_manager.request_loader
def load_user_from_request(request): def load_user_from_request(request):
......
...@@ -13,7 +13,7 @@ def parse_args(mode=True, name=None): ...@@ -13,7 +13,7 @@ def parse_args(mode=True, name=None):
name = 'burp-ui' name = 'burp-ui'
parser = ArgumentParser(prog=name) parser = ArgumentParser(prog=name)
parser.add_argument('-v', '--verbose', dest='log', help='increase output verbosity (e.g., -vv is more verbose than -v)', action='count') parser.add_argument('-v', '--verbose', dest='log', help='increase output verbosity (e.g., -vv is more verbose than -v)', action='count')
parser.add_argument('-d', '--debug', dest='log', help='alias for -v', action='count') # alias for -v parser.add_argument('-d', '--debug', dest='debug', help='enable debug mode', action='store_true') # alias for -v
parser.add_argument('-V', '--version', dest='version', help='print version and exit', action='store_true') parser.add_argument('-V', '--version', dest='version', help='print version and exit', action='store_true')
parser.add_argument('-c', '--config', dest='config', help='configuration file', metavar='<CONFIG>') parser.add_argument('-c', '--config', dest='config', help='configuration file', metavar='<CONFIG>')
parser.add_argument('-l', '--logfile', dest='logfile', help='output logs in defined file', metavar='<FILE>') parser.add_argument('-l', '--logfile', dest='logfile', help='output logs in defined file', metavar='<FILE>')
...@@ -54,7 +54,7 @@ def server(options=None): ...@@ -54,7 +54,7 @@ def server(options=None):
conf = lookup_config(options.config) conf = lookup_config(options.config)
check_config(conf) check_config(conf)
server = init(conf, options.log, options.logfile, False) server = init(conf, options.log, options.logfile, False, debug=options.debug)
server.manual_run() server.manual_run()
...@@ -85,12 +85,24 @@ def agent(options=None): ...@@ -85,12 +85,24 @@ def agent(options=None):
'burpui', 'burpui',
'etc' 'etc'
) )
root3 = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
'..',
'..',
'..',
'..',
'share',
'burpui',
'etc',
)
conf_files = [ conf_files = [
'/etc/burp/buiagent.cfg', '/etc/burp/buiagent.cfg',
os.path.join(root, 'buiagent.cfg'), os.path.join(root, 'buiagent.cfg'),
os.path.join(root, 'buiagent.sample.cfg'), os.path.join(root, 'buiagent.sample.cfg'),
os.path.join(root2, 'buiagent.cfg'), os.path.join(root2, 'buiagent.cfg'),
os.path.join(root2, 'buiagent.sample.cfg') os.path.join(root2, 'buiagent.sample.cfg'),
os.path.join(root3, 'buiagent.cfg'),
os.path.join(root3, 'buiagent.sample.cfg')
] ]
for p in conf_files: for p in conf_files:
if os.path.isfile(p): if os.path.isfile(p):
...@@ -99,7 +111,7 @@ def agent(options=None): ...@@ -99,7 +111,7 @@ def agent(options=None):
check_config(conf) check_config(conf)
agent = Agent(conf, options.log, options.logfile) agent = Agent(conf, options.log, options.logfile, options.debug)
agent.run() agent.run()
......
...@@ -11,28 +11,26 @@ import sys ...@@ -11,28 +11,26 @@ import sys
import os import os
try: try:
import ConfigParser # NOQA import ConfigParser # noqa
except ImportError: except ImportError:
import configparser as ConfigParser # NOQA import configparser as ConfigParser # noqa
try: try:
import cPickle as pickle # NOQA import cPickle as pickle # noqa
except ImportError: except ImportError:
import pickle # NOQA import pickle # noqa
if sys.version_info[0] >= 3: if sys.version_info[0] >= 3:
PY3 = True PY3 = True
from urllib.parse import unquote # NOQA from urllib.parse import unquote # noqa
else: else:
PY3 = False PY3 = False
from urllib import unquote # NOQA from urllib import unquote # noqa
IS_GUNICORN = 'gunicorn' in os.environ.get('SERVER_SOFTWARE', '') if 'gunicorn' in os.environ.get('SERVER_SOFTWARE', ''):
IS_GUNICORN = True
if IS_GUNICORN:
from gevent.local import local # NOQA
else: else:
local = object IS_GUNICORN = False
# maps module name -> attribute name -> original item # maps module name -> attribute name -> original item
...@@ -66,7 +64,7 @@ def patch_module(name, items=None): ...@@ -66,7 +64,7 @@ def patch_module(name, items=None):
def patch_json(): def patch_json():
try: try:
import ujson # NOQA import ujson # noqa
except ImportError: except ImportError:
# ujson is not available, we won't patch anything # ujson is not available, we won't patch anything
return return
......
...@@ -12,4 +12,4 @@ ...@@ -12,4 +12,4 @@
from . import init from . import init
app = init(gunicorn=False) app = init(conf='/dev/null', gunicorn=False)
...@@ -13,6 +13,7 @@ from logging.handlers import RotatingFileHandler ...@@ -13,6 +13,7 @@ from logging.handlers import RotatingFileHandler
from .exceptions import BUIserverException from .exceptions import BUIserverException
from .misc.backend.interface import BUIbackend from .misc.backend.interface import BUIbackend
from ._compat import ConfigParser, pickle from ._compat import ConfigParser, pickle
from .utils import BUIlogging
g_port = u'10000' g_port = u'10000'
g_bind = u'::' g_bind = u'::'
...@@ -43,9 +44,8 @@ class BurpHandler(BUIbackend): ...@@ -43,9 +44,8 @@ class BurpHandler(BUIbackend):
mod = __import__(module, fromlist=['Burp']) mod = __import__(module, fromlist=['Burp'])
Client = mod.Burp Client = mod.Burp
self.backend = Client(conf=conf) self.backend = Client(conf=conf)
self.backend.set_logger(self.logger)
except Exception as e: except Exception as e:
self._logger('error', '{}\n\nFailed loading backend for Burp version {}: {}'.format(traceback.format_exc(), self.vers, str(e))) self.logger.error('{}\n\nFailed loading backend for Burp version {}: {}'.format(traceback.format_exc(), self.vers, str(e)))
sys.exit(2) sys.exit(2)
def __getattribute__(self, name): def __getattribute__(self, name):
...@@ -60,7 +60,7 @@ class BurpHandler(BUIbackend): ...@@ -60,7 +60,7 @@ class BurpHandler(BUIbackend):
return object.__getattribute__(self, name) return object.__getattribute__(self, name)
class BUIAgent(BUIbackend): class BUIAgent(BUIbackend, BUIlogging):
BUIbackend.__abstractmethods__ = frozenset() BUIbackend.__abstractmethods__ = frozenset()
defaults = { defaults = {
'port': g_port, 'bind': g_bind, 'port': g_port, 'bind': g_bind,
...@@ -68,30 +68,37 @@ class BUIAgent(BUIbackend): ...@@ -68,30 +68,37 @@ class BUIAgent(BUIbackend):
'version': g_version, 'password': g_password 'version': g_version, 'password': g_password
} }
def __init__(self, conf=None, debug=False, logfile=None): def __init__(self, conf=None, level=0, logfile=None, debug=False):
self.conf = conf self.conf = conf
self.dbg = debug self.debug = debug
self.padding = 1 self.padding = 1
if debug > logging.NOTSET: if level > logging.NOTSET:
logging.addLevelName(DISCLOSURE, 'DISCLOSURE') logging.addLevelName(DISCLOSURE, 'DISCLOSURE')
levels = [0, logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG, DISCLOSURE] levels = [
if debug >= len(levels): logging.CRITICAL,
debug = len(levels) - 1 logging.ERROR,
lvl = levels[debug] logging.WARNING,
self.app.logger = logging.getLogger(__name__) logging.INFO,
self.set_logger(self.app.logger) logging.DEBUG,
DISCLOSURE
]
if level >= len(levels):
level = len(levels) - 1
lvl = levels[level]
self.logger.setLevel(lvl) self.logger.setLevel(lvl)
if logfile: if lvl > logging.DEBUG:
handler = RotatingFileHandler(logfile, maxBytes=1024 * 1024 * 100, backupCount=20)
LOG_FORMAT = '[%(asctime)s] %(levelname)s in %(module)s.%(funcName)s: %(message)s' LOG_FORMAT = '[%(asctime)s] %(levelname)s in %(module)s.%(funcName)s: %(message)s'
else: else:
handler = logging.StreamHandler()
LOG_FORMAT = ( LOG_FORMAT = (
'-' * 80 + '\n' + '-' * 80 + '\n' +
'%(levelname)s in %(module)s.%(funcName)s [%(pathname)s:%(lineno)d]:\n' + '%(levelname)s in %(module)s.%(funcName)s [%(pathname)s:%(lineno)d]:\n' +
'%(message)s\n' + '%(message)s\n' +
'-' * 80 '-' * 80
) )
if logfile:
handler = RotatingFileHandler(logfile, maxBytes=1024 * 1024 * 100, backupCount=20)
else:
handler = logging.StreamHandler()
handler.setLevel(lvl) handler.setLevel(lvl)
handler.setFormatter(logging.Formatter(LOG_FORMAT)) handler.setFormatter(logging.Formatter(LOG_FORMAT))
self.logger.addHandler(handler) self.logger.addHandler(handler)
...@@ -184,6 +191,12 @@ class BUIAgent(BUIbackend): ...@@ -184,6 +191,12 @@ class BUIAgent(BUIbackend):
self.request.sendall(buf) self.request.sendall(buf)
buf = f.read(1024) buf = f.read(1024)
os.unlink(res) os.unlink(res)
lengthbuf = self.request.recv(8)
length, = struct.unpack('!Q', lengthbuf)
data = self.recvall(length)
txt = data.decode('UTF-8')
if txt == 'RE':
return
else: else:
self.request.sendall(struct.pack('!Q', len(res))) self.request.sendall(struct.pack('!Q', len(res)))
self.request.sendall(res.encode('UTF-8')) self.request.sendall(res.encode('UTF-8'))
......
...@@ -10,18 +10,17 @@ ...@@ -10,18 +10,17 @@
""" """
import os import os
import sys import sys
import json
from flask import Blueprint, Response, request from flask import Blueprint, Response, request
from flask.ext.restplus import Api from flask_restplus import Api
from flask.ext.login import current_user from flask_login import current_user
from flask.ext.cache import Cache from flask_cache import Cache
from importlib import import_module from importlib import import_module
from functools import wraps from functools import wraps
from .._compat import IS_GUNICORN from .._compat import IS_GUNICORN, PY3
if sys.version_info >= (3, 0): # pragma: no cover if PY3: # pragma: no cover
basestring = str basestring = str
EXEMPT_METHODS = set(['OPTIONS']) EXEMPT_METHODS = set(['OPTIONS'])
...@@ -33,7 +32,7 @@ if IS_GUNICORN: ...@@ -33,7 +32,7 @@ if IS_GUNICORN:
import gevent import gevent
from gevent.queue import Queue from gevent.queue import Queue
ret = [] ret = []
api.bui.cli._logger('debug', 'Using gevent') api.bui.cli.logger.debug('Using gevent')
if not callable(func): if not callable(func):
api.abort(500, 'The provided \'func\' is not callable!') api.abort(500, 'The provided \'func\' is not callable!')
...@@ -127,7 +126,7 @@ def api_login_required(func): ...@@ -127,7 +126,7 @@ def api_login_required(func):
class ApiWrapper(Api): class ApiWrapper(Api):
"""Wrapper class around :class:`flask.ext.restplus.Api`""" """Wrapper class around :class:`flask_restplus.Api`"""
cache = Cache(config={'CACHE_TYPE': 'null', 'CACHE_NO_NULL_WARNING': True}) cache = Cache(config={'CACHE_TYPE': 'null', 'CACHE_NO_NULL_WARNING': True})
loaded = False loaded = False
release = None release = None
...@@ -143,17 +142,6 @@ class ApiWrapper(Api): ...@@ -143,17 +142,6 @@ class ApiWrapper(Api):
self.bui = bui self.bui = bui
self.load_all() self.load_all()
def abort(self, code=500, message=None, **kwargs):
"""Override :func:`flask.ext.restplus.Api.abort` in order to raise
custom exceptions
"""
if message and not isinstance(message, basestring):
try:
message = json.dumps(message) # pragma: no cover
except:
message = None
super(ApiWrapper, self).abort(code, message, **kwargs) # pragma: no cover
def load_all(self): def load_all(self):
"""hack to automatically import api modules""" """hack to automatically import api modules"""
if not self.loaded: if not self.loaded:
...@@ -165,7 +153,7 @@ class ApiWrapper(Api): ...@@ -165,7 +153,7 @@ class ApiWrapper(Api):
ext == '.py' and ext == '.py' and
name not in ['__init__', '.', '..']): name not in ['__init__', '.', '..']):
mod = '.' + name mod = '.' + name
import_module(mod, 'burpui.api') import_module(mod, __name__)
apibp = Blueprint('api', __name__, url_prefix='/api') apibp = Blueprint('api', __name__, url_prefix='/api')
......
# -*- coding: utf8 -*-
"""
.. module:: burpui.api.backup
:platform: Unix
:synopsis: Burp-UI backup api module.
.. moduleauthor:: Ziirish <hi+burpui@ziirish.me>
"""
from . import api
from .custom import Resource
from ..exceptions import BUIserverException
ns = api.namespace('backup', 'Backup methods')
@ns.route('/server-backup/<name>',
'/<server>/server-backup/<name>',
methods=['GET', 'DELETE'],
endpoint='is_server_backup')
@ns.route('/do-server-backup/<name>',
'/<server>/do-server-backup/<name>',
methods=['PUT'],
endpoint='server_backup')
class ServerBackup(Resource):
"""The :class:`burpui.api.backup.ServerBackup` resource allows you to
prepare a server-initiated backup.
This resource is part of the :mod:`burpui.api.backup` module.
"""
@ns.doc(
params={
'server': 'Which server to collect data from when in multi-agent mode',
'name': 'Client name',
},
responses={
200: 'Success',
400: 'Missing parameter',
403: 'Insufficient permissions',
500: 'Internal failure',
},
)
def get(self, server=None, name=None):
"""Tells if a 'backup' file is present
**GET** method provided by the webservice.
:param server: Which server to collect data from when in multi-agent
mode
:type server: str
:param name: The client we are working on
:type name: str
:returns: True if the file is found
"""
if not name:
self.abort(400, 'Missing options')
# Manage ACL
if (api.bui.acl and
(not api.bui.acl.is_client_allowed(self.username,
name,
server) and not
self.is_admin)):
self.abort(403, 'You are not allowed to access this client')
try:
return {'is_server_backup': api.bui.cli.is_server_backup(name, server)}
except BUIserverException as e:
self.abort(500, str(e))
@ns.doc(
params={
'server': 'Which server to collect data from when in multi-agent mode',
'name': 'Client name',
},
responses={
200: 'Success',
400: 'Missing parameter',
403: 'Insufficient permissions',
500: 'Internal failure',
},
)
def delete(self, server=None, name=None):
"""Remove the 'backup' file if present
**DELETE** method provided by the webservice.
:param server: Which server to collect data from when in multi-agent
mode
:type server: str
:param name: The client we are working on
:type name: str
:returns: Status message (success or failure)
"""
if not name:
self.abort(400, 'Missing options')
# Manage ACL
if (api.bui.acl and
(not api.bui.acl.is_client_allowed(self.username,
name,
server) and not
self.is_admin)):
self.abort(403, 'You are not allowed to cancel a backup for this client')
try:
return api.bui.cli.cancel_server_backup(name, server)
except BUIserverException as e:
self.abort(500, str(e))
@ns.doc(
params={
'server': 'Which server to collect data from when in multi-agent mode',
'name': 'Client name',
},
responses={
201: 'Success',
400: 'Missing parameter',
403: 'Insufficient permissions',
500: 'Internal failure',
},
)
def put(self, server=None, name=None):
"""Schedule a server-initiated backup
**PUT** method provided by the webservice.
:param server: Which server to collect data from when in multi-agent
mode
:type server: str
:param name: The client we are working on
:type name: str
:returns: Status message (success or failure)
"""
json = []
# Check params
if not name:
self.abort(400, 'Missing options')
# Manage ACL
if (api.bui.acl and
(not api.bui.acl.is_client_allowed(self.username,
name,
server) and not
self.is_admin and
(to and not
api.bui.acl.is_client_allowed(self.username,
to,
server)))):
self.abort(
403,
'You are not allowed to schedule a backup for this client'
)
try:
json = api.bui.cli.server_backup(name, server)
return json, 201
except BUIserverException as e:
self.abort(500, str(e))
This diff is collapsed.
...@@ -7,13 +7,11 @@ ...@@ -7,13 +7,11 @@
.. moduleauthor:: Ziirish <hi+burpui@ziirish.me> .. moduleauthor:: Ziirish <hi+burpui@ziirish.me>
""" """
# This is a submodule we can also use "from ..api import api"
from . import api, cache_key from . import api, cache_key
from .custom import fields, Resource from .custom import fields, Resource
from ..exceptions import BUIserverException from ..exceptions import BUIserverException
from six import iteritems from six import iteritems
from flask.ext.login import current_user
ns = api.namespace('clients', 'Clients methods') ns = api.namespace('clients', 'Clients methods')
...@@ -33,14 +31,14 @@ class RunningClients(Resource): ...@@ -33,14 +31,14 @@ class RunningClients(Resource):
in multi-agent mode. in multi-agent mode.
""" """
parser = api.parser() parser = api.parser()
parser.add_argument('serverName', type=str, help='Which server to collect data from when in multi-agent mode') parser.add_argument('serverName', help='Which server to collect data from when in multi-agent mode')
@api.doc( @ns.expect(parser)
@ns.doc(
params={ params={
'server': 'Which server to collect data from when in multi-agent mode', 'server': 'Which server to collect data from when in multi-agent mode',
'client': 'Client name', 'client': 'Client name',
}, },
parser=parser
) )
def get(self, client=None, server=None): def get(self, client=None, server=None):
"""Returns a list of clients currently running a backup """Returns a list of clients currently running a backup
...@@ -67,8 +65,8 @@ class RunningClients(Resource): ...@@ -67,8 +65,8 @@ class RunningClients(Resource):
server = server or self.parser.parse_args()['serverName'] server = server or self.parser.parse_args()['serverName']
if client: if client:
if api.bui.acl: if api.bui.acl:
if (not api.bui.acl.is_admin(current_user.get_id()) and not if (not self.is_admin and not
api.bui.acl.is_client_allowed(current_user.get_id(), api.bui.acl.is_client_allowed(self.username,
client, client,
server)): server)):
r = [] r = []
...@@ -82,16 +80,15 @@ class RunningClients(Resource): ...@@ -82,16 +80,15 @@ class RunningClients(Resource):
r = api.bui.cli.is_one_backup_running(server) r = api.bui.cli.is_one_backup_running(server)
# Manage ACL # Manage ACL
if (api.bui.acl and not if api.bui.acl and not self.is_admin:
api.bui.acl.is_admin(current_user.get_id())):
if isinstance(r, dict): if isinstance(r, dict):
new = {} new = {}
for serv in api.bui.acl.servers(current_user.get_id()): for serv in api.bui.acl.servers(self.username):
allowed = api.bui.acl.clients(current_user.get_id(), serv) allowed = api.bui.acl.clients(self.username, serv)
new[serv] = [x for x in r[serv] if x in allowed] new[serv] = [x for x in r[serv] if x in allowed]
r = new r = new
else: else:
allowed = api.bui.acl.clients(current_user.get_id(), server) allowed = api.bui.acl.clients(self.username, server)
r = [x for x in r if x in allowed] r = [x for x in r if x in allowed]
return r return r
...@@ -110,8 +107,8 @@ class RunningBackup(Resource): ...@@ -110,8 +107,8 @@ class RunningBackup(Resource):
'running': fields.Boolean(required=True, description='Is there a backup running right now'), 'running': fields.Boolean(required=True, description='Is there a backup running right now'),
}) })
@api.marshal_with(running_fields, code=200, description='Success') @ns.marshal_with(running_fields, code=200, description='Success')
@api.doc( @ns.doc(
params={ params={
'server': 'Which server to collect data from when in multi-agent mode', 'server': 'Which server to collect data from when in multi-agent mode',
} }
...@@ -139,16 +136,15 @@ class RunningBackup(Resource): ...@@ -139,16 +136,15 @@ class RunningBackup(Resource):
""" """
j = api.bui.cli.is_one_backup_running(server) j = api.bui.cli.is_one_backup_running(server)
# Manage ACL # Manage ACL
if (api.bui.acl and not if api.bui.acl and not self.is_admin:
api.bui.acl.is_admin(current_user.get_id())):
if isinstance(j, dict): if isinstance(j, dict):
new = {} new = {}
for serv in api.bui.acl.servers(current_user.get_id()): for serv in api.bui.acl.servers(self.username):
allowed = api.bui.acl.clients(current_user.get_id(), serv) allowed = api.bui.acl.clients(self.username, serv)
new[serv] = [x for x in j[serv] if x in allowed] new[serv] = [x for x in j[serv] if x in allowed]
j = new j = new
else: else:
allowed = api.bui.acl.clients(current_user.get_id(), server) allowed = api.bui.acl.clients(self.username, server)
j = [x for x in j if x in allowed] j = [x for x in j if x in allowed]
r = False r = False
if isinstance(j, dict): if isinstance(j, dict):
...@@ -174,7 +170,7 @@ class ClientsReport(Resource): ...@@ -174,7 +170,7 @@ class ClientsReport(Resource):
in multi-agent mode. in multi-agent mode.
""" """
parser = api.parser() parser = api.parser()
parser.add_argument('serverName', type=str, help='Which server to collect data from when in multi-agent mode') parser.add_argument('serverName', help='Which server to collect data from when in multi-agent mode')
stats_fields = api.model('ClientsStats', { stats_fields = api.model('ClientsStats', {
'total': fields.Integer(required=True, description='Number of files', default=0), 'total': fields.Integer(required=True, description='Number of files', default=0),
'totsize': fields.Integer(required=True, description='Total size occupied by all the backups of this client', default=0), 'totsize': fields.Integer(required=True, description='Total size occupied by all the backups of this client', default=0),
...@@ -194,8 +190,9 @@ class ClientsReport(Resource): ...@@ -194,8 +190,9 @@ class ClientsReport(Resource):
}) })
@api.cache.cached(timeout=1800, key_prefix=cache_key) @api.cache.cached(timeout=1800, key_prefix=cache_key)
@api.marshal_with(report_fields, code=200, description='Success') @ns.marshal_with(report_fields, code=200, description='Success')
@api.doc( @ns.expect(parser)
@ns.doc(
params={ params={
'server': 'Which server to collect data from when in multi-agent mode', 'server': 'Which server to collect data from when in multi-agent mode',
}, },
...@@ -203,7 +200,6 @@ class ClientsReport(Resource): ...@@ -203,7 +200,6 @@ class ClientsReport(Resource):
403: 'Insufficient permissions', 403: 'Insufficient permissions',
500: 'Internal failure', 500: 'Internal failure',
}, },
parser=parser
) )
def get(self, server=None): def get(self, server=None):
"""Returns a global report about all the clients of a given server """Returns a global report about all the clients of a given server
...@@ -258,19 +254,18 @@ class ClientsReport(Resource): ...@@ -258,19 +254,18 @@ class ClientsReport(Resource):
j = {} j = {}
# Manage ACL # Manage ACL
if (not api.bui.standalone and api.bui.acl and if (not api.bui.standalone and api.bui.acl and
(not api.bui.acl.is_admin(current_user.get_id()) and (not self.is_admin and
server not in server not in
api.bui.acl.servers(current_user.get_id()))): api.bui.acl.servers(self.username))):
api.abort(403, 'Sorry, you don\'t have any rights on this server') self.abort(403, 'Sorry, you don\'t have any rights on this server')
clients = [] clients = []
if (api.bui.acl and not if api.bui.acl and not self.is_admin:
api.bui.acl.is_admin(current_user.get_id())): clients = [{'name': x} for x in api.bui.acl.clients(self.username, server)]
clients = [{'name': x} for x in api.bui.acl.clients(current_user.get_id(), server)]
else: else:
try: try:
clients = api.bui.cli.get_all_clients(agent=server) clients = api.bui.cli.get_all_clients(agent=server)
except BUIserverException as e: except BUIserverException as e:
api.abort(500, str(e)) self.abort(500, str(e))
j = api.bui.cli.get_clients_report(clients, server) j = api.bui.cli.get_clients_report(clients, server)
return j return j
...@@ -288,7 +283,7 @@ class ClientsStats(Resource): ...@@ -288,7 +283,7 @@ class ClientsStats(Resource):
in multi-agent mode. in multi-agent mode.
""" """
parser = api.parser() parser = api.parser()
parser.add_argument('serverName', type=str, help='Which server to collect data from when in multi-agent mode') parser.add_argument('serverName', help='Which server to collect data from when in multi-agent mode')
client_fields = api.model('ClientsStatsSingle', { client_fields = api.model('ClientsStatsSingle', {
'last': fields.DateTime(required=True, dt_format='iso8601', description='Date of last backup'), 'last': fields.DateTime(required=True, dt_format='iso8601', description='Date of last backup'),
'name': fields.String(required=True, description='Client name'), 'name': fields.String(required=True, description='Client name'),
...@@ -298,8 +293,9 @@ class ClientsStats(Resource): ...@@ -298,8 +293,9 @@ class ClientsStats(Resource):
}) })
@api.cache.cached(timeout=1800, key_prefix=cache_key) @api.cache.cached(timeout=1800, key_prefix=cache_key)
@api.marshal_list_with(client_fields, code=200, description='Success') @ns.marshal_list_with(client_fields, code=200, description='Success')
@api.doc( @ns.expect(parser)
@ns.doc(
params={ params={
'server': 'Which server to collect data from when in multi-agent mode', 'server': 'Which server to collect data from when in multi-agent mode',
}, },
...@@ -307,7 +303,6 @@ class ClientsStats(Resource): ...@@ -307,7 +303,6 @@ class ClientsStats(Resource):
403: 'Insufficient permissions', 403: 'Insufficient permissions',
500: 'Internal failure', 500: 'Internal failure',
}, },
parser=parser
) )
def get(self, server=None): def get(self, server=None):
"""Returns a list of clients with their states """Returns a list of clients with their states
...@@ -350,14 +345,13 @@ class ClientsStats(Resource): ...@@ -350,14 +345,13 @@ class ClientsStats(Resource):
try: try:
if (not api.bui.standalone and if (not api.bui.standalone and
api.bui.acl and api.bui.acl and
(not api.bui.acl.is_admin(current_user.get_id()) and (not self.is_admin and
server not in server not in
api.bui.acl.servers(current_user.get_id()))): api.bui.acl.servers(self.username))):
api.abort(403, 'Sorry, you don\'t have any rights on this server') self.abort(403, 'Sorry, you don\'t have any rights on this server')
j = api.bui.cli.get_all_clients(agent=server) j = api.bui.cli.get_all_clients(agent=server)
if (api.bui.acl and not if api.bui.acl and not self.is_admin:
api.bui.acl.is_admin(current_user.get_id())): j = [x for x in j if x['name'] in api.bui.acl.clients(self.username, server)]
j = [x for x in j if x['name'] in api.bui.acl.clients(current_user.get_id(), server)]
except BUIserverException as e: except BUIserverException as e:
api.abort(500, str(e)) self.abort(500, str(e))
return j return j
...@@ -7,4 +7,4 @@ ...@@ -7,4 +7,4 @@
.. moduleauthor:: Ziirish <hi+burpui@ziirish.me> .. moduleauthor:: Ziirish <hi+burpui@ziirish.me>
""" """
from .resource import Resource from .resource import Resource # noqa
...@@ -8,5 +8,5 @@ ...@@ -8,5 +8,5 @@
""" """
from flask.ext.restplus.fields import * from flask_restplus.fields import * # noqa
from .my_fields import DateTime, BackupNumber from .my_fields import DateTime, BackupNumber # noqa
# -*- coding: utf8 -*-
"""
.. module:: burpui.api.custom.inputs
:platform: Unix
:synopsis: Burp-UI api custom inputs module.
.. moduleauthor:: Ziirish <hi+burpui@ziirish.me>
"""
from flask_restplus.inputs import * # noqa
from .my_inputs import boolean # noqa
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
""" """
import arrow import arrow
from flask.ext.restplus import fields from flask_restplus import fields
from tzlocal import get_localzone from tzlocal import get_localzone
......
# -*- coding: utf8 -*-
"""
.. module:: burpui.api.custom.my_inputs
:platform: Unix
:synopsis: Burp-UI api custom inputs module.
.. moduleauthor:: Ziirish <hi+burpui@ziirish.me>
"""
from flask_restplus.inputs import boolean as boolean_ori
def boolean(value):
"""
Parse the string ``"true"`` or ``"false"`` as a boolean (case insensitive).
Also accepts ``"1"`` and ``"0"`` as ``True``/``False`` (respectively).
A form checkbox returns ``"on"`` when checked. This will be treated as
``True``.
If the input is from the request JSON body, the type is already a native
python boolean, and will be passed through without further parsing.
:raises ValueError: if the boolean value is invalid
"""
try:
return boolean_ori(value)
except ValueError as e:
if not value:
return False
value = value.lower()
if value == 'on':
return True
raise e