+++ /dev/null
-include *.md
-recursive-include src *.py *.conf *.plate *.bat
+++ /dev/null
-Subproject commit d56cc513fb57eb18fd1b0be7f70513f459093f51
+++ /dev/null
-# Makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line.
-SPHINXOPTS =
-SPHINXBUILD = sphinx-build
-PAPER =
-BUILDDIR = _build
-
-# Internal variables.
-PAPEROPT_a4 = -D latex_paper_size=a4
-PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-# the i18n builder cannot share the environment and doctrees with the others
-I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-
-.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
-
-help:
- @echo "Please use \`make <target>' where <target> is one of"
- @echo " html to make standalone HTML files"
- @echo " dirhtml to make HTML files named index.html in directories"
- @echo " singlehtml to make a single large HTML file"
- @echo " pickle to make pickle files"
- @echo " json to make JSON files"
- @echo " htmlhelp to make HTML files and a HTML help project"
- @echo " qthelp to make HTML files and a qthelp project"
- @echo " devhelp to make HTML files and a Devhelp project"
- @echo " epub to make an epub"
- @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
- @echo " latexpdf to make LaTeX files and run them through pdflatex"
- @echo " text to make text files"
- @echo " man to make manual pages"
- @echo " texinfo to make Texinfo files"
- @echo " info to make Texinfo files and run them through makeinfo"
- @echo " gettext to make PO message catalogs"
- @echo " changes to make an overview of all changed/added/deprecated items"
- @echo " linkcheck to check all external links for integrity"
- @echo " doctest to run all doctests embedded in the documentation (if enabled)"
-
-clean:
- -rm -rf $(BUILDDIR)/*
-
-html:
- $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
- @echo
- @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
-
-dirhtml:
- $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
- @echo
- @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
-
-singlehtml:
- $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
- @echo
- @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
-
-pickle:
- $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
- @echo
- @echo "Build finished; now you can process the pickle files."
-
-json:
- $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
- @echo
- @echo "Build finished; now you can process the JSON files."
-
-htmlhelp:
- $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
- @echo
- @echo "Build finished; now you can run HTML Help Workshop with the" \
- ".hhp project file in $(BUILDDIR)/htmlhelp."
-
-qthelp:
- $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
- @echo
- @echo "Build finished; now you can run "qcollectiongenerator" with the" \
- ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
- @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/sploitego.qhcp"
- @echo "To view the help file:"
- @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/sploitego.qhc"
-
-devhelp:
- $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
- @echo
- @echo "Build finished."
- @echo "To view the help file:"
- @echo "# mkdir -p $$HOME/.local/share/devhelp/sploitego"
- @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/sploitego"
- @echo "# devhelp"
-
-epub:
- $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
- @echo
- @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
-
-latex:
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
- @echo
- @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
- @echo "Run \`make' in that directory to run these through (pdf)latex" \
- "(use \`make latexpdf' here to do that automatically)."
-
-latexpdf:
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
- @echo "Running LaTeX files through pdflatex..."
- $(MAKE) -C $(BUILDDIR)/latex all-pdf
- @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
-
-text:
- $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
- @echo
- @echo "Build finished. The text files are in $(BUILDDIR)/text."
-
-man:
- $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
- @echo
- @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
-
-texinfo:
- $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
- @echo
- @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
- @echo "Run \`make' in that directory to run these through makeinfo" \
- "(use \`make info' here to do that automatically)."
-
-info:
- $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
- @echo "Running Texinfo files through makeinfo..."
- make -C $(BUILDDIR)/texinfo info
- @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
-
-gettext:
- $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
- @echo
- @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
-
-changes:
- $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
- @echo
- @echo "The overview file is in $(BUILDDIR)/changes."
-
-linkcheck:
- $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
- @echo
- @echo "Link check complete; look for any errors in the above output " \
- "or in $(BUILDDIR)/linkcheck/output.txt."
-
-doctest:
- $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
- @echo "Testing of doctests in the sources finished, look at the " \
- "results in $(BUILDDIR)/doctest/output.txt."
+++ /dev/null
-.. _ref_canari_commander:
-
-Canari Commander
-================
-
-The Canari commander (``canari``) script provides all of the functionality to create, debug, execute, distribute, and
-install transforms. The ``canari`` commander provides the following set of commands:
-
-+--------------------------+-------------------------------------------------------------------------------------------+
-| Canari Command | Description |
-+==========================+===========================================================================================+
-| :ref:`create-package` | Creates a Canari transform package skeleton. |
-+--------------------------+-------------------------------------------------------------------------------------------+
-| :ref:`create-transform` | Creates a new transform in the specified directory and auto-updates ``__init__.py``. |
-+--------------------------+-------------------------------------------------------------------------------------------+
-| :ref:`csv2sheets` | Convert mixed entity type CSVs to separated CSV sheets. |
-+--------------------------+-------------------------------------------------------------------------------------------+
-| :ref:`debug-transform` | Runs Canari local transforms in a terminal-friendly fashion. |
-+--------------------------+-------------------------------------------------------------------------------------------+
-| :ref:`delete-transform` | Deletes a transform in the specified directory and auto-updates ``__init__.py``. |
-+--------------------------+-------------------------------------------------------------------------------------------+
-| :ref:`generate-entities` | Converts Maltego entity definition files to Canari python classes. Excludes Maltego |
-| | built-in entities. |
-+--------------------------+-------------------------------------------------------------------------------------------+
-| :ref:`help` | Provides detailed help on a specific command (alias for ``-h`` option in all commands). |
-+--------------------------+-------------------------------------------------------------------------------------------+
-| :ref:`install-package` | Installs and configures Canari transform packages in Maltego's UI |
-+--------------------------+-------------------------------------------------------------------------------------------+
-| :ref:`list-commands` | Lists all the available Canari commands |
-+--------------------------+-------------------------------------------------------------------------------------------+
-| :ref:`mtgx2csv` | Convert Maltego graph files (``*.mtgx``) to comma-separated values (CSV) file. |
-+--------------------------+-------------------------------------------------------------------------------------------+
-| :ref:`rename-transform` | Renames a transform in the specified directory and auto-updates ``__init__.py``. |
-+--------------------------+-------------------------------------------------------------------------------------------+
-| :ref:`run-server` | Runs a transform server for the given packages. |
-+--------------------------+-------------------------------------------------------------------------------------------+
-| :ref:`run-transform` | Runs Canari local transforms in a terminal-friendly fashion. |
-+--------------------------+-------------------------------------------------------------------------------------------+
-| :ref:`shell` | Creates a Canari debug shell for the specified transform package. |
-+--------------------------+-------------------------------------------------------------------------------------------+
-| :ref:`uninstall-package` | Uninstalls and unconfigures canari transform packages in Maltego's UI |
-+--------------------------+-------------------------------------------------------------------------------------------+
-
-
-Canari Commands
----------------
-
-The following subsections provide detailed information on each of the ``canari`` commands. Each of these commands accept
-an additional ``-h`` argument that is an alias to the ``help`` command.
-
-
-.. _list-commands:
-
-``list-commands``
-^^^^^^^^^^^^^^^^^
-
-The ``list-commands`` command accepts lists all of the available ``canari`` commands along with a brief description. It
-accepts no parameters::
-
- $ canari list-commands
- create-package - Creates a Canari transform package skeleton.
- create-transform - Creates a new transform in the specified directory and auto-updates __init__.py.
- csv2sheets - Convert mixed entity type CSVs to separated CSV sheets.
- debug-transform - Runs Canari local transforms in a terminal-friendly fashion.
- delete-transform - Deletes a transform in the specified directory and auto-updates __init__.py.
- generate-entities - Converts Maltego entity definition files to Canari python classes. Excludes Maltego built-in entities.
- install-package - Installs and configures canari transform packages in Maltego's UI
- list-commands - Lists all the available canari commands
- mtgx2csv - Convert Maltego graph files (*.mtgx) to comma-separated values (CSV) file.
- rename-transform - Renames a transform in the specified directory and auto-updates __init__.py.
- run-server - Runs a transform server for the given packages.
- run-transform - Runs Canari local transforms in a terminal-friendly fashion.
- shell - Creates a Canari debug shell for the specified transform package.
- uninstall-package - Uninstalls and unconfigures canari transform packages in Maltego's UI
- ...
-
-.. _help:
-
-``help``
-^^^^^^^^
-
-The ``help`` command displays detailed help on a specific ``canari`` command. It accepts the following parameters:
-
-* ``<command name>`` (**required**): the name of the ``canari`` command you're seeking help for.
-
-The following example illustrates the use of the ``canari help`` command to display detailed help for the
-``run-transform`` command::
-
- $ canari help run-transform
- usage: canari run-transform <transform> [param1 ... paramN] <value> [field1=value1...#fieldN=valueN]
-
- Runs Canari local transforms in a terminal-friendly fashion.
-
- positional arguments:
- <transform> The name of the transform you wish to run (e.g.
- sploitego.transforms.nmapfastscan).
- <value> The value of the input entity being passed into the
- local transform.
- [param1 ... paramN] Any extra parameters that can be sent to the local
- transform.
- [field1=value1...#fieldN=valueN]
- The fields of the input entity being passed into the
- local transform.
-
- optional arguments:
- -h, --help show this help message and exit
-
-.. _run-transform:
-
-``run-transform``
-^^^^^^^^^^^^^^^^^
-
-The ``run-transform`` command loads and executes the specified local transform module, returning transform results to
-the Maltego UI. It accepts the following parameters:
-
-* ``<transform module>`` (**required**): the name of the python module that contains the local transform data mining
- logic (e.g. :py:mod:`sploitego.transforms.whatismyip`)
-* ``[param1 ... paramN]`` (**optional**): any extra local transform parameters that can be parsed using
- :py:mod:`argparse` (e.g. ``-p 80``)
-* ``<value>`` (**required**): the value of the entity being passed into the local transform (e.g. ``google.com``)
-* ``[field1=value1...#fieldN=valueN]`` (**optional**): optionally, any entity field values delimited by # (e.g.
- ``url=http://www.google.ca#public=true``)
-
-The following example illustrates the use of ``canari run-transform`` to execute the :py:mod:`sploitego.transforms.whatismyip`
-transform module that comes bundled with the `Sploitego <https://github.com/allfro/sploitego>`_ transform package::
-
- $ canari run-transform sploitego.transforms.whatismyip -
- <MaltegoMessage><MaltegoTransformResponseMessage><Entities><Entity Type="maltego.IPv4Address"><Value>192.168.0.200</Value>
- <Weight>1</Weight><AdditionalFields><Field DisplayName="Internal" MatchingRule="strict" Name="ipaddress.internal">true</Field>
- <Field DisplayName="Hardware Address" MatchingRule="strict" Name="ethernet.hwaddr">de:ad:be:ef:fe:ed</Field></AdditionalFields>
- </Entity></Entities></MaltegoTransformResponseMessage></MaltegoMessage>
-
-.. _debug-transform:
-
-``debug-transform``
-^^^^^^^^^^^^^^^^^^^
-
-The ``debug-transform`` command operates in the same fashion as the :ref:`run-transform` command but outputs the result
-in a terminal friendly manner. The following example illustrates the use of ``canari debug-transform`` to execute the
-:py:mod:`sploitego.transforms.nmapfastscan` transform module on ``www.google.ca``::
-
- $ canari run-transform sploitego.transforms.nmapfastscan www.google.com
- `- MaltegoTransformResponseMessage:
- `- Entities:
- `- Entity: {'Type': 'sploitego.Port'}
- `- Value: 80
- `- Weight: 1
- `- AdditionalFields:
- `- Field: TCP {'DisplayName': 'Protocol', 'Name': 'protocol', 'MatchingRule': 'strict'}
- `- Field: Open {'DisplayName': 'Port Status', 'Name': 'port.status', 'MatchingRule': 'strict'}
- `- Field: 173.194.75.147 {'DisplayName': 'Destination IP', 'Name': 'ip.destination', 'MatchingRule': 'strict'}
- `- Field: syn-ack {'DisplayName': 'Port Response', 'Name': 'port.response', 'MatchingRule': 'strict'}
- `- IconURL: file:///Library/Python/2.6/site-packages/canari-1.0-py2.6.egg/canari/resources/images/networking/openport.gif
- `- DisplayInformation:
- `- Label: http {'Type': 'text/text', 'Name': 'Service Name'}
- `- Label: table {'Type': 'text/text', 'Name': 'Method'}
- ...
-
-
-.. _run-server:
-
-``run-server``
-^^^^^^^^^^^^^^
-
-The ``run-server`` command loads one or more transform packages and handles remote transform requests brokered by a
-`Transform Distribution Server (TDS) <http://paterva.com>`_ via port 80 or 443 (if SSL enabled). ``run-server``
-provides similar functionality to the `Paterva Transform Application Server <http://paterva.com>`_. It accepts the
-following parameters:
-
-* ``<package>`` (**required**): The name of the transform packages you wish to host (e.g. :py:mod:`mypkg.transforms`).
-* ``--port <port>`` (**optional**): The port the server will run on (default: 443; or 80 if SSL is disabled).
-* ``--disable-ssl`` (**optional**): Any extra parameters that can be sent to the local transform.
-* ``--enable-privileged`` (**optional**): permit TAS to run packages that require elevated privileges.
-* ``--listen-on <address>`` (**optional**): The address of the interface to listen on.
-* ``--cert <certificate>`` (**optional**): The name of the certificate file used for the server in PEM format.
-* ``--hostname <hostname>`` (**optional**): The hostname of this transform server.
-* ``--daemon`` (**optional**): Daemonize server (fork to background).
-
-The following example illustrates the use of ``canari run-server`` to operate a transform application server to serve
-transform requests for transforms belonging to the :py:mod:`sploitego` transform package::
-
- $ canari run-server sploitego --disable-ssl
- You must run this server as root to continue...
- Loading transform packages...
- Loading transform package sploitego.transforms
- WARNING: No route found for IPv6 destination :: (no default route?)
- Loading sploitego.transforms.bcsitereview at /sploitego.transforms.bcsitereview...
- Loading sploitego.transforms.sitereputation at /sploitego.transforms.sitereputation...
- Starting web server on :80...
- Really? Over regular HTTP? What a shame...
-
-
-.. note::
-
- ``run-server`` will automatically ask for ``root`` credentials if the server is listening on ports in the reserved
- range (0-1024) or if any of the transform modules within the specified transform package is decorated with the
- :py:func:`@superuser` decorator and ``--enable-privileged`` is set.
-
-.. _install-package:
-
-``install-package``
-^^^^^^^^^^^^^^^^^^^
-
-The ``install-package`` command installs and configures a transform package (transforms, entities, Maltego machines) in
-the Maltego UI. It accepts the following parameters:
-
-* ``<package>`` (**required**): name of the transform package that contains transform modules (i.e. ``canari``).
-* ``-s [dir]``, ``--settings-dir=[dir]`` (**optional**): the name of the directory that contains Maltego's settings.
-
-.. note::
-
- The Maltego settings directory is typically located in the following locations:
-
- * **Linux**: ``~/.maltego/<version>`` (i.e. ``~/.maltego/3.2.0``)
- * **Mac OS/X**: ``~/Library/Application\ Support/maltego/<version>`` (i.e. ``~/Library/Application\ Support/maltego/3.2.0``)
-
-* ``-w [dir]``, ``--working-dir=[dir]`` (**optional, default: current working directory**): the default working
- directory for the Maltego transforms.
-
-The following example illustrates the use of ``canari install-package`` command to install transforms from the
-:py:mod:`sploitego` transform package::
-
- $ canari install-package sploitego
- Installing transform sploitego.v2.NmapReportToBanner_Amap from sploitego.transforms.amap...
- Installing transform sploitego.v2.WebsiteToSiteCategory_BlueCoat from sploitego.transforms.bcsitereview...
- Installing transform sploitego.v2.DomainToDNSName_Bing from sploitego.transforms.bingsubdomains...
- Installing transform sploitego.v2.DNSNameToIPv4Address_DNS from sploitego.transforms.dnsalookup...
- Installing transform sploitego.v2.IPv4AddressToDNSName_CacheSnoop from sploitego.transforms.dnscachesnoop...
- Installing transform sploitego.v2.NSRecordToDNSName_CacheSnoop from sploitego.transforms.dnscachesnoop...
- ...
-
-.. warning::
-
- You must have initialized Maltego for the first time before attempting to install a transform package using
- ``install-package``. Otherwise, the installation will fail.
-
-.. warning::
-
- **DO NOT** run ``canari install-package`` as ``root`` unless you intend to run Maltego as ``root`` at all times.
-
-.. _uninstall-package:
-
-``uninstall-package``
-^^^^^^^^^^^^^^^^^^^^^
-
-The ``uninstall-package`` command uninstalls and un-configures all the local transform modules within the specified
-transform package in the Maltego UI. It accepts the following parameters:
-
-* ``<package>`` (**required**): name of the transform package that contains transform modules. (i.e. :py:mod:`sploitego`)
-* ``-s [dir]``, ``--settings-dir=[dir]`` (**optional**): the name of the directory that contains Maltego's settings
- (i.e. ``~/.maltego/<version>`` in Linux, ``~/Library/Application\ Support/maltego/<version>`` in Mac OS X)
-
-The following example illustrates the use of ``canari uninstall-package`` to uninstall transforms from the
-:py:mod:`sploitego` transform package::
-
- $ canari uninstall-package sploitego
- Multiple versions of Maltego detected:
- [0] Maltego v3.1.1
- [1] Maltego v3.1.1CE
- Please select which version you wish to install the transforms in [0]: 1
- Uninstalling transform sploitego.v2.NmapReportToBanner_Amap from sploitego.transforms.amap...
- Uninstalling transform sploitego.v2.WebsiteToSiteCategory_BlueCoat from sploitego.transforms.bcsitereview...
- Uninstalling transform sploitego.v2.DomainToDNSName_Bing from sploitego.transforms.bingsubdomains...
- Uninstalling transform sploitego.v2.DNSNameToIPv4Address_DNS from sploitego.transforms.dnsalookup...
- Uninstalling transform sploitego.v2.IPv4AddressToDNSName_CacheSnoop from sploitego.transforms.dnscachesnoop...
- Uninstalling transform sploitego.v2.NSRecordToDNSName_CacheSnoop from sploitego.transforms.dnscachesnoop...
-
-.. _shell:
-
-``shell``
-^^^^^^^^^
-
-The canari shell script offers an interactive shell for running transforms (work in progress). It accepts the following
-parameters:
-
-* ``<transform package>`` (**required**): the name of the transform package to load.
-
-The following example illustrates the use of canari shell to run transforms from the sploitego transform package::
-
- $ canari shell sploitego
- Welcome to Canari.
- mtg> whatismyip('4.2.2.1')
- `- MaltegoTransformResponseMessage:
- `- Entities:
- `- Entity: {'Type': 'maltego.IPv4Address'}
- `- Value: 10.0.1.22
- `- Weight: 1
- `- AdditionalFields:
- `- Field: true {'DisplayName': 'Internal', 'Name': 'ipaddress.internal', 'MatchingRule': 'strict'}
- `- Field: 68:a8:6d:4e:0f:72 {'DisplayName': 'Hardware Address', 'Name': 'ethernet.hwaddr', 'MatchingRule': 'strict'}
- mtg>
-
-.. _create-package:
-
-``create-package``
-^^^^^^^^^^^^^^^^^^
-
-The ``create-package`` command generates a transform package skeleton for eager transform developers. It accepts the
-following parameters:
-
-* ``<package name>`` (**required**): the desired name of the transform package you wish to develop.
-
-The following example illustrates the use of ``canari create-package`` to create a transform package named
-:py:mod:`foobar`::
-
- $ canari create-package foobar
- creating skeleton in foobar
- creating directory foobar
- creating directory foobar/src
- creating directory foobar/maltego
- creating directory foobar/src/foobar
- creating directory foobar/src/foobar/transforms
- creating directory foobar/src/foobar/transforms/common
- creating directory foobar/src/foobar/resources
- creating directory foobar/src/foobar/resources/etc
- creating directory foobar/src/foobar/resources/images
- creating file foobar/setup.py...
- creating file foobar/README.md...
- creating file foobar/src/foobar/__init__.py...
- creating file foobar/src/foobar/resources/__init__.py...
- creating file foobar/src/foobar/resources/etc/__init__.py...
- creating file foobar/src/foobar/resources/images/__init__.py...
- creating file foobar/src/foobar/resources/etc/foobar.conf...
- creating file foobar/src/foobar/transforms/__init__.py...
- creating file foobar/src/foobar/transforms/helloworld.py...
- creating file foobar/src/foobar/transforms/common/__init__.py...
- creating file foobar/src/foobar/transforms/common/entities.py...
- done!
-
-
-.. _create-transform:
-
-``create-transform``
-^^^^^^^^^^^^^^^^^^^^
-
-The ``create-transform`` command generates a transform module and automatically adds it to the ``__init__.py`` file in a
-transform package. It accepts the following parameters:
-
-* ``<transform name>`` (**required**): the desired name of the transform module to create.
-
-The following example illustrates the use of ``canari create-transform`` to create a transform module named
-:py:mod:`cooltransform`::
-
- $ cd foobar/src/foobar/transforms/
- $ canari create-transform cooltransform
- creating file ./cooltransform.py...
- updating __init__.py
- done!
-
-.. _rename-transform:
-
-``rename-transform``
-^^^^^^^^^^^^^^^^^^^^
-
-The ``rename-transform`` command renames a transform module and automatically updates the corresponding ``__init__.py``
-file entry in a transform package. It accepts the following parameters:
-
-* ``<old transform name>`` (**required**): the name of the transform module to rename.
-* ``<new transform name>`` (**required**): the new desired name of the transform module.
-
-The following example illustrates the use of ``canari rename-transform`` to rename a transform module named
-:py:mod:`cooltransform` to :py:mod:`mytransform`::
-
- $ cd foobar/src/foobar/transforms/
- $ canari rename-transform cooltransform mytransform
- renaming transform '/home/foo/foobar/src/foobar/transforms/cooltransform.py' to '/home/foo/foobar/src/foobar/transforms/mytransform.py'...
- updating /home/foo/foobar/src/foobar/transforms/__init__.py
- done!
-
-
-.. _delete-transform:
-
-``delete-transform``
-^^^^^^^^^^^^^^^^^^^^
-
-The ``delete-transform`` command deletes a transform module and automatically removes the corresponding ``__init__.py``
-file entry in a transform package. It accepts the following parameters:
-
-* ``<transform name>`` (**required**): the name of the transform module to delete.
-
-The following example illustrates the use of ``canari delete-transform`` to delete a transform module named
-:py:mod:`mytransform`::
-
- $ cd foobar/src/foobar/transforms/
- $ canari delete-transform mytransform
- deleting transform '/home/foo/foobar/src/foobar/transforms/poop.py'...
- updating /home/foo/foobar/src/foobar/transforms/__init__.py
- done!
-
-
-.. _generate-entities:
-
-``generate-entities``
-^^^^^^^^^^^^^^^^^^^^^
-
-The ``generate-entities`` command generates the Python/Canari definitions of the entities contained within Maltego or a
-Maltego entity export file (``*.mtz``) and writes the result to a file. The entities within the ``maltego`` namespace
-(or builtin entities) are automatically excluded and only custom entity definitions are generated. It accepts the
-following parameters:
-
-* ``<outfile>`` (**optional**): Which file to write the output to (default: ``entities.py``).
-* ``--mtz-file <mtzfile>``, ``-m <mtzfile>`` (**optional**): A ``*.mtz`` file containing an export of Maltego entities.
-* ``--exclude-namespace <namespace>``, ``-e <namespace>`` (**optional**): Name of Maltego entity namespace to ignore.
- Can be defined multiple times.
-* ``--namespace <namespace>``, ``-n <namespace>`` (**optional**): Name of Maltego entity namespace to generate entity
- classes for. Can be defined multiple times.
-* ``--append``, ``-a`` (**optional**): Whether or not to append to the existing ``entities.py`` file.
-* ``--entity <entity>``, ``-E <entity>`` (**optional**): Name of Maltego entity to generate Canari python class for.
-
-If no arguments are passed, the ``generate-entities`` command will load the entity definition files from Maltego's
-setting directory and automatically generate an ``entities.py`` file in the current working directory.
-
-.. warning::
-
- The ``generate-entities`` command will overwrite the current ``entities.py`` file if executed with no arguments in
- the ``src/<package>/transforms/common`` directory.
-
-
-.. _mtgx2csv:
-
-``mtgx2csv``
-^^^^^^^^^^^^
-
-The ``mtgx2csv`` command generates a comma-separated report (CSV) of a Maltego-generated graph. It accepts the
-following parameters:
-
-* ``<graph>`` (**required**): the name of the Maltego graph file.
-
-The following example illustrates the use of ``canari mtgx2csv`` to create a CSV report of a Maltego graph file named
-``Graph1.mtgx``::
-
- $ canari mtgx2csv ``Graph1.mtgx``
- $ ls *.csv
- Graph1.csv
-
-.. _csv2sheets:
-
-``csv2sheets``
-^^^^^^^^^^^^^^
-
-The ``csv2sheets`` command separates the CSV report file into multiple CSV files containing entities of the same type.
-It accepts the following parameters:
-
-* ``<csv report>`` (**required**): the name of the CSV report generated by ``canari mtgx2csv``
-* ``<prefix>`` (**required**): a prefix to prepend to the generated CSV files.
-
-The following example illustrates the use of ``canari csv2sheets`` to create a CSV files containing entities of the same
-type from the CSV report Graph1.csv::
-
- $ csv2sheets Graph1.csv IRS
- $ ls *.csv
- Graph1.csv IRS_0.csv IRS_1.csv ...
\ No newline at end of file
+++ /dev/null
-# -*- coding: utf-8 -*-
-#
-# canari documentation build configuration file, created by
-# sphinx-quickstart on Sat Aug 25 19:44:54 2012.
-#
-# This file is execfile()d with the current directory set to its containing dir.
-#
-# Note that not all possible configuration values are present in this
-# autogenerated file.
-#
-# All configuration values have a default; values that are commented out
-# serve to show the default.
-
-import sys, os
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-sys.path.insert(0, os.path.abspath('../src/'))
-
-# -- General configuration -----------------------------------------------------
-
-# If your documentation needs a minimal Sphinx version, state it here.
-#needs_sphinx = '1.0'
-
-# Add any Sphinx extension module names here, as strings. They can be extensions
-# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx']
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
-
-# The suffix of source filenames.
-source_suffix = '.rst'
-
-# The encoding of source files.
-#source_encoding = 'utf-8-sig'
-
-# The master toctree document.
-master_doc = 'index'
-
-# General information about the project.
-project = u'canari'
-copyright = u'2012, Canari Project'
-
-# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-#
-# The short X.Y version.
-version = '1.0'
-# The full version, including alpha/beta/rc tags.
-release = '1.0'
-
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-#language = None
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-#today = ''
-# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
-
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-exclude_patterns = ['_build']
-
-# The reST default role (used for this markup: `text`) to use for all documents.
-#default_role = None
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-#add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-#show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
-
-# A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
-
-
-# -- Options for HTML output ---------------------------------------------------
-
-# The theme to use for HTML and HTML Help pages. See the documentation for
-# a list of builtin themes.
-html_theme = 'default'
-
-# Theme options are theme-specific and customize the look and feel of a theme
-# further. For a list of options available for each theme, see the
-# documentation.
-#html_theme_options = {}
-
-# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
-
-# The name for this set of Sphinx documents. If None, it defaults to
-# "<project> v<release> documentation".
-#html_title = None
-
-# A shorter title for the navigation bar. Default is the same as html_title.
-#html_short_title = None
-
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-#html_logo = None
-
-# The name of an image file (within the static path) to use as favicon of the
-# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-#html_favicon = None
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
-
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-#html_use_smartypants = True
-
-# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
-
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-#html_additional_pages = {}
-
-# If false, no module index is generated.
-#html_domain_indices = True
-
-# If false, no index is generated.
-#html_use_index = True
-
-# If true, the index is split into individual pages for each letter.
-#html_split_index = False
-
-# If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
-
-# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
-
-# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-#html_show_copyright = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it. The value of this option must be the
-# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
-
-# This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'canaridoc'
-
-
-# -- Options for LaTeX output --------------------------------------------------
-
-latex_elements = {
-# The paper size ('letterpaper' or 'a4paper').
-#'papersize': 'letterpaper',
-
-# The font size ('10pt', '11pt' or '12pt').
-#'pointsize': '10pt',
-
-# Additional stuff for the LaTeX preamble.
-#'preamble': '',
-}
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, documentclass [howto/manual]).
-latex_documents = [
- ('index', 'canari.tex', u'Canari Framework Documentation',
- u'Nadeem Douba', 'manual'),
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-#latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-#latex_use_parts = False
-
-# If true, show page references after internal links.
-#latex_show_pagerefs = False
-
-# If true, show URL addresses after external links.
-#latex_show_urls = False
-
-# Documents to append as an appendix to all manuals.
-#latex_appendices = []
-
-# If false, no module index is generated.
-#latex_domain_indices = True
-
-
-# -- Options for manual page output --------------------------------------------
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-man_pages = [
- ('index', 'canari', u'Canari Framework Documentation',
- [u'Nadeem Douba'], 1)
-]
-
-# If true, show URL addresses after external links.
-#man_show_urls = False
-
-
-# -- Options for Texinfo output ------------------------------------------------
-
-# Grouping the document tree into Texinfo files. List of tuples
-# (source start file, target name, title, author,
-# dir menu entry, description, category)
-texinfo_documents = [
- ('index', 'canari', u'Canari Framework Documentation',
- u'Nadeem Douba', 'canari', 'A slick and easy Maltego local transform framework.',
- 'Miscellaneous'),
-]
-
-# Documents to append as an appendix to all manuals.
-#texinfo_appendices = []
-
-# If false, no module index is generated.
-#texinfo_domain_indices = True
-
-# How to display URL addresses: 'footnote', 'no', or 'inline'.
-#texinfo_show_urls = 'footnote'
-
-
-# Example configuration for intersphinx: refer to the Python standard library.
-intersphinx_mapping = {'http://docs.python.org/': None}
+++ /dev/null
-################################
-Transform Development Quickstart
-################################
-
-Developing local and remote transforms is a cinch with :py:mod:`canari`. Whether you want to develop a whole bunch of
-transforms or just one, you'll probably want to take advantage of :py:mod:`canari`'s amazing features. So let's get
-started with a quick tutorial on how you can take advantage of :py:mod:`canari`'s powerful transform framework. The
-following sections will give you a quick-start tutorial on how to develop transforms.
-
-Creating a Transform Package
-============================
-
-We'll just go ahead and create a transform package called :py:mod:`mypackage`::
-
- $ canari create-package mypackage
- creating skeleton in mypackage
- creating file setup.py...
- creating file README.md...
- creating file src/mypackage/transforms/common/entities.py...
- creating file src/mypackage/transforms/helloworld.py...
- creating file src/mypackage/__init__.py...
- creating file src/mypackage/transforms/__init__.py...
- creating file src/mypackage/transforms/common/__init__.py...
- done!
-
-
-You'll notice that a simple skeleton project was generated, with a :py:mod:`helloworld` transform to get you started.
-You can test the :py:mod:`helloworld` transform module right away by running `canari debug-transform` like so::
-
-
- $ canari debug-transform mypackage.transforms.helloworld Phil
- %50
- D:This was pointless!
- %100
- `- MaltegoTransformResponseMessage:
- `- Entities:
- `- Entity: {'Type': 'test.MyTestEntity'}
- `- Value: Hello Phil!
- `- Weight: 1
- `- AdditionalFields:
- `- Field: 2 {'DisplayName': 'Field 1', 'Name': 'test.field1', 'MatchingRule': 'strict'}
- `- Field: test {'DisplayName': 'Field N', 'Name': 'test.fieldN', 'MatchingRule': 'strict'}
-
-
-Developing a Transform
-======================
-
-Let's take a look at an abbreviated version of ``src/mypackage/transforms/helloworld.py``, from our example above,
-to see how this transform was put together:
-
-.. code-block:: python
-
- #!/usr/bin/env python
-
- from canari.maltego.message import Person
- from canari.maltego.utils import debug, progress
- from canari.framework import configure #, superuser
- from common.entities import MypackageEntity
-
- # ...
- #@superuser
- @configure(
- label='To MypackageEntity [Hello World]',
- description='Returns a MyPackageEntity entity with the phrase "Hello Word!"',
- uuids=[ 'mypackage.v2.MyPackageEntityToPhrase_HelloWorld' ],
- inputs=[ ( 'MyPackageEntity', Person ) ],
- debug=True
- )
- def dotransform(request, response):
- # Report transform progress
- progress(50)
- # Send a debugging message to the Maltego UI console
- debug('This was pointless!')
-
- # Create MyPackageEntity entity with value set to 'Hello <request.value>!'
- e = MypackageEntity('Hello %s!' % request.value)
-
- # Setting field values on the entity
- e.field1 = 2
- e.fieldN = 'test'
-
- # Update progress
- progress(100)
-
- # Add entity to response object
- response += e
-
- # Return response for visualization
- return response
-
-
- def onterminate():
- debug('Caught signal... exiting.')
- exit(0)
-
-
-Right away, you notice that there are a whole bunch of decorators (or annotations) and two functions
-(:py:func:`dotransform` and :py:func:`onterminate`). So what does this all mean and how does it work? Let's focus on the
-meat, shall we?
-
-The :py:func:`dotransform` function is the transform's entry point, this is where all the fun stuff happens. This
-transform isn't particularly fun, but it serves as a good example of what typically happens in a canari transform.
-:py:func:`dotransform` takes two arguments, :py:obj:`request` and :py:obj:`response`. The :py:obj:`request` object
-contains the data passed by Maltego to the local transform and is parsed and stored into the following properties:
-
-.. py:attribute:: value
-
- A string containing the value of the input entity.
-
-.. py:attribute:: fields
-
- A dictionary of entity field names and their respective values of the input entity.
-
-.. py:attribute:: params
-
- A list of any additional command-line arguments to be passed to the transform.
-
-The :py:obj:`response` object is what our data mining logic will populate with entities and it is of type
-:py:class:`MaltegoTransformResponseMessage`. The :py:obj:`response` object is very neat in the sense that it can do
-magical things with data. With simple arithematic operations (``+=``, ``-=``, ``+``, ``-``), one can add/remove entities
-or Maltego UI messages. You'll probably want to use the ``+=`` or ``-=`` operators because ``-`` and ``+`` create
-a new :py:class:`MaltegoTransformResponseMessage` object and that can be costly. Let's take a look at how it works in
-the transform above:
-
-.. code-block:: python
-
- # ...
- e = MypackageEntity('Hello %s!' % request.value)
- # ...
- response += e
- # ...
-
-
-The first line of code, creates a new :py:class:`MypackageEntity` object is created with a value
-``'Hello <request.value>!'``. The second line of code adds the newly created object, :py:data:`e`, to the
-:py:obj:`response` object. If we serialize the object into XML we'd see the following (spaced for clarity) output:
-
-.. code-block:: xml
-
- <MaltegoMessage>
- <MaltegoTransformResponseMessage>
- <Entities>
- <Entity Type="mypackage.MypackageEntity">
- <Value>Hello Phil!</Value>
- <Weight>1</Weight>
- <AdditionalFields>
- <Field DisplayName="Field 1" MatchingRule="strict" Name="mypackage.field1">2</Field>
- <Field DisplayName="Field N" MatchingRule="strict" Name="mypackage.fieldN">test</Field>
- </AdditionalFields>
- </Entity>
- </Entities>
- </MaltegoTransformResponseMessage>
- </MaltegoMessage>
-
-
-You may be wondering where those fields (``mypackage.field1`` and ``mypackage.fieldN``) came from? Simple, from here:
-
-.. code-block:: python
-
- # ...
- e.field1 = 2
- e.fieldN = 'test'
- # ...
-
-
-If your feeling eager, see :ref:`custom-entity` for more information on how those properties came to fruition.
-
-Once :py:func:`dotransform` is called, the data mining logic does it's thing and adds entities to the
-:py:obj:`response` object if necessary. Finally, the :py:obj:`response` is returned and :program:`dispatcher`
-serializes the object into XML. What about the decorators (:py:func:`@configure` and :py:func:`@superuser`)?
-Read on...
-
-
-``canari install-package`` Magic (:py:func:`@configure`)
------------------------------------------------------------
-
-So how does ``canari install-package`` figure out how to install and configure the transform in Maltego's UI? Simple,
-just use the :py:func:`@configure` decorator on your :py:func:`dotransform` function and ``canari install`` will take
-care of the rest. The :py:func:`@configure` decorator tells ``canari install-package`` how to install the transform
-in Maltego. It takes the following named parameters:
-
-.. py:function:: @configure(**kwargs)
-
- :keyword str label: The name of the transform as it appears in the Maltego UI transform selection menu.
- :keyword str description: A short description of the transform.
- :keyword list uuids: A list of unique transform IDs, one per input type. The order of this list must match that of
- the inputs parameter. Make sure you account for entity type inheritance in Maltego. For example,
- if you choose a :py:class:`DNSName` entity type as your input type you do not need to specify it
- again for :py:class:`MXRecord`, :py:class:`NSRecord`, etc.
- :keyword list inputs**: A list of tuples where the first item is the name of the transform set the transform should
- be part of, and the second item is the input entity type.
- :keyword bool debug: Whether or not the debugging window should appear in Maltego's UI when running the transform.
-
-Let's take a look at the code again from the example above:
-
-.. code-block:: python
-
- # ...
- @configure(
- label='To MypackageEntity [Hello World]',
- description='Returns a MyPackageEntity entity with the phrase "Hello Word!"',
- uuids=[ 'mypackage.v2.MyPackageEntityToPhrase_HelloWorld' ],
- inputs=[ ( 'Mypackage', Person ) ],
- debug=True
- )
- def dotransform(request, response):
- # ...
-
-
-The example above tells ``canari install-package`` to process the transform in the following manner:
-
-#. The name of the transform in the transform selection context menu should appear as
- ``To MypackageEntity [Hello World]`` in Maltego's UI.
-#. The short description of the transform as it appears in Maltego's UI is ``Returns a MyPackageEntity entity with the
- phrase "Hello Word!"``.
-#. The transform ID of the transform in Maltego's UI will be ``mypackage.v2.MyPackageEntityToPhrase_HelloWorld``. and
- will only work with an input entity type of :py:class:`Person` belonging to the ``Mypackage`` transform set.
-#. Finally, Maltego should pop a debug window on transform execution.
-
-What if we wanted this transform to work for entity types of :py:class:`Location`, as well. Simple, just add another
-``uuid`` and ``input`` tuple like so:
-
-.. code-block:: python
-
- # ...
- @configure(
- label='To MypackageEntity [Hello World]',
- description='Returns a MyPackageEntity entity with the phrase "Hello Word!"',
- uuids=[ 'mypackage.v2.MyPackageEntityToPhrase_HelloWorld', 'mypackage.v2.MyPackageEntityToLocation_HelloWorld' ],
- inputs=[ ( 'Mypackage', Person ), ( 'Mypackage', Location ) ],
- debug=True
- )
- def dotransform(request, response):
- # ...
-
-
-Now you have one transform configured to run on two different input entity types (:py:class:`Person` and
-:py:class:`Location`) with just a few lines of code and you can do this as many times as you like! Awesome!
-
-
-Running as Root (:py:func:`@superuser`)
----------------------------------------
-
-At some point you may want to run your transform using a super-user account in UNIX-based environments. Maybe to run
-something cool like :program:`Metasploit` or :program:`Nmap`. You can do that simply by decorating
-:py:func:`dotransform` with :py:func:`@superuser`:
-
-.. code-block:: python
-
- # ...
- @superuser
- @configure(
- # ...
- )
- def dotransform(request, response):
- # ...
-
-
-This will instruct :program:`dispatcher` to run the transform using :program:`sudo`. If :program:`dispatcher` is not
-running as ``root`` a :program:`sudo` password dialog box will appear asking the user to enter their password.
-If successful, the transform will run as root, just like that!
-
-Renaming Transforms with ``canari rename-transform``
--------------------------------------------------------
-
-Alright, so you got a bit excited and decided to re-purpose the :py:mod:`helloworld` transform module to do something
-cool. In you're bliss you decided to change the name of the transform module to ``mycooltransform.py``. So you're all
-set to go, right? **Wrong**, you'll need to change the entry in the :py:data:`__all__` variable (i.e. ``'helloworld'``
--> ``'mycooltransform'``) in ``src/mypackage/transforms/__init__.py``, first. Why? Because ``canari install-package``
-will only detect transforms if they are listed in the :py:data:`__all__` variable of the transform package's
-``__init__.py`` script. You can do this quite simply by running::
-
- $ pwd
- /home/user1/foo/src/foo/transforms
- $ canari rename-transform helloworld mycooltransform
- renaming transform 'helloworld' to 'mycooltransform'...
- updating __init__.py
- done!
-
-
-Creating and Removing Transforms
---------------------------------
-
-So you want to create another transform but you want to be speedy like Gonzalez. You don't want to keep writing out the
-same thing for each transform. No problem, ``canari create-transform`` will give you a head start.
-``canari create-transform`` generates a bare bones transform module that you can hack up to do whatever you like.
-Just run ``canari create-transform`` in the ``src/mypackage/transforms`` directory, like so::
-
- $ cd src/mypackage/transforms
- $ canari create-transform mysecondcooltransform
- creating file ./mysecondcooltransform.py...
- updating __init__.py
- done!
-
-
-No need to add the entry in ``__init__.py`` anymore because ``canari create-transform`` does it for you
-automagically. The same is true for ``canari delete-transform`` if you want to remove a transform from your package.
-
-
-.. _custom-entity:
-
-Creating Custom Entities
-========================
-
-Now you want to get a custom entity in. No problem! We've got that covered too. With just a few lines of code you can
-create as many entities as you wish. The only gotcha in this process is that you'll probably want to iconify these
-entities so they look good in Maltego. That's a manual process we can't get away from. On the other hand, defining
-custom entities in your code is quite simple. Take a look inside your custom package's
-``src/mypackage/transforms/common/entities.py`` file. It should look similar to this:
-
-.. code-block:: python
-
- #!/usr/bin/env python
-
- from canari.maltego.message import Entity, EntityField, EntityFieldType, MatchingRule
-
- # ...
-
- """
- DO NOT EDIT
- ...
- """
- class FooEntity(Entity):
- namespace = 'foo'
-
-
- """
- TODO
- ...
- """
- @EntityField(name='foo.fieldN', propname='fieldN', displayname='Field N', matchingrule=MatchingRule.Loose)
- @EntityField(name='foo.field1', propname='field1', displayname='Field 1', type=EntityFieldType.Integer)
- class MyFooEntity(FooEntity):
- # ...
- # name = my.fancy.EntityType
- pass
-
-You may be asking yourself "That's it?" or maybe even scratching your head about what this all means. Don't worry, we'll
-go through this line-by-line. The first class, :py:class:`FooEntity` is the base entity class for all your custom
-entities. You won't want to edit this much since all it provides is a custom namespace for your entities. What is a
-namespace? If you've designed a custom entity in Maltego you probably noticed that the entity gets a suggested ID of
-``<username>.<EntityName>``. In this case the namespace is the ``<username>`` portion of the entity's ID. This is done
-to avoid conflicts between different entity definitions from various transform developers. Maltego's built-in entities
-have a namespace of ``maltego``. In our case, the namespace for all of our entities will be ``foo``.
-
-What about the other entity, :py:class:`MyFooEntity`? That's just an example entity definition that you can modify to
-your heart's content. Notice the :py:func:`@EntityField` decorators. Those define the structure of the entity in terms
-of what entity fields exist, their data-types, icon decorators, and various other elements that affect how Maltego
-compares two different entities of the same type. In addition, these decorators synthesize class fields identified by
-the ``propname`` keyword argument. Modifying their values is as easy as ``myfooentity.mypropname``.
-
-You can specify as many entity fields as you want by just adding an extra :py:func:`@EntityField` decorator to your
-entities. The :py:func:`@EntityField` decorator takes the following parameters:
-
-.. py:function:: @EntityField(**kwargs)
-
- :keyword str name: the name of the field without spaces or special characters except for dots ('.') (required).
- :keyword str propname: the name of the object's property used to get and set the value of the field
- (required, if name contains dots)
- :keyword str displayname: the name of the entity as it appears in Maltego (optional).
- :keyword str type: the data type of the field (optional, default: EntityFieldType.String).
- :keyword bool required: whether or not the field's value must be set before sending back the message (optional,
- default: False).
- :keyword list choices: a list of acceptable field values for this field (optional).
- :keyword str matchingrule: whether or not the field should be loosely or strictly matched by Maltego's graphing
- engine (optional, default: MatchingRule.Strict).
- :keyword callable decorator: a function that is invoked each and every time the field's value is set or changed.
-
-
-Matching Rules
---------------
-
-Maltego currently supports two types of matching rules for entities: ``strict`` and ``loose``. These rules apply to an
-entity's fields and determine how Maltego graph two entities of the same type and value but with differing entity field
-values on a graph. For example, let's assume you've performed a transform that produced two ``IPv4Address`` entities on
-a graph with the same entity value of ``127.0.0.1``. Each ``IPv4Address`` entity has an ``internal`` boolean field
-which indicates whether or not the ``IPv4Address`` entity represents an internal IP address. Let's assume that the
-``internal`` fields are different, one is set to ``true`` and the other to ``false``. In the case where the ``internal``
-field is ``loose``'ly matched, both entities would appear as one entity on the graph. Otherwise, if the ``internal``
-field is ``strict``'ly matched, then both these entities would appear as two separate entities on the graph. If you're a
-fan of a visual example, try the following example transform out to see what the end results are:
-
-.. code-block:: python
-
- #!/usr/bin/env python
-
- from canari.maltego.message import Entity, MatchingRule
- from canari.maltego.message import Phrase, Field
- from canari.framework import configure
-
-
- class TestEntity(Entity):
- namespace='test'
-
- class MyIPv4Address(TestEntity):
- pass
-
-
- @configure(
- label='To IPv4Address [Matching Rules]',
- description='Shows how matching rules work in Maltego.',
- uuids=[ 'tests.v2.PhraseToIPv4Address_Matching_Rules' ],
- inputs=[ ( 'Testing Matching Rules', Phrase ) ],
- debug=True
- )
- def dotransform(request, response):
-
- # What kind of matching rule are we using?
- mr = MatchingRule.Strict
- if request.value.lower() == 'loose':
- mr = MatchingRule.Loose
-
- # First IP
- ip1 = MyIPv4Address('127.0.0.1')
- ip1 += Field('internal', 'true', matchingrule=mr)
- response += ip1
-
- # Second IP
- ip2 = MyIPv4Address('127.0.0.1')
- ip2 += Field('internal', 'false', matchingrule=mr)
- response += ip2
-
- # Return response for visualization
- return response
-
-
-The example transform runs on ``Phrase`` entities and determines its matching rule based on the ``Phrase`` entity's
-value. If it is anything other than ``loose``, the entity field ``internal`` will be ``strict``'ly matched.
-
-Entity Field Decorators
------------------------
-
-Say you want to provide users of your transforms with better visuals for your transform outputs. For example,
\ No newline at end of file
+++ /dev/null
-Canari Framework
-================
-
-Contents:
-
-.. toctree::
- :maxdepth: 2
- :numbered:
-
- intro
- canari
- development
-
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
-
+++ /dev/null
-
-Introduction
-============
-
-Welcome to the official documentation for the `Canari Framework <http://canariproject.com>`_. The
-`Canari Framework <http://canariproject.com>`_ is a rapid transform development framework that can be used to develop
-**local and remote** transforms for `Maltego <http://paterva.com>`_ . Designed on the principles of convention over
-configuration, developing transforms using Canari is extremely fast and easy. Canari takes care of XML serialization and
-deserialization, argument or parameter parsing, as well as transform configuration and execution. Not only is Canari
-great for Maltego transform development but it is also extremely easy to test, debug, and distribute your transforms.
-Canari provides a powerful transform package specification that makes local transform distribution a cinch. Installing a
-set of Maltego transforms, entities, and Maltego Scripts (or Machines) is as easy as typing one line in your terminal.
-Even if you're not a Python developer, Canari has support for easily distributing transforms written in different
-languages (i.e. PERL, Java, Ruby, etc.). The following subsections will provide an in-depth look of Canari's features,
-libraries, and transform package specification.
-
-
-Terminology
------------
-
-Before we get started with the documentation, it might be useful to introduce some of the terminology that will be used
-throughout the documentation:
-
-+-----------------------+----------------------------------------------------------------------------------------------+
-| Term | Definition |
-+=======================+==============================================================================================+
-| **Entity** | a piece of information on a Maltego graph represented as a node. |
-+-----------------------+----------------------------------------------------------------------------------------------+
-| **Input Entity** | the entity that is being passed into the transform to use for data mining purposes. |
-+-----------------------+----------------------------------------------------------------------------------------------+
-| **Output Entity** | the entity that is being returned by the transform to be drawn on a Maltego graph. |
-+-----------------------+----------------------------------------------------------------------------------------------+
-| **Transform** | a function that takes one *input entity* as input and returns zero or more *output entities*.|
-+-----------------------+----------------------------------------------------------------------------------------------+
-| **Transform Module** | a python module local transform code. |
-+-----------------------+----------------------------------------------------------------------------------------------+
-| **Transform Package** | a python package containing one or more transform modules, entities, and Maltego machines. |
-+-----------------------+----------------------------------------------------------------------------------------------+
-
-
-Installing Canari
------------------
-
-Canari is officially supported on Python versions 2.6 and 2.7 with `setuptools <http://pypi.python.org/pypi/setuptools>`_
-on Linux and Mac OS/X. Canari has not yet been tested on Windows but should be able to operate in this environment as
-well. To install setuptools in your Python distribution, simply go to `<http://pypi.python.org/pypi/setuptools>`_ and
-download the corresponding Python egg distribution for your operating system and follow the instructions for
-installation. Once setuptools is installed, type the following command in your terminal::
-
- $ sudo easy_install canari
-
-This will install of Canari's dependencies (argparse and pexpect) as well as Canari's transform development tool-suite.
-If successful, you should be able to run Canari's commander by typing ``canari list-commands`` at the command-prompt::
-
- $ canari list-commands
- create-package - Creates a Canari transform package skeleton.
- create-transform - Creates a new transform in the specified directory and auto-updates __init__.py.
- csv2sheets - Convert mixed entity type CSVs to separated CSV sheets.
- debug-transform - Runs Canari local transforms in a terminal-friendly fashion.
- delete-transform - Deletes a transform in the specified directory and auto-updates __init__.py.
- generate-entities - Converts Maltego entity definition files to Canari python classes. Excludes Maltego built-in entities.
- install-package - Installs and configures canari transform packages in Maltego's UI
- list-commands - Lists all the available canari commands
- mtgx2csv - Convert Maltego graph files (*.mtgx) to comma-separated values (CSV) file.
- rename-transform - Renames a transform in the specified directory and auto-updates __init__.py.
- run-server - Runs a transform server for the given packages.
- run-transform - Runs Canari local transforms in a terminal-friendly fashion.
- shell - Creates a Canari debug shell for the specified transform package.
- uninstall-package - Uninstalls and unconfigures canari transform packages in Maltego's UI
-
-If you were unable to run the Canari commander then please refer to :ref:`ref_troubleshoot` for information. Otherwise,
-let's dive right into the :ref:`ref_canari_commander`.
-
-.. _ref_troubleshoot:
-
-Trouble-shooting Canari Installations
--------------------------------------
-
-In some odd cases, the ``canari`` commander is inaccessible due to erroneous permission or system path definitions. To
-troubleshoot this issue ensure the following two conditions are true:
-
-* The path where ``canari`` is installed (i.e. ``/usr/local/bin``) has read and execute permissions for everyone.
-* The system's ``PATH`` environment variable includes the path where ``canari`` has been installed.
-
-The following subsections provide some pointers for trouble-shooting Canari installations on specific operating systems.
-
-
-Linux and Mac OS/X
-^^^^^^^^^^^^^^^^^^
-
-To determine the location of your ``canari`` script, check the output of ``easy_install``::
-
- $ sudo easy_install canari
- ...
- Installing canari script to /usr/local/bin
- Installing dispatcher script to /usr/local/bin
- Installing pysudo script to /usr/local/bin
- ...
-
-Once you've determined the location of the ``canari`` script (e.g. ``/usr/local/bin``), ensure that it is in
-your system's ``PATH`` environment variable::
-
- $ echo $PATH
- /usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
-
-If the ``canari`` script's path is not included in your system's ``PATH`` environment variable, then check your
-operating system's documentation on how to modify your ``PATH`` environment variable. Otherwise, if the path is in your
-system's ``PATH`` environment variable and you are still unable to run ``canari`` then you'll want to ensure that the
-``canari`` script's parent directory is accessible by everyone::
-
- $ ls -l /usr/local
- total 0
- drwxr-xr-x 58 root wheel 1972 7 Jan 23:42 bin
- ...
-
-
-Ensure that ``canari``'s parent directory (e.g. ``/usr/local/bin``) has ``755`` permissions. If not, use the following
-command to correct the directory's permissions::
-
- $ sudo chmod 755 /usr/local/bin
-
-If none of these steps have helped correct this issue please feel free to send an email to `<bugs@canariproject.com>`_
-for additional help with the following details:
-
- * Operating system name and version.
- * Canari version.
- * ``easy_install`` output.
-
-Windows
-^^^^^^^
-
-.. note::
-
- Canari has not been tested on Windows yet.
+++ /dev/null
-@ECHO OFF
-
-REM Command file for Sphinx documentation
-
-if "%SPHINXBUILD%" == "" (
- set SPHINXBUILD=sphinx-build
-)
-set BUILDDIR=_build
-set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
-set I18NSPHINXOPTS=%SPHINXOPTS% .
-if NOT "%PAPER%" == "" (
- set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
- set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
-)
-
-if "%1" == "" goto help
-
-if "%1" == "help" (
- :help
- echo.Please use `make ^<target^>` where ^<target^> is one of
- echo. html to make standalone HTML files
- echo. dirhtml to make HTML files named index.html in directories
- echo. singlehtml to make a single large HTML file
- echo. pickle to make pickle files
- echo. json to make JSON files
- echo. htmlhelp to make HTML files and a HTML help project
- echo. qthelp to make HTML files and a qthelp project
- echo. devhelp to make HTML files and a Devhelp project
- echo. epub to make an epub
- echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
- echo. text to make text files
- echo. man to make manual pages
- echo. texinfo to make Texinfo files
- echo. gettext to make PO message catalogs
- echo. changes to make an overview over all changed/added/deprecated items
- echo. linkcheck to check all external links for integrity
- echo. doctest to run all doctests embedded in the documentation if enabled
- goto end
-)
-
-if "%1" == "clean" (
- for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
- del /q /s %BUILDDIR%\*
- goto end
-)
-
-if "%1" == "html" (
- %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/html.
- goto end
-)
-
-if "%1" == "dirhtml" (
- %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
- goto end
-)
-
-if "%1" == "singlehtml" (
- %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
- goto end
-)
-
-if "%1" == "pickle" (
- %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can process the pickle files.
- goto end
-)
-
-if "%1" == "json" (
- %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can process the JSON files.
- goto end
-)
-
-if "%1" == "htmlhelp" (
- %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can run HTML Help Workshop with the ^
-.hhp project file in %BUILDDIR%/htmlhelp.
- goto end
-)
-
-if "%1" == "qthelp" (
- %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can run "qcollectiongenerator" with the ^
-.qhcp project file in %BUILDDIR%/qthelp, like this:
- echo.^> qcollectiongenerator %BUILDDIR%\qthelp\sploitego.qhcp
- echo.To view the help file:
- echo.^> assistant -collectionFile %BUILDDIR%\qthelp\sploitego.ghc
- goto end
-)
-
-if "%1" == "devhelp" (
- %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished.
- goto end
-)
-
-if "%1" == "epub" (
- %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The epub file is in %BUILDDIR%/epub.
- goto end
-)
-
-if "%1" == "latex" (
- %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
- goto end
-)
-
-if "%1" == "text" (
- %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The text files are in %BUILDDIR%/text.
- goto end
-)
-
-if "%1" == "man" (
- %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The manual pages are in %BUILDDIR%/man.
- goto end
-)
-
-if "%1" == "texinfo" (
- %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
- goto end
-)
-
-if "%1" == "gettext" (
- %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
- goto end
-)
-
-if "%1" == "changes" (
- %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
- if errorlevel 1 exit /b 1
- echo.
- echo.The overview file is in %BUILDDIR%/changes.
- goto end
-)
-
-if "%1" == "linkcheck" (
- %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
- if errorlevel 1 exit /b 1
- echo.
- echo.Link check complete; look for any errors in the above output ^
-or in %BUILDDIR%/linkcheck/output.txt.
- goto end
-)
-
-if "%1" == "doctest" (
- %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
- if errorlevel 1 exit /b 1
- echo.
- echo.Testing of doctests in the sources finished, look at the ^
-results in %BUILDDIR%/doctest/output.txt.
- goto end
-)
-
-:end
+++ /dev/null
-Subproject commit ee41be0597cd99303bcb42ae750da93e6c892220
+++ /dev/null
-#!/usr/bin/env python
-
-import os
-import sys
-from setuptools import setup, find_packages
-
-sys.path.insert(0, 'src')
-
-import canari
-
-scripts = [
- 'src/scripts/canari',
- 'src/scripts/dispatcher',
-]
-
-if os.name == 'posix':
- scripts.extend(
- [
- 'src/scripts/pysudo'
- ]
- )
-
-
-extras = [
- 'readline'
-]
-
-
-if os.name == 'nt':
- scripts += ['%s.bat' % s for s in scripts]
-
-setup(
- name='canari',
- author='Nadeem Douba',
- version=canari.__version__,
- author_email='ndouba@gmail.com',
- description='Rapid transform development and transform execution framework for Maltego.',
- license='GPL',
- packages=find_packages('src'),
- package_dir={ '' : 'src' },
- scripts=scripts,
- zip_safe=False,
- package_data={
- '' : [ '*.conf', '*.plate' ]
- },
- install_requires=[
- 'argparse',
- 'flask'
- ],
- dependency_links=[]
-)
+++ /dev/null
-Subproject commit e84242e64ff3dea0e44ee9e57b6d61005a11f46b
+++ /dev/null
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.9'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-__all__ = [
- 'commands',
- 'maltego',
- 'resources',
- 'utils',
- 'xmltools',
- 'config',
- 'easygui',
- 'framework',
- 'resource'
-]
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-__all__ = [
- 'install_package',
- 'uninstall_package',
- 'mtgx2csv',
- 'csv2sheets',
- 'common',
- 'help',
- 'create_package',
- 'create_transform',
- 'debug_transform',
- 'shell',
- 'run_transform',
- 'delete_transform',
- 'rename_transform',
- 'list_commands',
- 'run_server',
- 'generate_entities',
- 'version',
- 'banner'
-]
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-from common import get_commands, cmd_name
-from argparse import ArgumentParser
-from sys import modules
-
-import canari
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-parser = ArgumentParser(
- description='Show banner of Canari framework that is currently active.',
- usage='canari %s' % cmd_name(__name__)
-)
-
-
-def help():
- parser.print_help()
-
-
-def description():
- return parser.description
-
-
-def run(args):
- print """
- Your running ...
-_________ _____ _______ _______
-__ ____/_____ _____________ __________(_) ___ ___ __ \ __( __ )
-_ / _ __ `/_ __ \ __ `/_ ___/_ / __ | / / / / / _ __ |
-/ /___ / /_/ /_ / / / /_/ /_ / _ / __ |/ // /_/ /__/ /_/ /
-\____/ \__,_/ /_/ /_/\__,_/ /_/ /_/ _____/ \____/_(_)____/
-
- ... http://canariproject.com
- """
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-from distutils.command.install import install
-from pkg_resources import resource_filename
-from distutils.dist import Distribution
-from datetime import datetime
-from string import Template
-import unicodedata
-import subprocess
-import threading
-import inspect
-import sys
-import os
-
-
-from canari.config import CanariConfigParser
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.4'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-def synchronized(func):
-
- func.__lock__ = threading.RLock()
-
- def synced_func(*args, **kws):
- with func.__lock__:
- return func(*args, **kws)
-
- return synced_func
-
-
-def get_transform_version(transform):
- spec = inspect.getargspec(transform)
- if spec.varargs is not None:
- return 3
- n = len(spec.args)
- if 2 <= n <= 3:
- return n
- raise Exception('Could not determine transform version.')
-
-
-def fix_etree():
- try:
- from xml.etree.cElementTree import XML
- e = XML('<test><t a="1"/></test>')
- e.find('t[@a="1"]')
- except SyntaxError:
- import canari.xmltools.fixetree
-
-
-def get_bin_dir():
- d = install(Distribution())
- d.finalize_options()
- return d.install_scripts
-
-
-def get_commands(module='canari.commands'):
- commands = {}
- sc = __import__(module, globals(), locals(), fromlist=['__all__'])
- for c in sc.__all__:
- m = __import__('%s.%s' % (module, c), globals(), locals(), fromlist=['run', 'help'])
- if 'run' in m.__dict__:
- commands[cmd_name(m.__name__)] = m
- return commands
-
-
-def _detect_settings_dir(d):
- vs = [ i for i in os.listdir(d) if os.path.isdir(os.path.join(d, i)) if os.path.isdir(os.path.join(d, i, 'config'))]
- if len(vs) == 1:
- return os.path.join(d, vs[0])
- else:
- while True:
- print('Multiple versions of Maltego detected: ')
- for i, v in enumerate(vs):
- print('[%d] Maltego %s' % (i, v))
- r = raw_input('Please select which version you wish to use [0]: ')
- try:
- if not r:
- return os.path.join(d, vs[0])
- elif int(r) < len(vs):
- return os.path.join(d, vs[int(r)])
- except ValueError:
- pass
- print('Invalid selection... %s' % repr(r))
- print('Could not automatically find Maltego\'s settings directory. Use the -w parameter to specify its location, instead.')
-
-
-def to_utf8(s):
- return unicodedata.normalize('NFKD', unicode(s)).encode('ascii', 'ignore')
-
-
-def detect_settings_dir():
- d = None
- if sys.platform.startswith('linux'):
- d = _detect_settings_dir(os.path.join(os.path.expanduser('~'), '.maltego'))
- elif sys.platform == 'darwin':
- d = _detect_settings_dir(os.path.join(os.path.expanduser('~'), 'Library', 'Application Support', 'maltego'))
- elif sys.platform == 'win32':
- d = _detect_settings_dir(os.path.join(os.environ['APPDATA'], '.maltego'))
- else:
- raise NotImplementedError('Unknown or unsupported OS: %s' % repr(sys.platform))
- return d
-
-
-def sudo(args):
- p = subprocess.Popen([os.path.join(get_bin_dir(), 'pysudo')] + args, stdin=subprocess.PIPE)
- p.communicate()
- return p.returncode
-
-
-def read_template(name, values):
- t = Template(file(resource_filename('canari.resources.template', '%s.plate' % name)).read())
- return t.substitute(**values)
-
-
-def write_template(fname, data):
- print('creating file %s...' % fname)
- with file(fname, mode='wb') as w:
- w.write(data)
-
-
-def generate_all(*args):
- return "\n\n__all__ = [\n '%s'\n]" % "',\n '".join(args)
-
-
-def build_skeleton(*args):
- for d in args:
- if isinstance(d, list):
- d = os.sep.join(d)
- print('creating directory %s' % d)
- os.mkdir(d)
-
-
-def highlight(s, color, bold):
-
- if os.name == 'posix':
- attr = []
- if color == 'green':
- # green
- attr.append('32')
- elif color == 'red':
- # red
- attr.append('31')
- else:
- attr.append('30')
- if bold:
- attr.append('1')
- s = '\x1b[%sm%s\x1b[0m' % (';'.join(attr), s)
-
- return s
-
-
-def croak(exc):
- print(highlight(exc, 'red', None))
-
-
-def fix_pypath():
- if '' not in sys.path:
- sys.path.insert(0, '')
-
-
-def fix_binpath(paths):
- if paths is not None and paths:
- if isinstance(paths, basestring):
- os.environ['PATH'] = paths
- elif isinstance(paths, list):
- os.environ['PATH'] = os.pathsep.join(paths)
-
-
-def import_transform(script):
- fix_pypath()
- return __import__(script, globals(), locals(), ['dotransform'])
-
-
-def import_package(package):
- fix_pypath()
- return __import__(package, globals(), locals(), ['*'])
-
-
-def cmd_name(name):
- return name.replace('canari.commands.', '').replace('_', '-')
-
-
-def console_message(msg, tab=-1):
- tab += 1
- print('%s`- %s: %s %s' % (
- ' ' * tab,
- highlight(msg.tag, None, True),
- highlight(msg.text, 'red', False) if msg.text is not None else '',
- highlight(msg.attrib, 'green', True) if msg.attrib.keys() else ''
- ))
- for c in msg.getchildren():
- print(' %s`- %s: %s %s' % (
- ' ' * tab,
- highlight(c.tag, None, True),
- highlight(c.text, 'red', False) if c.text is not None else '',
- highlight(c.attrib, 'green', True) if c.attrib.keys() else ''
- ))
- for sc in c.getchildren():
- tab += 1
- console_message(sc, tab)
- tab -= 1
- tab -= 1
-
-
-def init_pkg():
-
- root = project_root()
-
- if root is not None:
- conf = os.path.join(root, '.canari')
- if os.path.exists(conf):
- c = CanariConfigParser()
- c.read(conf)
- return {
- 'author' : c['metadata/author'],
- 'email' : c['metadata/email'],
- 'maintainer' : c['metadata/maintainer'],
- 'project' : c['metadata/project'],
- 'year' : datetime.now().year
- }
-
- return {
- 'author' : '',
- 'email' : '',
- 'maintainer' : '',
- 'project' : '',
- 'year' : datetime.now().year
- }
-
-
-def project_root():
- marker = '.canari'
- for i in range(0, 5):
- if os.path.exists(marker):
- return os.path.dirname(os.path.realpath(marker))
- marker = '..%s%s' % (os.sep, marker)
- print 'Unable to determine project root.'
- exit(-1)
-
-
-def project_tree():
-
- root = project_root()
-
- tree = dict(
- root=root,
- src=None,
- pkg=None,
- resources=None,
- transforms=None
- )
-
- for base, dirs, files in os.walk(root):
- if base.endswith('src'):
- tree['src'] = base
- elif 'resources' in dirs:
- tree['pkg'] = base
- elif base.endswith('resources'):
- tree['resources'] = base
- elif base.endswith('transforms'):
- tree['transforms'] = base
-
- return tree
-
-
-def parse_bool(ans, default='y'):
-
- while True:
- ans = raw_input(ans).lower() or default
- if ans.startswith('y'):
- return True
- elif ans.startswith('n'):
- return False
+++ /dev/null
-#!/usr/bin/env python
-
-from argparse import ArgumentParser
-from datetime import datetime
-from getpass import getuser
-from os import path
-
-from common import read_template, write_template, generate_all, build_skeleton, cmd_name, parse_bool
-import canari
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.6'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-parser = ArgumentParser(
- description='Creates a Canari transform package skeleton.',
- usage='canari %s <package name>' % cmd_name(__name__)
-)
-
-parser.add_argument(
- 'package',
- metavar='<package name>',
- help='The name of the canari package you wish to create.'
-)
-
-
-def write_setup(package_name, values):
- write_template(path.join(package_name, '.canari'), read_template('_canari', values))
- write_template(path.join(package_name, 'setup.py'), read_template('setup', values))
- write_template(path.join(package_name, 'README.md'), read_template('README', values))
- write_template(path.join(package_name, 'MANIFEST.in'), read_template('MANIFEST', values))
-
-
-def write_root(base, init):
- write_template(
- path.join(base, '__init__.py'),
- init + generate_all('resources', 'transforms')
- )
-
-
-def write_resources(package_name, resources, init, values):
- write_template(
- path.join(resources, '__init__.py'),
- init + generate_all('etc', 'images', 'maltego', 'external')
- )
-
- write_template(
- path.join(resources, 'etc', '__init__.py'),
- init
- )
-
- write_template(
- path.join(resources, 'images', '__init__.py'),
- init
- )
-
- write_template(
- path.join(resources, 'external', '__init__.py'),
- init
- )
-
- write_template(
- path.join(resources, 'maltego', '__init__.py'),
- init
- )
-
- write_template(
- path.join(resources, 'etc', '%s.conf' % package_name),
- read_template('conf', values)
- )
-
-
-def write_common(transforms, init, values):
-
- if values['example']:
- write_template(
- path.join(transforms, '__init__.py'),
- init + generate_all('common', 'helloworld')
- )
-
- write_template(
- path.join(transforms, 'helloworld.py'),
- read_template('transform', values)
- )
- else:
- write_template(
- path.join(transforms, '__init__.py'),
- init + generate_all('common')
- )
-
- write_template(
- path.join(transforms, 'common', '__init__.py'),
- init + generate_all('entities')
- )
-
- write_template(
- path.join(transforms, 'common', 'entities.py'),
- read_template('entities', values)
- )
-
-
-def help():
- parser.print_help()
-
-
-def description():
- return parser.description
-
-
-def ask_user(defaults):
-
- print('Welcome to the Canari transform package wizard.')
-
- if not parse_bool('Would you like to specify authorship information? [Y/n]: '):
- return
-
- defaults['description'] = raw_input('Project description [%s]: ' % defaults['description']) or defaults['description']
- defaults['example'] = parse_bool('Generate an example transform? [Y/n]: ')
- defaults['author'] = raw_input('Author name [%s]: ' % defaults['author']) or defaults['author']
- defaults['email'] = raw_input('Author email []: ') or ''
- defaults['maintainer'] = raw_input('Maintainer name [%s]: ' % defaults['author']) or defaults['author']
-
- if not parse_bool('Are you satisfied with this information? [Y/n]: '):
- return ask_user(defaults)
-
-
-def run(args):
-
- opts = parser.parse_args(args)
-
- package_name = opts.package
- capitalized_package_name = package_name.capitalize()
-
- values = {
- 'package' : package_name,
- 'entity' : 'My%sEntity' % capitalized_package_name,
- 'base_entity' : '%sEntity' % capitalized_package_name,
- 'project' : capitalized_package_name,
- 'author' : getuser(),
- 'year' : datetime.now().year,
- 'namespace' : package_name,
- 'email' : '',
- 'maintainer' : getuser(),
- 'example' : True,
- 'description' : '',
- 'canari_version' : canari.__version__
- }
-
- ask_user(values)
-
- base = path.join(package_name, 'src', package_name)
- transforms = path.join(base, 'transforms')
- resources = path.join(base, 'resources')
-
- if not path.exists(package_name):
- print('creating skeleton in %s' % package_name)
- build_skeleton(
- package_name,
- [package_name, 'src'],
- [package_name, 'maltego'],
- base,
- transforms,
- [transforms, 'common'],
- resources,
- [resources, 'etc'],
- [resources, 'images'],
- [resources, 'external'],
- [resources, 'maltego']
- )
- else:
- print('A directory with the name %s already exists... exiting' % package_name)
- exit(-1)
-
-
- init = read_template('__init__', values)
-
- write_setup(package_name, values)
-
- write_root(base, init)
-
- write_resources(package_name, resources, init, values)
-
- write_common(transforms, init, values)
-
- print('done!')
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-from common import write_template, read_template, cmd_name, init_pkg, project_tree
-
-from argparse import ArgumentParser
-from os import path
-from re import sub
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-parser = ArgumentParser(
- description='Creates a new transform in the specified directory and auto-updates __init__.py.',
- usage='canari %s <transform name> [options]' % cmd_name(__name__)
-)
-
-parser.add_argument(
- 'transform',
- metavar='<transform name>',
- help='The name of the transform you wish to create.'
-)
-
-parser.add_argument(
- '-d',
- '--transform-dir',
- metavar='<dir>',
- help='The directory in which you wish to create the transform.',
- default=None
-)
-
-
-def help():
- parser.print_help()
-
-
-def description():
- return parser.description
-
-
-def parse_args(args):
- args = parser.parse_args(args)
- if args.transform_dir is None:
- args.transform_dir= project_tree()['transforms']
- return args
-
-
-def run(args):
-
- opts = parse_args(args)
-
- initf = path.join(opts.transform_dir, '__init__.py')
- transform = opts.transform if not opts.transform.endswith('.py') else opts.transform[:-3]
-
- if '.' in transform:
- print "Transform name (%s) cannot have a dot ('.')." % repr(transform)
- exit(-1)
- elif not transform:
- print "You must specify a valid transform name."
- exit(-1)
-
- directory = opts.transform_dir
- transformf = path.join(directory, opts.transform if opts.transform.endswith('.py') else '%s.py' % opts.transform )
-
- if not path.exists(initf):
- print ('Directory %s does not appear to be a python package directory... quitting!' % repr(opts.transform_dir))
- exit(-1)
- if path.exists(transformf):
- print ('Transform %s already exists... quitting' % repr(transformf))
- exit(-1)
-
- values = init_pkg()
-
- write_template(
- transformf,
- read_template('newtransform', values)
- )
-
- print ('updating %s' % initf)
- init = file(initf).read()
-
- with file(initf, mode='wb') as w:
- w.write(
- sub(
- r'__all__\s*\=\s*\[',
- '__all__ = [\n %s,' % repr(transform),
- init
- )
- )
-
- print ('done!')
+++ /dev/null
-#!/usr/bin/env python
-
-from common import cmd_name
-
-from argparse import ArgumentParser
-from re import sub, match
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-parser = ArgumentParser(
- description='Convert mixed entity type CSVs to separated CSV sheets.',
- usage='canari %s <graph csv> <sheet prefix>' % cmd_name(__name__)
-)
-
-parser.add_argument(
- 'graph',
- metavar='<graph csv>',
- help='The CSV file containing the output from the mtgx2csv command.'
-)
-
-parser.add_argument(
- 'prefix',
- metavar='<sheet prefix>',
- help='The prefix to prepend to the generated CSV files.'
-)
-
-
-def help():
- parser.print_help()
-
-
-def description():
- return parser.description
-
-
-def parse_args(args):
- return parser.parse_args(args)
-
-
-def run(args):
-
- opts = parse_args(args)
-
- matchers = {}
-
- for line in file(opts.graph):
- line.replace('""', '"')
- matcher = sub('=([^"]+)"', '=([^"]+)"', line)
-
- if matcher not in matchers:
- matchers[matcher] = []
-
- matchers[matcher].append(line)
-
-
- i = 0
- for matcher in matchers:
- f = open('%s_%d.csv' % (opts.prefix, i), 'w')
- i += 1
-
- f.write(matcher.replace('=([^"]+)', ''))
-
- for r in matchers[matcher]:
- line = '","'.join(match(matcher, r).groups())
- line = '"%s"\n' % line
- line.replace('"', '""')
- f.write(line)
-
- f.close()
+++ /dev/null
-#!/usr/bin/env python
-
-import os
-import sys
-
-from argparse import ArgumentParser
-from traceback import format_exc
-
-from common import croak, import_transform, cmd_name, console_message, fix_binpath, sudo, get_transform_version
-from canari.maltego.message import (MaltegoException, MaltegoTransformResponseMessage, UIMessage,
- MaltegoTransformRequestMessage)
-from canari.maltego.utils import onterminate, parseargs
-from canari.config import config
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.4'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-parser = ArgumentParser(
- description='Runs Canari local transforms in a terminal-friendly fashion.',
- usage='canari %s <transform> [param1 ... paramN] <value> [field1=value1...#fieldN=valueN]' % cmd_name(__name__)
-)
-
-parser.add_argument(
- 'transform',
- metavar='<transform>',
- help='The name of the transform you wish to run (e.g. sploitego.transforms.nmapfastscan).'
-)
-
-parser.add_argument(
- 'value',
- metavar='<value>',
- help='The value of the input entity being passed into the local transform.'
-)
-
-parser.add_argument(
- 'params',
- metavar='[param1 ... paramN]',
- help='Any extra parameters that can be sent to the local transform.'
-)
-
-parser.add_argument(
- 'fields',
- metavar='[field1=value1...#fieldN=valueN]',
- help='The fields of the input entity being passed into the local transform.'
-)
-
-
-def help():
- parser.print_help()
-
-
-def description():
- return parser.description
-
-
-def run(args):
-
- [transform, params, value, fields] = parseargs(['canari %s' % cmd_name(__name__)] + args)
-
- m = None
- fix_binpath(config['default/path'])
- try:
- m = import_transform(transform)
-
- if os.name == 'posix' and hasattr(m.dotransform, 'privileged') and os.geteuid():
- rc = sudo(sys.argv)
- if rc == 1:
- console_message(MaltegoTransformResponseMessage() + UIMessage('User cancelled transform.'))
- elif rc == 2:
- console_message(MaltegoTransformResponseMessage() + UIMessage('Too many incorrect password attempts.'))
- elif rc:
- console_message(MaltegoTransformResponseMessage() + UIMessage('Unknown error occurred.'))
- exit(rc)
-
- if hasattr(m, 'onterminate'):
- onterminate(m.onterminate)
- else:
- m.__setattr__('onterminate', lambda *args: exit(-1))
-
- msg = m.dotransform(
- MaltegoTransformRequestMessage(value, fields, params),
- MaltegoTransformResponseMessage()
- ) if get_transform_version(m.dotransform) == 2 else m.dotransform(
- MaltegoTransformRequestMessage(value, fields, params),
- MaltegoTransformResponseMessage(),
- config
- )
-
- if isinstance(msg, MaltegoTransformResponseMessage):
- console_message(msg)
- elif isinstance(msg, basestring):
- raise MaltegoException(msg)
- else:
- raise MaltegoException('Could not resolve message type returned by transform.')
- except MaltegoException, me:
- croak(str(me))
- except ImportError:
- e = format_exc()
- croak(e)
- except Exception:
- e = format_exc()
- croak(e)
- except KeyboardInterrupt, ki:
- if m is not None:
- m.onterminate()
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-from common import cmd_name, project_tree
-
-from argparse import ArgumentParser
-from os import path, unlink
-from re import sub
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-parser = ArgumentParser(
- description='Deletes a transform in the specified directory and auto-updates __init__.py.',
- usage='canari %s <transform name> [options]' % cmd_name(__name__)
-)
-
-parser.add_argument(
- 'transform',
- metavar='<transform name>',
- help='The name of the transform you wish to delete.'
-)
-
-parser.add_argument(
- '-d',
- '--transform-dir',
- metavar='<dir>',
- help='The directory from which you wish to delete the transform.',
- default=None
-)
-
-
-def help():
- parser.print_help()
-
-
-def description():
- return parser.description
-
-
-def parse_args(args):
- args = parser.parse_args(args)
- if args.transform_dir is None:
- args.transform_dir = project_tree()['transforms']
- return args
-
-
-def run(args):
-
- opts = parse_args(args)
-
- initf = path.join(opts.transform_dir, '__init__.py')
- transform = opts.transform
- transformf = path.join(opts.transform_dir, transform if transform.endswith('.py') else '%s.py' % transform )
-
- if not path.exists(initf):
- print ('Directory %s does not appear to be a python package directory... quitting!' % repr(opts.transform_dir))
- exit(-1)
- if not path.exists(transformf):
- print ("Transform %s doesn't exists... quitting" % repr(transformf))
- exit(-1)
-
- print ("deleting transform %s..." % repr(transformf))
- unlink(transformf)
-
- print ('updating %s' % initf)
- init = file(initf).read()
-
- with file(initf, mode='wb') as w:
- w.write(
- sub(
- r'\s*%s,?' % repr(transform),
- '',
- init
- )
- )
-
- print ('done!')
+++ /dev/null
-#!/usr/bin/env python
-
-from common import detect_settings_dir, cmd_name, project_tree, parse_bool
-from canari.maltego.entities import Entity
-
-from xml.etree.cElementTree import XML
-from argparse import ArgumentParser
-from os import walk, path
-from zipfile import ZipFile
-from imp import load_source
-from re import sub
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = ['Nadeem Douba']
-
-__license__ = 'GPL'
-__version__ = '0.3'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-parser = ArgumentParser(
- description='Converts Maltego entity definition files to Canari python classes. Excludes Maltego built-in entities.',
- usage='canari %s [output file] [options]' % cmd_name(__name__)
-)
-
-
-parser.add_argument(
- 'outfile',
- metavar='[output file]',
- help='Which file to write the output to.',
- default=None,
- nargs='?'
-)
-
-parser.add_argument(
- '--mtz-file',
- '-m',
- metavar='<mtzfile>',
- help='A *.mtz file containing an export of Maltego entities.',
- required=False
-)
-
-parser.add_argument(
- '--exclude-namespace',
- '-e',
- metavar='<namespace>',
- help='Name of Maltego entity namespace to ignore. Can be defined multiple times.',
- required=False,
- action='append',
- default=['maltego', 'maltego.affiliation']
-)
-
-parser.add_argument(
- '--namespace',
- '-n',
- metavar='<namespace>',
- help='Name of Maltego entity namespace to generate entity classes for. Can be defined multiple times.',
- required=False,
- action='append',
- default=[]
-)
-
-parser.add_argument(
- '--maltego-entities',
- '-M',
- help="Generate entities belonging to the 'maltego' namespace.",
- default=False,
- action='store_true'
-)
-
-parser.add_argument(
- '--append',
- '-a',
- help='Whether or not to append to the existing *.py file.',
- action='store_true',
- default=False
-)
-
-parser.add_argument(
- '--entity',
- '-E',
- metavar='<entity>',
- help='Name of Maltego entity to generate Canari python class for.',
- required=False,
- action='append',
- default=[]
-)
-
-
-def help():
- parser.print_help()
-
-
-def description():
- return parser.description
-
-
-def parse_args(args):
- args = parser.parse_args(args)
- if args.outfile is None:
- args.outfile = path.join(project_tree()['transforms'], 'common', 'entities.py')
- if args.maltego_entities:
- args.namespace.extend(args.exclude_namespace)
- args.exclude_namespace = []
- return args
-
-
-def normalize_fn(fn):
- # Get rid of starting underscores or numbers and bad chars for var names in python
- return sub(r'[^A-Za-z0-9]', '', sub(r'^[^A-Za-z]+', '', fn))
-
-
-def diff(fn):
- m = load_source('entities', fn)
- l = []
- for c in dir(m):
- try:
- i = m.__dict__[c]('load')
- if isinstance(i, Entity):
- l.append(i)
- except TypeError:
- pass
- return l
-
-
-class DirFile(object):
-
- def __init__(self, path):
- self.path = path
-
- def namelist(self):
- l = []
- for base, dirs, files in walk(self.path):
- l.extend([ path.join(base, f) for f in files ])
- return l
-
- def open(self, fname):
- return file(fname)
-
-
-def run(args):
-
- opts = parse_args(args)
-
- if path.exists(opts.outfile) and not opts.append and not \
- parse_bool('%s already exists. Are you sure you want to overwrite it? [y/N]: ' % repr(opts.outfile), default='n'):
- exit(-1)
-
-
- ar = DirFile(
- path.join(detect_settings_dir(), 'config', 'Maltego', 'Entities')
- ) if opts.mtz_file is None else ZipFile(opts.mtz_file)
-
- entities = filter(lambda x: x.endswith('.entity'), ar.namelist())
-
- nses = dict()
-
- el = []
- if opts.append:
- l = diff(opts.outfile)
- el.extend([i.type for i in l])
- for i in l:
- if i.type.endswith('Entity'):
- nses[i.namespace] = i.__class__.__name__
-
- print 'Generating %s...' % repr(opts.outfile)
- fd = open(opts.outfile, 'ab' if opts.append else 'wb')
-
- if opts.append:
- fd.write('\n\n')
- else:
- fd.write('#!/usr/bin/env python\n\nfrom canari.maltego.entities import EntityField, Entity\n\n\n')
-
- for e in entities:
- xml = XML(ar.open(e).read())
- id_ = xml.get('id')
-
- if (opts.entity and id_ not in opts.entity) or id_ in el:
- continue
-
- ens = id_.split('.')
-
- base_classname = None
- namespace = '.'.join(ens[:-1])
- name = ens[-1]
- classname = name
-
- if (opts.namespace and namespace not in opts.namespace) or namespace in opts.exclude_namespace:
- continue
-
- if namespace not in nses:
- base_classname = '%sEntity' % (''.join([ n.title() for n in ens[:-1] ]))
- nses[namespace] = base_classname
-
- fd.write('class %s(Entity):\n namespace = %s\n\n' % (base_classname, repr(namespace)))
- else:
- base_classname = nses[namespace]
-
-
- for f in xml.findall('Properties/Fields/Field'):
- fields = [
- 'name=%s' % repr(f.get('name')),
- 'propname=%s' % repr(normalize_fn(f.get('name'))),
- 'displayname=%s' % repr(f.get('displayName'))
-
- ]
- fd.write('@EntityField(%s)\n' % ', '.join(fields))
-
- fd.write('class %s(%s):\n pass\n\n\n' % (classname, base_classname))
-
- fd.close()
- print 'done.'
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-from common import get_commands, cmd_name
-
-from argparse import ArgumentParser
-from sys import modules
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-cmds = get_commands()
-cmds.update({'help': modules[__name__]})
-
-parser = ArgumentParser(
- description='Shows help related to various canari commands',
- usage='canari %s <command>' % cmd_name(__name__)
-)
-
-parser.add_argument(
- 'command',
- metavar='<command>',
- choices=cmds,
- default='help',
- nargs='?',
- help='The canari command you want help for (%s)' % ', '.join(cmds)
-)
-
-
-def help():
- parser.print_help()
-
-
-def description():
- return parser.description
-
-
-def run(args):
- cmds[parser.parse_args(args).command].help()
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-import os
-import sys
-
-from pkg_resources import resource_filename, resource_listdir
-from xml.etree.cElementTree import XML, SubElement
-from argparse import ArgumentParser
-from re import findall, sub
-from zipfile import ZipFile
-from string import Template
-
-from canari.maltego.configuration import (MaltegoTransform, CmdCwdTransformProperty, CmdDbgTransformProperty,
- CmdLineTransformProperty, CmdParmTransformProperty, InputConstraint, TransformSet,
- TransformSettings, CmdCwdTransformPropertySetting, CmdDbgTransformPropertySetting,
- CmdLineTransformPropertySetting, CmdParmTransformPropertySetting)
-from common import detect_settings_dir, cmd_name, fix_pypath, get_bin_dir, import_transform, import_package, fix_etree
-from canari.maltego.message import ElementTree
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.4'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-# Dictionary of detected transforms
-transforms = {}
-
-# Argument parser
-parser = ArgumentParser(
- description="Installs and configures canari transform packages in Maltego's UI",
- usage='canari %s <package> [options]' % cmd_name(__name__)
-)
-
-parser.add_argument(
- 'package',
- metavar='<package>',
- help='the name of the canari transforms package to install.'
-)
-parser.add_argument(
- '-w',
- '--working-dir',
- metavar='[working dir]',
- default=os.path.join(os.path.expanduser('~'), '.canari'),
- help='the path that will be used as the working directory for the transforms being installed (default: current working directory)'
-)
-parser.add_argument(
- '-s',
- '--settings-dir',
- metavar='[settings dir]',
- default=detect_settings_dir,
- help='the path to the Maltego settings directory (automatically detected if excluded)'
-)
-
-
-# Help for this command
-def help():
- parser.print_help()
-
-
-def description():
- return parser.description
-
-
-# Extra sauce to parse args
-def parse_args(args):
- args = parser.parse_args(args)
-
- if args.settings_dir is detect_settings_dir:
- try:
- args.settings_dir = detect_settings_dir()
- except OSError:
- print "Make sure you've run Maltego for the first time and activated your license."
- exit(-1)
-
- args.working_dir = os.path.realpath(args.working_dir)
- return args
-
-
-# Logic to install transforms
-def install_transform(module, name, author, spec, prefix, working_dir):
-
- installdir = os.path.join(prefix, 'config', 'Maltego', 'TransformRepositories', 'Local')
-
- if not os.path.exists(installdir):
- os.mkdir(installdir)
-
- setsdir = os.path.join(prefix, 'config', 'Maltego', 'TransformSets')
-
- for i,n in enumerate(spec.uuids):
-
- if n in transforms:
- sys.stderr.write('WARNING: Previous declaration of %s in transform %s. Overwriting...' % (n, module))
- else:
- print ('Installing transform %s from %s...' % (n, module))
- transforms[n] = module
-
- intype = spec.inputs[i][1]('').type
-
- sets = None
- if spec.inputs[i][0] is not None:
- setdir = os.path.join(setsdir, spec.inputs[i][0])
- if not os.path.exists(setdir):
- os.mkdir(setdir)
- open(os.path.join(setdir, n), 'w').close()
- sets=TransformSet(spec.inputs[i][0])
-
- transform = MaltegoTransform(
- n,
- spec.label,
- author=author,
- description=spec.description,
- properties=[
- CmdLineTransformProperty(),
- CmdCwdTransformProperty(),
- CmdDbgTransformProperty(),
- CmdParmTransformProperty()
- ],
- input=InputConstraint(intype),
- sets=sets
- )
- transform.sets
-
-
- ElementTree(transform).write(os.path.join(installdir, '%s.transform' % n))
-
- transformsettings = TransformSettings(properties=[
- CmdLineTransformPropertySetting(
- os.path.join(get_bin_dir(),
- 'dispatcher.bat' if os.name == 'nt' else 'dispatcher')
- ),
- CmdParmTransformPropertySetting(name),
- CmdCwdTransformPropertySetting(working_dir),
- CmdDbgTransformPropertySetting(spec.debug)
- ])
- ElementTree(transformsettings).write(os.path.join(installdir, '%s.transformsettings' % n))
-
-
-def writeconf(sf, df, **kwargs):
- if not os.path.exists(df):
- print ('Writing %s to %s' % (sf, df))
- with file(df, mode='wb') as w:
- if 'sub' in kwargs and kwargs['sub']:
- del kwargs['sub']
- w.write(
- Template(
- file(
- sf
- ).read()
- ).substitute(**kwargs)
- )
- else:
- w.write(
- file(
- sf
- ).read()
- )
-
-
-def updateconf(c, f):
- ld = os.getcwd()
- os.chdir(os.path.dirname(f))
-
- import canari.config as config
- reload(config)
-
- if c not in config.config['default/configs']:
- print ('Updating %s...' % f)
- s = ''
- with file(f) as r:
- s = r.read()
- with file(f, mode='wb') as w:
- w.write(sub(r'configs\s*\=', 'configs = %s,' % c, s))
- os.chdir(ld)
-
-
-def installconf(opts, args):
- src = resource_filename('canari.resources.template', 'canari.plate')
- writeconf(
- src,
- os.path.join(opts.working_dir, 'canari.conf'),
- sub=True,
- command=' '.join(['canari install'] + args),
- config=('%s.conf' % opts.package) if opts.package != 'canari' else '',
- path='${PATH},/usr/local/bin,/opt/local/bin' if os.name == 'posix' else ''
- )
-
- if opts.package != 'canari':
- src = resource_filename('%s.resources.etc' % opts.package, '%s.conf' % opts.package)
- writeconf(src, os.path.join(opts.working_dir, '%s.conf' % opts.package), sub=False)
- updateconf('%s.conf' % opts.package, os.path.join(opts.working_dir, 'canari.conf'))
-
-
-def installmtz(package, prefix):
- try:
- src = resource_filename('%s.resources.maltego' % package, 'entities.mtz')
- if not os.path.exists(src):
- return
- prefix = os.path.join(prefix, 'config', 'Maltego', 'Entities')
- z = ZipFile(src)
- entities = filter(lambda x: x.endswith('.entity'), z.namelist())
-
- for e in entities:
- data = z.open(e).read()
- xml = XML(data)
- category = xml.get('category')
- catdir = os.path.join(prefix, category)
- if not os.path.exists(catdir):
- os.mkdir(catdir)
- p = os.path.join(catdir, os.path.basename(e))
- print 'Installing entity %s to %s...' % (e, p)
- with open(p, 'wb') as f:
- f.write(data)
- except ImportError:
- pass
-
-
-def installnbattr(xml, src, dst):
- src = findall('machine\(([^\)]+)', src)[0]
- if not src:
- return
- props = sub('\s*\n\s*|"', '', src).split(',')
- e = None
- for p in props:
- if ':' not in p:
- if xml.find('fileobject[@name="%s"]' % dst) is not None:
- return
- e = SubElement(xml, 'fileobject')
- e.set('name', dst)
- else:
- n, v = p.split(':')
- s = SubElement(e, 'attr')
- s.set('name', n)
- s.set('stringvalue', v)
- s = SubElement(e, 'attr')
- s.set('name', 'readonly')
- s.set('boolvalue', 'false')
- s = SubElement(e, 'attr')
- s.set('name', 'enabled')
- s.set('boolvalue', 'true')
-
-
-def installmachines(package, prefix):
- try:
- prefix = os.path.join(prefix, 'config', 'Maltego', 'Machines')
- n = os.path.join(prefix, '.nbattrs')
- e = XML('<attributes version="1.0"/>')
- if os.path.exists(n):
- e = XML(file(n).read())
- if not os.path.exists(prefix):
- os.mkdir(prefix)
- package = '%s.resources.maltego' % package
- for m in filter(lambda x: x.endswith('.machine'), resource_listdir(package, '')):
- src = resource_filename(package, m)
- dst = os.path.join(prefix, m)
- print 'Installing machine %s to %s...' % (src, dst)
- with open(dst, 'wb') as f:
- data = file(src).read()
- f.write(data)
- installnbattr(e, data, m)
- ElementTree(e).write(file(n, 'wb'))
- except ImportError, e:
- pass
-
-
-
-def makedirs(working_dir):
- name = ''
- if os.name != 'nt':
- name = os.sep
- for l, i in enumerate(working_dir.split(os.sep)):
- name = os.path.join(name, i)
- if name.endswith(':') and not l and os.name == 'nt':
- name = '%s%s' % (name, os.sep)
- if not os.path.exists(name):
- os.mkdir(name, 0755)
-
-
-# Main
-def run(args):
-
- if os.name == 'posix' and not os.geteuid():
- login = os.getlogin()
-
- if login != 'root':
- print 'Why are you using root to run this command? You should be using %s! Bringing you down...' % login
- import pwd
- user = pwd.getpwnam(login)
- os.setgid(user.pw_gid)
- os.setuid(user.pw_uid)
-
- opts = parse_args(args)
-
- makedirs(opts.working_dir)
- fix_pypath()
- fix_etree()
-
- if opts.package.endswith('.transforms'):
- opts.package = opts.package.replace('.transforms', '')
-
- try:
- installconf(opts, args)
- except ImportError:
- pass
-
- print ('Looking for transforms in %s.transforms' % opts.package)
- m = None
- try:
- m = import_package('%s.transforms' % opts.package)
- except ImportError, e:
- print ("Does not appear to be a valid canari package. Couldn't import the '%s.transforms' package in '%s'. Error message: %s" % (opts.package, opts.package, e))
- exit(-1)
-
- for t in m.__all__:
- transform = '%s.transforms.%s' % (opts.package, t)
-
- m2 = import_transform(transform)
- if hasattr(m2, 'dotransform') and hasattr(m2.dotransform, 'label'):
- install_transform(
- m2.__name__,
- transform,
- getattr(m2, '__author__', ''),
- m2.dotransform,
- opts.settings_dir,
- opts.working_dir
- )
-
- installmtz(opts.package, opts.settings_dir)
- installmachines(opts.package, opts.settings_dir)
-
- if not transforms:
- print ('Error: no transforms found...')
- exit(-1)
+++ /dev/null
-#!/usr/bin/env python
-
-from common import get_commands, cmd_name, highlight
-
-from argparse import ArgumentParser
-from sys import modules
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-cmds = get_commands()
-cmds.update({'list-commands': modules[__name__]})
-
-parser = ArgumentParser(
- description='Lists all the available canari commands',
- usage='canari %s' % cmd_name(__name__)
-)
-
-
-def help():
- parser.print_help()
-
-
-def description():
- return parser.description
-
-
-def run(args):
- k = cmds.keys()
- k.sort()
- for i in k:
- print ('%s - %s' % (highlight(i, 'green', True), cmds[i].description()))
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-from common import cmd_name, to_utf8
-
-from xml.etree.cElementTree import XML
-from argparse import ArgumentParser
-from zipfile import ZipFile
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.2'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-parser = ArgumentParser(
- description='Convert Maltego graph files (*.mtgx) to comma-separated values (CSV) file.',
- usage='canari %s <graph>' % cmd_name(__name__)
-)
-
-parser.add_argument(
- 'graph',
- metavar='<graph>',
- help='The name of the graph file you wish to convert to CSV.',
-)
-
-
-def parse_args(args):
- return parser.parse_args(args)
-
-
-def help():
- parser.print_help()
-
-
-def description():
- return parser.description
-
-
-def run(args):
-
- opts = parse_args(args)
-
- zip = ZipFile(opts.graph)
- graphs = filter(lambda x: x.endswith('.graphml'), zip.namelist())
-
- for f in graphs:
- csv = open(f.split('/')[1].split('.')[0] + '.csv', 'w')
- xml = XML(zip.open(f).read())
- for e in xml.findall('{http://graphml.graphdrawing.org/xmlns}graph/{http://graphml.graphdrawing.org/xmlns}node/{http://graphml.graphdrawing.org/xmlns}data/{http://maltego.paterva.com/xml/mtgx}MaltegoEntity'):
- csv.write(to_utf8(('"Entity Type=%s",' % e.get('type')).strip()))
- for prop in e.findall('{http://maltego.paterva.com/xml/mtgx}Properties/{http://maltego.paterva.com/xml/mtgx}Property'):
- value = prop.find('{http://maltego.paterva.com/xml/mtgx}Value').text or ''
- if '"' in value:
- value.replace('"', '""')
- csv.write(to_utf8(('"%s=%s",' % (prop.get('displayName'), value)).strip().replace('\n', ', ')))
- csv.write('\n')
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-from common import cmd_name, project_tree
-
-from argparse import ArgumentParser
-from os import path, rename
-from re import sub
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-parser = ArgumentParser(
- description='Renames a transform in the specified directory and auto-updates __init__.py.',
- usage='canari %s <transform name> [options]' % cmd_name(__name__)
-)
-
-parser.add_argument(
- 'transform',
- metavar='<old transform name>',
- help='The name of the transform you wish to rename.'
-)
-
-parser.add_argument(
- 'new_transform',
- metavar='<new transform name>',
- help='The desired name of the transform.'
-)
-
-parser.add_argument(
- '-d',
- '--transform-dir',
- metavar='<dir>',
- help='The directory from which you wish to rename the transform.',
- default=None
-)
-
-
-def help():
- parser.print_help()
-
-
-def description():
- return parser.description
-
-
-def parse_args(args):
- args = parser.parse_args(args)
- if args.transform_dir is None:
- args.transform_dir = project_tree()['transforms']
- return args
-
-
-def run(args):
-
- opts = parse_args(args)
-
- initf = path.join(opts.transform_dir, '__init__.py')
- transform = opts.transform
- transformf = path.join(opts.transform_dir, transform if transform.endswith('.py') else '%s.py' % transform )
- dtransform = opts.new_transform
- dtransformf = path.join(opts.transform_dir, dtransform if dtransform.endswith('.py') else '%s.py' % dtransform )
-
- if not path.exists(initf):
- print ('Directory %s does not appear to be a python package directory... quitting!' % repr(opts.transform_dir))
- exit(-1)
- if not path.exists(transformf):
- print ("Transform %s doesn't exists... quitting" % repr(transformf))
- exit(-1)
- if path.exists(dtransformf):
- print ("Cannot overwrite existing transform %s... quitting" % repr(dtransformf))
- exit(-1)
- if dtransform == transform:
- print ("Nothing to do here... the new name is the same as the old one?")
- exit(-1)
-
- print ('renaming transform %s to %s...' % (repr(transformf), repr(dtransformf)))
- rename(transformf, dtransformf)
-
- print ('updating %s' % initf)
- init = file(initf).read()
-
- with file(initf, mode='wb') as w:
- w.write(
- sub(
- repr(transform),
- repr(dtransform),
- init
- )
- )
-
- print ('done!')
+++ /dev/null
-#!/usr/bin/env python
-
-import os
-import sys
-
-from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
-from xml.etree.cElementTree import fromstring
-from SocketServer import ThreadingMixIn
-from ssl import wrap_socket, CERT_NONE
-from argparse import ArgumentParser
-from cStringIO import StringIO
-from socket import getfqdn
-from urlparse import urlsplit
-from re import sub, findall
-from hashlib import md5
-
-from canari.maltego.message import (MaltegoTransformResponseMessage, MaltegoException, MaltegoTransformRequestMessage,
- MaltegoTransformExceptionMessage, MaltegoMessage, Message)
-from common import cmd_name, import_transform, fix_binpath, fix_pypath, import_package, get_transform_version
-from canari.config import config
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.6'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-parser = ArgumentParser(
- description='Runs a transform server for the given packages.',
- usage='canari %s <transform package> [...]' % cmd_name(__name__)
-)
-
-parser.add_argument(
- 'packages',
- metavar='<package>',
- help='The name of the transform packages you wish to host (e.g. mypkg.transforms).',
- nargs='+'
-)
-
-parser.add_argument(
- '--port',
- metavar='<port>',
- default=-1,
- type=int,
- help='The port the server will run on.'
-)
-
-parser.add_argument(
- '--disable-ssl',
- action='store_true',
- default=False,
- help='Any extra parameters that can be sent to the local transform.'
-)
-
-parser.add_argument(
- '--enable-privileged',
- action='store_true',
- default=False,
- help='DANGEROUS: permit TDS to run packages that require elevated privileges.'
-)
-
-parser.add_argument(
- '--listen-on',
- metavar='[address]',
- default='',
- help='The address of the interface to listen on.'
-)
-
-parser.add_argument(
- '--cert',
- metavar='[certificate]',
- default='cert.pem',
- help='The name of the certificate file used for the server in PEM format.'
-)
-
-parser.add_argument(
- '--hostname',
- metavar='[hostname]',
- default=None,
- help='The hostname of this transform server.'
-)
-
-parser.add_argument(
- '--daemon',
- default=False,
- action='store_true',
- help='Daemonize server (fork to background).'
-)
-
-
-def help():
- parser.print_help()
-
-
-def description():
- return parser.description
-
-
-def message(m, r):
- """Write a MaltegoMessage to stdout and exit successfully"""
-
- r.send_response(200)
- r.send_header('Content-Type', 'text/xml')
- r.send_header('Connection', 'close')
- r.end_headers()
-
- v = None
- if isinstance(m, basestring):
- for url in findall("<iconurl>\s*(file://[^\s<]+)\s*</iconurl>(?im)", m):
- path = '/%s' % md5(url).hexdigest()
- new_url = '%s://%s%s' % ('https' if r.server.is_ssl else 'http', r.server.hostname, path)
- if path not in r.server.resources:
- r.server.resources[path] = url[7:]
- m.replace(url, new_url, 1)
- v = m
- else:
- sio = StringIO()
- for e in m.entities:
- if e.iconurl is not None:
- e.iconurl = e.iconurl.strip()
- if e.iconurl.startswith('file://'):
- path = '/%s' % md5(e.iconurl).hexdigest()
- new_url = '%s://%s%s' % ('https' if r.server.is_ssl else 'http', r.server.hostname, path)
- if path not in r.server.resources:
- r.server.resources[path] = e.iconurl[7:]
- e.iconurl = new_url
-
- Message(MaltegoMessage(m)).write(sio)
- v = sio.getvalue()
- # Get rid of those nasty unicode 32 characters
- r.wfile.write(sub(r'(&#\d{5};){2}', r'', v))
-
-
-def croak(error_msg, r):
- """Throw an exception in the Maltego GUI containing error_msg."""
-
- r.send_response(200)
- r.send_header('Content-Type', 'text/xml')
- r.send_header('Connection', 'close')
- r.end_headers()
-
- Message(
- MaltegoMessage(
- MaltegoTransformExceptionMessage(exceptions=MaltegoException(error_msg)
- )
- )
- ).write(file=r.wfile)
-
-
-class MaltegoTransformRequestHandler(BaseHTTPRequestHandler):
-
- protocol_version = 'HTTP/1.1'
- server_version = 'Canari/1.0'
- count = 0
-
-
- def dotransform(self, t):
- try:
- if 'Content-Length' not in self.headers:
- self.send_error(500, 'What?')
- return
-
- request_str = self.rfile.read(int(self.headers['Content-Length']))
-
- xml = fromstring(request_str).find('MaltegoTransformRequestMessage')
-
- e = xml.find('Entities/Entity')
- etype = e.get('Type', '')
-
- if t[1] and etype not in t[1]:
- self.send_error(400, 'Unsupported input entity!')
- return
-
- value = e.find('Value').text or ''
- fields = dict([(f.get('Name', ''), f.text) for f in xml.findall('Entities/Entity/AdditionalFields/Field')])
- params = dict([(f.get('Name', ''), f.text) for f in xml.findall('TransformFields/Field')])
- for k, i in params.items():
- if '.' in k:
- config[k.replace('.', '/', 1)] = i
- else:
- config['default/%s' % k] = i
- limits = xml.find('Limits').attrib
-
- msg = t[0](
- MaltegoTransformRequestMessage(value, fields, params, limits),
- request_str if hasattr(t[0], 'cmd') and callable(t[0].cmd) else MaltegoTransformResponseMessage()
- ) if get_transform_version(t[0]) == 2 else t[0](
- MaltegoTransformRequestMessage(value, fields, params, limits),
- request_str if hasattr(t[0], 'cmd') and callable(t[0].cmd) else MaltegoTransformResponseMessage(),
- config
- )
-
- if isinstance(msg, MaltegoTransformResponseMessage) or isinstance(msg, basestring):
- message(msg, self)
- return
- else:
- raise MaltegoException('Could not resolve message type returned by transform.')
-
- except MaltegoException, me:
- croak(str(me), self)
- except Exception, e:
- croak(str(e), self)
-
- def do_POST(self):
- path = urlsplit(self.path or '/').path
-
- if path not in self.server.transforms:
- self.send_error(404, "Duh?")
- else:
- self.dotransform(self.server.transforms[path])
-
- def do_GET(self):
- path = urlsplit(self.path or '/').path
- if path in self.server.transforms:
- self.send_error(200, 'Yes')
- return
- elif path in self.server.resources:
- self.send_response(200)
- self.send_header('Content-Type', 'application/octet-stream')
- self.send_header('Connection', 'close')
- self.end_headers()
- self.wfile.write(file(self.server.resources[path]).read())
- return
-
- self.send_error(404, 'No')
-
-
-class MaltegoHTTPServer(HTTPServer):
-
- server_name = 'Canari'
- resources = {}
- is_ssl = False
-
- def __init__(self, server_address=('', 8080), RequestHandlerClass=MaltegoTransformRequestHandler,
- bind_and_activate=True, transforms={}, hostname=getfqdn()):
- HTTPServer.__init__(self, server_address, RequestHandlerClass, bind_and_activate)
- self.transforms = transforms
- self.hostname = hostname
-
-
-class SecureMaltegoHTTPServer(MaltegoHTTPServer):
-
- is_ssl = True
-
- def __init__(self, server_address=('', 8080), RequestHandlerClass=MaltegoTransformRequestHandler,
- bind_and_activate=True, transforms={}, cert='cert.pem', hostname=getfqdn()):
- MaltegoHTTPServer.__init__(
- self,
- server_address,
- RequestHandlerClass,
- bind_and_activate=bind_and_activate,
- transforms=transforms,
- hostname=hostname
- )
- self.socket = wrap_socket(self.socket, server_side=True, certfile=cert, cert_reqs=CERT_NONE)
-
-
-class AsyncSecureMaltegoHTTPServer(ThreadingMixIn, SecureMaltegoHTTPServer):
- pass
-
-
-class AsyncMaltegoHTTPServer(ThreadingMixIn, MaltegoHTTPServer):
- pass
-
-
-def parse_args(args):
- args = parser.parse_args(args)
- if args.hostname is None:
- args.hostname = getfqdn()
- return args
-
-
-def run(args):
-
- opts = parse_args(args)
-
- fix_pypath()
-
- if opts.port == -1:
- opts.port = 443 if not opts.disable_ssl else 80
-
- if os.name == 'posix' and os.geteuid() and (opts.port <= 1024 or opts.enable_privileged):
- print ('You must run this server as root to continue...')
- os.execvp('sudo', ['sudo'] + sys.argv)
-
- fix_binpath(config['default/path'])
-
-
- transforms = {}
-
- print ('Loading transform packages...')
-
- try:
- for p in opts.packages:
-
- if not p.endswith('.transforms'):
- p = ('%s.transforms' % p)
-
- print ('Loading transform package %s' % p)
-
- m = import_package(p)
-
- for t in m.__all__:
-
- t = ('%s.%s' % (p, t))
- m2 = import_transform(t)
-
- if not hasattr(m2, 'dotransform'):
- continue
-
- if os.name == 'posix' and hasattr(m2.dotransform, 'privileged') and (os.geteuid() or not opts.enable_privileged):
- continue
-
- if hasattr(m2.dotransform, 'remote') and m2.dotransform.remote:
- print ('Loading %s at /%s...' % (t, t))
- if hasattr(m2.dotransform, 'inputs'):
- inputs = [e[1]('').type for e in m2.dotransform.inputs]
- inputs = inputs + [i.split('.')[-1] for i in inputs]
- transforms['/%s' % t] = (m2.dotransform, inputs)
- else:
- transforms['/%s' % t] = (m2.dotransform, [])
-
- except Exception, e:
- print (str(e))
- print ('Failed to load transforms... exiting')
- exit(-1)
-
- if not transforms:
- print ("Couldn't find any remote transforms... you sure you got this right?")
- exit(-1)
-
- httpd = None
-
- print ('Starting web server on %s:%s...' % (opts.listen_on, opts.port))
- server_address = (opts.listen_on, opts.port)
-
- if not opts.disable_ssl:
- if not os.path.exists(opts.cert):
- print ('The certificate file %s does not exist. Please create a PEM file...' % repr(opts.cert))
- exit(-1)
- print ('Making it secure (1337)...')
- httpd = AsyncSecureMaltegoHTTPServer(server_address=server_address,
- transforms=transforms, cert=opts.cert, hostname=opts.hostname)
- else:
- print ('Really? Over regular HTTP? What a shame...')
- httpd = AsyncMaltegoHTTPServer(server_address=server_address, transforms=transforms, hostname=opts.hostname)
-
- if not opts.daemon or not os.fork():
- try:
- httpd.serve_forever()
- except KeyboardInterrupt:
- httpd.server_close()
- exit(0)
+++ /dev/null
-#!/usr/bin/env python
-
-import os
-import sys
-from traceback import format_exc
-
-from argparse import ArgumentParser
-
-from canari.maltego.message import (MaltegoException, MaltegoTransformResponseMessage, UIMessage,
- MaltegoTransformRequestMessage)
-from canari.maltego.utils import onterminate, parseargs, croak, message
-from common import cmd_name, import_transform, fix_binpath, sudo, get_transform_version
-from canari.config import config
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.4'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-parser = ArgumentParser(
- description='Runs Canari local transforms in a terminal-friendly fashion.',
- usage='canari %s <transform> [param1 ... paramN] <value> [field1=value1...#fieldN=valueN]' % cmd_name(__name__)
-)
-
-parser.add_argument(
- 'transform',
- metavar='<transform>',
- help='The name of the transform you wish to run (e.g. sploitego.transforms.nmapfastscan).'
-)
-
-parser.add_argument(
- 'value',
- metavar='<value>',
- help='The value of the input entity being passed into the local transform.'
-)
-
-parser.add_argument(
- 'params',
- metavar='[param1 ... paramN]',
- help='Any extra parameters that can be sent to the local transform.'
-)
-
-parser.add_argument(
- 'fields',
- metavar='[field1=value1...#fieldN=valueN]',
- help='The fields of the input entity being passed into the local transform.'
-)
-
-
-def help():
- parser.print_help()
-
-
-def description():
- return parser.description
-
-
-def run(args):
-
- [transform, params, value, fields] = parseargs(['canari %s' % cmd_name(__name__)] + args)
-
- m = None
-
- fix_binpath(config['default/path'])
- try:
- m = import_transform(transform)
-
- if os.name == 'posix' and hasattr(m.dotransform, 'privileged') and os.geteuid():
- rc = sudo(sys.argv)
- if rc == 1:
- message(MaltegoTransformResponseMessage() + UIMessage('User cancelled transform.'))
- elif rc == 2:
- message(MaltegoTransformResponseMessage() + UIMessage('Too many incorrect password attempts.'))
- elif rc:
- message(MaltegoTransformResponseMessage() + UIMessage('Unknown error occurred.'))
- exit(0)
-
- if hasattr(m, 'onterminate'):
- onterminate(m.onterminate)
- else:
- m.__setattr__('onterminate', lambda *args: exit(-1))
-
- msg = m.dotransform(
- MaltegoTransformRequestMessage(value, fields, params),
- MaltegoTransformResponseMessage()
- ) if get_transform_version(m.dotransform) == 2 else m.dotransform(
- MaltegoTransformRequestMessage(value, fields, params),
- MaltegoTransformResponseMessage(),
- config
- )
-
- if isinstance(msg, MaltegoTransformResponseMessage):
- message(msg)
- elif isinstance(msg, basestring):
- raise MaltegoException(msg)
- else:
- raise MaltegoException('Could not resolve message type returned by transform.')
- except MaltegoException, me:
- croak(str(me))
- except ImportError:
- e = format_exc()
- croak(e)
- except Exception:
- e = format_exc()
- croak(e)
- except KeyboardInterrupt, be:
- if m is not None:
- m.onterminate()
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-import os
-import sys
-
-from code import InteractiveConsole
-from argparse import ArgumentParser
-from atexit import register
-
-from common import console_message, cmd_name, highlight, fix_pypath, fix_binpath, import_package
-from canari.maltego.message import MaltegoTransformResponseMessage
-from canari.config import config
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.2'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-parser = ArgumentParser(
- description='Creates a Canari debug shell for the specified transform package.',
- usage='canari %s <package name>' % cmd_name(__name__)
-)
-
-parser.add_argument(
- 'package',
- metavar='<package name>',
- help='The name of the canari package you wish to load local transform from for the Canari shell session.'
-)
-
-
-def help():
- parser.print_help()
-
-
-def description():
- return parser.description
-
-
-class ShellCommand(object):
-
- def __init__(self, mod):
- self.mod = mod
- self.sudoargs = ['sudo'] + list(sys.argv)
-
- def __call__(self, value, *args, **kwargs):
- if os.name == 'posix' and hasattr(self.mod.dotransform, 'privileged') and os.geteuid():
- print highlight("Need to be root to run this transform... sudo'ing...", 'green', True)
- os.execvp('sudo', self.sudoargs)
- return
- return console_message(self.mod.dotransform(
- type(
- 'MaltegoTransformRequestMessage',
- (object,),
- {
- 'value' : value,
- 'params' : list(args),
- 'fields' : kwargs
- }
- )(),
- MaltegoTransformResponseMessage()
- ))
-
-
-class MtgConsole(InteractiveConsole):
-
- def __init__(self, package):
- package = import_package(package)
- transforms = dict(dir=dir)
- for name, mod in package.__dict__.iteritems():
- if getattr(mod, 'dotransform', ''):
- transforms[name] = ShellCommand(mod)
- InteractiveConsole.__init__(self, locals=transforms)
- self.init_history(os.path.expanduser('~/.mtgsh_history'))
-
- def init_history(self, histfile):
- try:
- import readline
- readline.parse_and_bind('tab: complete')
- if hasattr(readline, "read_history_file"):
- try:
- readline.read_history_file(histfile)
- except IOError:
- pass
- register(lambda h: readline.write_history_file(h), histfile)
- except ImportError:
- pass
-
-
-def run(args):
-
- opts = parser.parse_args(args)
-
- fix_binpath(config['default/path'])
- fix_pypath()
-
- if not opts.package.endswith('transforms'):
- opts.package = '%s.transforms' % opts.package
-
- mtgsh = MtgConsole(opts.package)
- mtgsh.interact(highlight('Welcome to Canari.', 'green', True))
+++ /dev/null
-#!/usr/bin/env python
-
-from common import detect_settings_dir, cmd_name, fix_pypath, import_package, import_transform, fix_etree
-
-from xml.etree.cElementTree import ElementTree, XML
-from os import path, mkdir, listdir, unlink, rmdir
-from pkg_resources import resource_listdir
-from argparse import ArgumentParser
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.2'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-# Argument parser
-parser = ArgumentParser(
- description="Uninstalls and unconfigures canari transform packages in Maltego's UI",
- usage='canari %s <package> [options]' % cmd_name(__name__)
-)
-
-parser.add_argument(
- 'package',
- metavar='<package>',
- help='the name of the canari transforms package to uninstall.'
-)
-parser.add_argument(
- '-s',
- '--settings-dir',
- metavar='[settings dir]',
- default=detect_settings_dir,
- help='the path to the Maltego settings directory (automatically detected if excluded)'
-)
-
-
-def help():
- parser.print_help()
-
-
-def description():
- return parser.description
-
-
-def uninstallnbattr(machine, xml):
- e = xml.find('fileobject[@name="%s"]' % machine)
- if e is not None:
- xml.remove(e)
-
-def uninstallmachines(package, prefix):
- try:
- prefix = path.join(prefix, 'config', 'Maltego', 'Machines')
- n = path.join(prefix, '.nbattrs')
- e = XML('<attributes version="1.0"/>')
- if path.exists(n):
- e = XML(file(n).read())
- if not path.exists(prefix):
- return
- package = '%s.resources.maltego' % package
- for m in filter(lambda x: x.endswith('.machine'), resource_listdir(package, '')):
- print 'Uninstalling machine %s...' % m
- try:
- unlink(path.join(prefix, m))
- uninstallnbattr(m, e)
- except OSError:
- pass
- ElementTree(e).write(file(n, 'wb'))
- except ImportError, e:
- pass
-
-
-def uninstall_transform(module, spec, prefix):
-
- installdir = path.join(prefix, 'config', 'Maltego', 'TransformRepositories', 'Local')
-
- if not path.exists(installdir):
- mkdir(installdir)
-
- setsdir = path.join(prefix, 'config', 'Maltego', 'TransformSets')
-
- for i,n in enumerate(spec.uuids):
-
- print ('Uninstalling transform %s from %s...' % (n, module))
-
- if spec.inputs[i][0] is not None:
- setdir = path.join(setsdir, spec.inputs[i][0])
- f = path.join(setdir, n)
- if path.exists(f):
- unlink(f)
- if path.exists(setdir) and not listdir(setdir):
- rmdir(setdir)
-
- tf = path.join(installdir, '%s.transform' % n)
- tsf = path.join(installdir, '%s.transformsettings' % n)
-
- if path.exists(tf):
- unlink(tf)
- if path.exists(tsf):
- unlink(tsf)
-
-
-def parse_args(args):
- args = parser.parse_args(args)
- if args.settings_dir is detect_settings_dir:
- args.settings_dir = detect_settings_dir()
- return args
-
-
-def run(args):
-
- opts = parse_args(args)
-
- if opts.package.endswith('.transforms'):
- opts.package = opts.package.replace('.transforms', '')
-
- fix_pypath()
-
- fix_etree()
-
- m = import_package('%s.transforms' % opts.package)
-
- for t in m.__all__:
- transform = '%s.transforms.%s' % (opts.package, t)
- m2 = import_transform(transform)
- if hasattr(m2, 'dotransform') and hasattr(m2.dotransform, 'label'):
- uninstall_transform(
- m2.__name__,
- m2.dotransform,
- opts.settings_dir
- )
-
- uninstallmachines(opts.package, opts.settings_dir)
+++ /dev/null
-#!/usr/bin/env python
-
-from common import get_commands, cmd_name
-from argparse import ArgumentParser
-from sys import modules
-
-import canari
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-parser = ArgumentParser(
- description='Show version of Canari framework that is currently active.',
- usage='canari %s' % cmd_name(__name__)
-)
-
-
-def help():
- parser.print_help()
-
-
-def description():
- return parser.description
-
-
-def run(args):
- print 'Your running *Canari Framework v%s*' % canari.__version__
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-from resource import conf
-
-from re import findall, search, match, split
-from ConfigParser import SafeConfigParser
-from os import environ, getcwd, path
-from utils.wordlist import wordlist
-from urlparse import urlsplit
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.2'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-__all__ = [
- 'CanariConfigParser',
- 'config'
-]
-
-
-class CanariConfigParser(SafeConfigParser):
-
- def _interpolate_environment_variables(self, value):
- if isinstance(value, str):
- evs = self._get_env_vars(value)
- if evs:
- for ev in evs:
- s = '${%s}' % ev
- value = value.replace(s, environ[ev])
- return value
-
- def _interpolate(self, section, option, value, d):
- if isinstance(value, str):
- value = self._interpolate_environment_variables(value)
- elif isinstance(value, dict):
- for i in value:
- value[i] = self._interpolate_environment_variables(value[i])
- else:
- for i in range(0, len(value)):
- value[i] = self._interpolate_environment_variables(value[i])
- value = SafeConfigParser._interpolate(self, section, option, value, d)
- return value
-
- def _get_env_vars(self, value):
- return findall(r'\${(.+?)}', value)
-
- def __iadd__(self, other):
- self.add_section(other)
- return self
-
- def __isub__(self, other):
- self.remove_section(other)
- return self
-
- def __getitem__(self, item):
- section,option = item.split('/')
- value = self.get(section, option)
- if isinstance(value, basestring):
- if value.startswith('module:'):
- r = urlsplit(value.replace('module', 'http'))
- try:
- v = r.path.lstrip('/')
- m = __import__(r.netloc, globals(), locals(), [v])
- value = m.__dict__[v]
- except ImportError:
- pass
- elif match(r'^\d+$', value) is not None:
- value = int(value)
- elif match(r'^\d+\.\d+$', value) is not None:
- value = float(value)
- elif search(r'\s*(?<=[^\\]),+\s*', value) is not None:
- l = split(r'\s*(?<=[^\\]),+\s*', value)
- value = []
- for v in l:
- if match(r'^\d+$', v) is not None:
- v = int(v)
- elif match(r'^\d+\.\d+$', v) is not None:
- v = float(v)
- else:
- v = v.replace(r'\,', ',')
- value.append(v)
- else:
- value = value.replace(r'\,', ',')
- if option == 'wordlist':
- value = wordlist(value)
- return value
-
- def __setitem__(self, key, value):
- section,option = key.split('/')
- if not self.has_section(section):
- self.add_section(section)
- self.set(section, option, value)
-
-
-config = CanariConfigParser()
-
-dconf = path.join( conf )
-lconf = path.join( getcwd(), 'canari.conf' )
-
-config.read([ dconf , lconf ])
-config.read(config['default/configs'])
\ No newline at end of file
+++ /dev/null
-"""
-@version: 0.96(2010-08-29)
-
-@note:
-ABOUT EASYGUI
-
-EasyGui provides an easy-to-use interface for simple GUI interaction
-with a user. It does not require the programmer to know anything about
-tkinter, frames, widgets, callbacks or lambda. All GUI interactions are
-invoked by simple function calls that return results.
-
-@note:
-WARNING about using EasyGui with IDLE
-
-You may encounter problems using IDLE to run programs that use EasyGui. Try it
-and find out. EasyGui is a collection of Tkinter routines that run their own
-event loops. IDLE is also a Tkinter application, with its own event loop. The
-two may conflict, with unpredictable results. If you find that you have
-problems, try running your EasyGui program outside of IDLE.
-
-Note that EasyGui requires Tk release 8.0 or greater.
-
-@note:
-LICENSE INFORMATION
-
-EasyGui version 0.96
-
-Copyright (c) 2010, Stephen Raymond Ferg
-
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation and/or
- other materials provided with the distribution.
-
- 3. The name of the author may not be used to endorse or promote products derived
- from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-STRICT LIABILITY, 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.
-
-@note:
-ABOUT THE EASYGUI LICENSE
-
-This license is what is generally known as the "modified BSD license",
-aka "revised BSD", "new BSD", "3-clause BSD".
-See http://www.opensource.org/licenses/bsd-license.php
-
-This license is GPL-compatible.
-See http://en.wikipedia.org/wiki/License_compatibility
-See http://www.gnu.org/licenses/license-list.html#GPLCompatibleLicenses
-
-The BSD License is less restrictive than GPL.
-It allows software released under the license to be incorporated into proprietary products.
-Works based on the software may be released under a proprietary license or as closed source software.
-http://en.wikipedia.org/wiki/BSD_licenses#3-clause_license_.28.22New_BSD_License.22.29
-
-"""
-egversion = __doc__.split()[1]
-
-__all__ = ['ynbox'
- , 'ccbox'
- , 'boolbox'
- , 'indexbox'
- , 'msgbox'
- , 'buttonbox'
- , 'integerbox'
- , 'multenterbox'
- , 'enterbox'
- , 'exceptionbox'
- , 'choicebox'
- , 'codebox'
- , 'textbox'
- , 'diropenbox'
- , 'fileopenbox'
- , 'filesavebox'
- , 'passwordbox'
- , 'multpasswordbox'
- , 'multchoicebox'
-# , 'abouteasygui'
- , 'egversion'
-# , 'egdemo'
-# , 'EgStore'
- ]
-
-import sys, os
-import string
-import pickle
-import traceback
-
-
-#--------------------------------------------------
-# check python version and take appropriate action
-#--------------------------------------------------
-"""
-From the python documentation:
-
-sys.hexversion contains the version number encoded as a single integer. This is
-guaranteed to increase with each version, including proper support for non-
-production releases. For example, to test that the Python interpreter is at
-least version 1.5.2, use:
-
-if sys.hexversion >= 0x010502F0:
- # use some advanced feature
- ...
-else:
- # use an alternative implementation or warn the user
- ...
-"""
-
-
-if sys.hexversion >= 0x020600F0:
- runningPython26 = True
-else:
- runningPython26 = False
-
-if sys.hexversion >= 0x030000F0:
- runningPython3 = True
-else:
- runningPython3 = False
-
-try:
- from PIL import Image as PILImage
- from PIL import ImageTk as PILImageTk
- PILisLoaded = True
-except:
- PILisLoaded = False
-
-
-if runningPython3:
- from tkinter import *
- import tkinter.filedialog as tk_FileDialog
- from io import StringIO
-else:
- from Tkinter import *
- import tkFileDialog as tk_FileDialog
- from StringIO import StringIO
-
-def write(*args):
- args = [str(arg) for arg in args]
- args = " ".join(args)
- sys.stdout.write(args)
-
-def writeln(*args):
- write(*args)
- sys.stdout.write("\n")
-
-say = writeln
-
-
-if TkVersion < 8.0 :
- stars = "*"*75
- writeln("""\n\n\n""" + stars + """
-You are running Tk version: """ + str(TkVersion) + """
-You must be using Tk version 8.0 or greater to use EasyGui.
-Terminating.
-""" + stars + """\n\n\n""")
- sys.exit(0)
-
-def dq(s):
- return '"%s"' % s
-
-rootWindowPosition = "+300+200"
-
-PROPORTIONAL_FONT_FAMILY = ("MS", "Sans", "Serif")
-MONOSPACE_FONT_FAMILY = ("Courier")
-
-PROPORTIONAL_FONT_SIZE = 10
-MONOSPACE_FONT_SIZE = 9 #a little smaller, because it it more legible at a smaller size
-TEXT_ENTRY_FONT_SIZE = 12 # a little larger makes it easier to see
-
-#STANDARD_SELECTION_EVENTS = ["Return", "Button-1"]
-STANDARD_SELECTION_EVENTS = ["Return", "Button-1", "space"]
-
-# Initialize some global variables that will be reset later
-__choiceboxMultipleSelect = None
-__widgetTexts = None
-__replyButtonText = None
-__choiceboxResults = None
-__firstWidget = None
-__enterboxText = None
-__enterboxDefaultText=""
-__multenterboxText = ""
-choiceboxChoices = None
-choiceboxWidget = None
-entryWidget = None
-boxRoot = None
-ImageErrorMsg = (
- "\n\n---------------------------------------------\n"
- "Error: %s\n%s")
-
-def _bring_to_front():
- from subprocess import Popen
- Tk().destroy()
- Popen([
- 'osascript',
- '-e', 'tell application "System Events"',
- '-e', 'set vprocs to every process whose unix id is %s' % os.getpid(),
- '-e', 'repeat with proc in vprocs',
- '-e', 'set the frontmost of proc to true',
- '-e', 'end repeat',
- '-e', 'end tell'
- ])
-#-------------------------------------------------------------------
-# various boxes built on top of the basic buttonbox
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# ynbox
-#-----------------------------------------------------------------------
-def ynbox(msg="Shall I continue?"
- , title=" "
- , choices=("Yes", "No")
- , image=None
- ):
- """
- Display a msgbox with choices of Yes and No.
-
- The default is "Yes".
-
- The returned value is calculated this way::
- if the first choice ("Yes") is chosen, or if the dialog is cancelled:
- return 1
- else:
- return 0
-
- If invoked without a msg argument, displays a generic request for a confirmation
- that the user wishes to continue. So it can be used this way::
- if ynbox(): pass # continue
- else: sys.exit(0) # exit the program
-
- @arg msg: the msg to be displayed.
- @arg title: the window title
- @arg choices: a list or tuple of the choices to be displayed
- """
- return boolbox(msg, title, choices, image=image)
-
-
-#-----------------------------------------------------------------------
-# ccbox
-#-----------------------------------------------------------------------
-def ccbox(msg="Shall I continue?"
- , title=" "
- , choices=("Continue", "Cancel")
- , image=None
- ):
- """
- Display a msgbox with choices of Continue and Cancel.
-
- The default is "Continue".
-
- The returned value is calculated this way::
- if the first choice ("Continue") is chosen, or if the dialog is cancelled:
- return 1
- else:
- return 0
-
- If invoked without a msg argument, displays a generic request for a confirmation
- that the user wishes to continue. So it can be used this way::
-
- if ccbox():
- pass # continue
- else:
- sys.exit(0) # exit the program
-
- @arg msg: the msg to be displayed.
- @arg title: the window title
- @arg choices: a list or tuple of the choices to be displayed
- """
- return boolbox(msg, title, choices, image=image)
-
-
-#-----------------------------------------------------------------------
-# boolbox
-#-----------------------------------------------------------------------
-def boolbox(msg="Shall I continue?"
- , title=" "
- , choices=("Yes","No")
- , image=None
- ):
- """
- Display a boolean msgbox.
-
- The default is the first choice.
-
- The returned value is calculated this way::
- if the first choice is chosen, or if the dialog is cancelled:
- returns 1
- else:
- returns 0
- """
- reply = buttonbox(msg=msg, choices=choices, title=title, image=image)
- if reply == choices[0]: return 1
- else: return 0
-
-
-#-----------------------------------------------------------------------
-# indexbox
-#-----------------------------------------------------------------------
-def indexbox(msg="Shall I continue?"
- , title=" "
- , choices=("Yes","No")
- , image=None
- ):
- """
- Display a buttonbox with the specified choices.
- Return the index of the choice selected.
- """
- reply = buttonbox(msg=msg, choices=choices, title=title, image=image)
- index = -1
- for choice in choices:
- index = index + 1
- if reply == choice: return index
- raise AssertionError(
- "There is a program logic error in the EasyGui code for indexbox.")
-
-
-#-----------------------------------------------------------------------
-# msgbox
-#-----------------------------------------------------------------------
-def msgbox(msg="(Your message goes here)", title=" ", ok_button="OK",image=None,root=None):
- """
- Display a messagebox
- """
- if type(ok_button) != type("OK"):
- raise AssertionError("The 'ok_button' argument to msgbox must be a string.")
-
- return buttonbox(msg=msg, title=title, choices=[ok_button], image=image,root=root)
-
-
-#-------------------------------------------------------------------
-# buttonbox
-#-------------------------------------------------------------------
-def buttonbox(msg="",title=" "
- ,choices=("Button1", "Button2", "Button3")
- , image=None
- , root=None
- ):
- """
- Display a msg, a title, and a set of buttons.
- The buttons are defined by the members of the choices list.
- Return the text of the button that the user selected.
-
- @arg msg: the msg to be displayed.
- @arg title: the window title
- @arg choices: a list or tuple of the choices to be displayed
- """
- if sys.platform == 'darwin':
- _bring_to_front()
-
- global boxRoot, __replyButtonText, __widgetTexts, buttonsFrame
-
-
- # Initialize __replyButtonText to the first choice.
- # This is what will be used if the window is closed by the close button.
- __replyButtonText = choices[0]
-
- if root:
- root.withdraw()
- boxRoot = Toplevel(master=root)
- boxRoot.withdraw()
- else:
- boxRoot = Tk()
- boxRoot.withdraw()
-
- boxRoot.protocol('WM_DELETE_WINDOW', denyWindowManagerClose )
- boxRoot.title(title)
- boxRoot.iconname('Dialog')
- boxRoot.geometry(rootWindowPosition)
- boxRoot.minsize(400, 100)
-
- # ------------- define the messageFrame ---------------------------------
- messageFrame = Frame(master=boxRoot)
- messageFrame.pack(side=TOP, fill=BOTH)
-
- # ------------- define the imageFrame ---------------------------------
- tk_Image = None
- if image:
- imageFilename = os.path.normpath(image)
- junk,ext = os.path.splitext(imageFilename)
-
- if os.path.exists(imageFilename):
- if ext.lower() in [".gif", ".pgm", ".ppm"]:
- tk_Image = PhotoImage(master=boxRoot, file=imageFilename)
- else:
- if PILisLoaded:
- try:
- pil_Image = PILImage.open(imageFilename)
- tk_Image = PILImageTk.PhotoImage(pil_Image, master=boxRoot)
- except:
- msg += ImageErrorMsg % (imageFilename,
- "\nThe Python Imaging Library (PIL) could not convert this file to a displayable image."
- "\n\nPIL reports:\n" + exception_format())
-
- else: # PIL is not loaded
- msg += ImageErrorMsg % (imageFilename,
- "\nI could not import the Python Imaging Library (PIL) to display the image.\n\n"
- "You may need to install PIL\n"
- "(http://www.pythonware.com/products/pil/)\n"
- "to display " + ext + " image files.")
-
- else:
- msg += ImageErrorMsg % (imageFilename, "\nImage file not found.")
-
- if tk_Image:
- imageFrame = Frame(master=boxRoot)
- imageFrame.pack(side=TOP, fill=BOTH)
- label = Label(imageFrame,image=tk_Image)
- label.image = tk_Image # keep a reference!
- label.pack(side=TOP, expand=YES, fill=X, padx='1m', pady='1m')
-
- # ------------- define the buttonsFrame ---------------------------------
- buttonsFrame = Frame(master=boxRoot)
- buttonsFrame.pack(side=TOP, fill=BOTH)
-
- # -------------------- place the widgets in the frames -----------------------
- messageWidget = Message(messageFrame, text=msg, width=400)
- messageWidget.configure(font=(PROPORTIONAL_FONT_FAMILY,PROPORTIONAL_FONT_SIZE))
- messageWidget.pack(side=TOP, expand=YES, fill=X, padx='3m', pady='3m')
-
- __put_buttons_in_buttonframe(choices)
-
- # -------------- the action begins -----------
- # put the focus on the first button
- __firstWidget.focus_force()
-
- boxRoot.deiconify()
- boxRoot.mainloop()
- boxRoot.destroy()
- if root: root.deiconify()
- return __replyButtonText
-
-
-#-------------------------------------------------------------------
-# integerbox
-#-------------------------------------------------------------------
-def integerbox(msg=""
- , title=" "
- , default=""
- , lowerbound=0
- , upperbound=99
- , image = None
- , root = None
- , **invalidKeywordArguments
- ):
- """
- Show a box in which a user can enter an integer.
-
- In addition to arguments for msg and title, this function accepts
- integer arguments for "default", "lowerbound", and "upperbound".
-
- The default argument may be None.
-
- When the user enters some text, the text is checked to verify that it
- can be converted to an integer between the lowerbound and upperbound.
-
- If it can be, the integer (not the text) is returned.
-
- If it cannot, then an error msg is displayed, and the integerbox is
- redisplayed.
-
- If the user cancels the operation, None is returned.
-
- NOTE that the "argLowerBound" and "argUpperBound" arguments are no longer
- supported. They have been replaced by "upperbound" and "lowerbound".
- """
- if sys.platform == 'darwin':
- _bring_to_front()
- if "argLowerBound" in invalidKeywordArguments:
- raise AssertionError(
- "\nintegerbox no longer supports the 'argLowerBound' argument.\n"
- + "Use 'lowerbound' instead.\n\n")
- if "argUpperBound" in invalidKeywordArguments:
- raise AssertionError(
- "\nintegerbox no longer supports the 'argUpperBound' argument.\n"
- + "Use 'upperbound' instead.\n\n")
-
- if default != "":
- if type(default) != type(1):
- raise AssertionError(
- "integerbox received a non-integer value for "
- + "default of " + dq(str(default)) , "Error")
-
- if type(lowerbound) != type(1):
- raise AssertionError(
- "integerbox received a non-integer value for "
- + "lowerbound of " + dq(str(lowerbound)) , "Error")
-
- if type(upperbound) != type(1):
- raise AssertionError(
- "integerbox received a non-integer value for "
- + "upperbound of " + dq(str(upperbound)) , "Error")
-
- if msg == "":
- msg = ("Enter an integer between " + str(lowerbound)
- + " and "
- + str(upperbound)
- )
-
- while 1:
- reply = enterbox(msg, title, str(default), image=image, root=root)
- if reply is None:
- return None
-
- try:
- reply = int(reply)
- except:
- msgbox ("The value that you entered:\n\t%s\nis not an integer." % dq(str(reply))
- , "Error")
- continue
-
- if reply < lowerbound:
- msgbox ("The value that you entered is less than the lower bound of "
- + str(lowerbound) + ".", "Error")
- continue
-
- if reply > upperbound:
- msgbox ("The value that you entered is greater than the upper bound of "
- + str(upperbound) + ".", "Error")
- continue
-
- # reply has passed all validation checks.
- # It is an integer between the specified bounds.
- return reply
-
-#-------------------------------------------------------------------
-# multenterbox
-#-------------------------------------------------------------------
-def multenterbox(msg="Fill in values for the fields."
- , title=" "
- , fields=()
- , values=()
- ):
- r"""
- Show screen with multiple data entry fields.
-
- If there are fewer values than names, the list of values is padded with
- empty strings until the number of values is the same as the number of names.
-
- If there are more values than names, the list of values
- is truncated so that there are as many values as names.
-
- Returns a list of the values of the fields,
- or None if the user cancels the operation.
-
- Here is some example code, that shows how values returned from
- multenterbox can be checked for validity before they are accepted::
- ----------------------------------------------------------------------
- msg = "Enter your personal information"
- title = "Credit Card Application"
- fieldNames = ["Name","Street Address","City","State","ZipCode"]
- fieldValues = [] # we start with blanks for the values
- fieldValues = multenterbox(msg,title, fieldNames)
-
- # make sure that none of the fields was left blank
- while 1:
- if fieldValues == None: break
- errmsg = ""
- for i in range(len(fieldNames)):
- if fieldValues[i].strip() == "":
- errmsg += ('"%s" is a required field.\n\n' % fieldNames[i])
- if errmsg == "":
- break # no problems found
- fieldValues = multenterbox(errmsg, title, fieldNames, fieldValues)
-
- writeln("Reply was: %s" % str(fieldValues))
- ----------------------------------------------------------------------
-
- @arg msg: the msg to be displayed.
- @arg title: the window title
- @arg fields: a list of fieldnames.
- @arg values: a list of field values
- """
- return __multfillablebox(msg,title,fields,values,None)
-
-
-#-----------------------------------------------------------------------
-# multpasswordbox
-#-----------------------------------------------------------------------
-def multpasswordbox(msg="Fill in values for the fields."
- , title=" "
- , fields=tuple()
- ,values=tuple()
- ):
- r"""
- Same interface as multenterbox. But in multpassword box,
- the last of the fields is assumed to be a password, and
- is masked with asterisks.
-
- Example
- =======
-
- Here is some example code, that shows how values returned from
- multpasswordbox can be checked for validity before they are accepted::
- msg = "Enter logon information"
- title = "Demo of multpasswordbox"
- fieldNames = ["Server ID", "User ID", "Password"]
- fieldValues = [] # we start with blanks for the values
- fieldValues = multpasswordbox(msg,title, fieldNames)
-
- # make sure that none of the fields was left blank
- while 1:
- if fieldValues == None: break
- errmsg = ""
- for i in range(len(fieldNames)):
- if fieldValues[i].strip() == "":
- errmsg = errmsg + ('"%s" is a required field.\n\n' % fieldNames[i])
- if errmsg == "": break # no problems found
- fieldValues = multpasswordbox(errmsg, title, fieldNames, fieldValues)
-
- writeln("Reply was: %s" % str(fieldValues))
- """
- return __multfillablebox(msg,title,fields,values,"*")
-
-def bindArrows(widget):
- widget.bind("<Down>", tabRight)
- widget.bind("<Up>" , tabLeft)
-
- widget.bind("<Right>",tabRight)
- widget.bind("<Left>" , tabLeft)
-
-def tabRight(event):
- boxRoot.event_generate("<Tab>")
-
-def tabLeft(event):
- boxRoot.event_generate("<Shift-Tab>")
-
-#-----------------------------------------------------------------------
-# __multfillablebox
-#-----------------------------------------------------------------------
-def __multfillablebox(msg="Fill in values for the fields."
- , title=" "
- , fields=()
- , values=()
- , mask = None
- ):
- if sys.platform == 'darwin':
- _bring_to_front()
-
- global boxRoot, __multenterboxText, __multenterboxDefaultText, cancelButton, entryWidget, okButton
-
- choices = ["OK", "Cancel"]
- if len(fields) == 0: return None
-
- fields = list(fields[:]) # convert possible tuples to a list
- values = list(values[:]) # convert possible tuples to a list
-
- if len(values) == len(fields): pass
- elif len(values) > len(fields):
- fields = fields[0:len(values)]
- else:
- while len(values) < len(fields):
- values.append("")
-
- boxRoot = Tk()
-
- boxRoot.protocol('WM_DELETE_WINDOW', denyWindowManagerClose )
- boxRoot.title(title)
- boxRoot.iconname('Dialog')
- boxRoot.geometry(rootWindowPosition)
- boxRoot.bind("<Escape>", __multenterboxCancel)
-
- # -------------------- put subframes in the boxRoot --------------------
- messageFrame = Frame(master=boxRoot)
- messageFrame.pack(side=TOP, fill=BOTH)
-
- #-------------------- the msg widget ----------------------------
- messageWidget = Message(messageFrame, width="4.5i", text=msg)
- messageWidget.configure(font=(PROPORTIONAL_FONT_FAMILY,PROPORTIONAL_FONT_SIZE))
- messageWidget.pack(side=RIGHT, expand=1, fill=BOTH, padx='3m', pady='3m')
-
- global entryWidgets
- entryWidgets = []
-
- lastWidgetIndex = len(fields) - 1
-
- for widgetIndex in range(len(fields)):
- argFieldName = fields[widgetIndex]
- argFieldValue = values[widgetIndex]
- entryFrame = Frame(master=boxRoot)
- entryFrame.pack(side=TOP, fill=BOTH)
-
- # --------- entryWidget ----------------------------------------------
- labelWidget = Label(entryFrame, text=argFieldName)
- labelWidget.pack(side=LEFT)
-
- entryWidget = Entry(entryFrame, width=40,highlightthickness=2)
- entryWidgets.append(entryWidget)
- entryWidget.configure(font=(PROPORTIONAL_FONT_FAMILY,TEXT_ENTRY_FONT_SIZE))
- entryWidget.pack(side=RIGHT, padx="3m")
-
- bindArrows(entryWidget)
-
- entryWidget.bind("<Return>", __multenterboxGetText)
- entryWidget.bind("<Escape>", __multenterboxCancel)
-
- # for the last entryWidget, if this is a multpasswordbox,
- # show the contents as just asterisks
- if widgetIndex == lastWidgetIndex:
- if mask:
- entryWidgets[widgetIndex].configure(show=mask)
-
- # put text into the entryWidget
- entryWidgets[widgetIndex].insert(0,argFieldValue)
- widgetIndex += 1
-
- # ------------------ ok button -------------------------------
- buttonsFrame = Frame(master=boxRoot)
- buttonsFrame.pack(side=BOTTOM, fill=BOTH)
-
- okButton = Button(buttonsFrame, takefocus=1, text="OK")
- bindArrows(okButton)
- okButton.pack(expand=1, side=LEFT, padx='3m', pady='3m', ipadx='2m', ipady='1m')
-
- # for the commandButton, bind activation events to the activation event handler
- commandButton = okButton
- handler = __multenterboxGetText
- for selectionEvent in STANDARD_SELECTION_EVENTS:
- commandButton.bind("<%s>" % selectionEvent, handler)
-
-
- # ------------------ cancel button -------------------------------
- cancelButton = Button(buttonsFrame, takefocus=1, text="Cancel")
- bindArrows(cancelButton)
- cancelButton.pack(expand=1, side=RIGHT, padx='3m', pady='3m', ipadx='2m', ipady='1m')
-
- # for the commandButton, bind activation events to the activation event handler
- commandButton = cancelButton
- handler = __multenterboxCancel
- for selectionEvent in STANDARD_SELECTION_EVENTS:
- commandButton.bind("<%s>" % selectionEvent, handler)
-
-
- # ------------------- time for action! -----------------
- entryWidgets[0].focus_force() # put the focus on the entryWidget
- boxRoot.mainloop() # run it!
-
- # -------- after the run has completed ----------------------------------
- boxRoot.destroy() # button_click didn't destroy boxRoot, so we do it now
- return __multenterboxText
-
-
-#-----------------------------------------------------------------------
-# __multenterboxGetText
-#-----------------------------------------------------------------------
-def __multenterboxGetText(event):
- global __multenterboxText
-
- __multenterboxText = []
- for entryWidget in entryWidgets:
- __multenterboxText.append(entryWidget.get())
- boxRoot.quit()
-
-
-def __multenterboxCancel(event):
- global __multenterboxText
- __multenterboxText = None
- boxRoot.quit()
-
-
-#-------------------------------------------------------------------
-# enterbox
-#-------------------------------------------------------------------
-def enterbox(msg="Enter something."
- , title=" "
- , default=""
- , strip=True
- , image=None
- , root=None
- ):
- """
- Show a box in which a user can enter some text.
-
- You may optionally specify some default text, which will appear in the
- enterbox when it is displayed.
-
- Returns the text that the user entered, or None if he cancels the operation.
-
- By default, enterbox strips its result (i.e. removes leading and trailing
- whitespace). (If you want it not to strip, use keyword argument: strip=False.)
- This makes it easier to test the results of the call::
-
- reply = enterbox(....)
- if reply:
- ...
- else:
- ...
- """
- result = __fillablebox(msg, title, default=default, mask=None,image=image,root=root)
- if result and strip:
- result = result.strip()
- return result
-
-
-def passwordbox(msg="Enter your password."
- , title=" "
- , default=""
- , image=None
- , root=None
- ):
- """
- Show a box in which a user can enter a password.
- The text is masked with asterisks, so the password is not displayed.
- Returns the text that the user entered, or None if he cancels the operation.
- """
- return __fillablebox(msg, title, default, mask="*",image=image,root=root)
-
-
-def __fillablebox(msg
- , title=""
- , default=""
- , mask=None
- , image=None
- , root=None
- ):
- """
- Show a box in which a user can enter some text.
- You may optionally specify some default text, which will appear in the
- enterbox when it is displayed.
- Returns the text that the user entered, or None if he cancels the operation.
- """
- if sys.platform == 'darwin':
- _bring_to_front()
- global boxRoot, __enterboxText, __enterboxDefaultText
- global cancelButton, entryWidget, okButton
-
- if title is None:
- title = ""
- if default is None:
- default = ""
- __enterboxDefaultText = default
- __enterboxText = __enterboxDefaultText
-
- if root:
- root.withdraw()
- boxRoot = Toplevel(master=root)
- boxRoot.withdraw()
- else:
- boxRoot = Tk()
- boxRoot.withdraw()
-
- boxRoot.protocol('WM_DELETE_WINDOW', denyWindowManagerClose )
- boxRoot.title(title)
- boxRoot.iconname('Dialog')
- boxRoot.geometry(rootWindowPosition)
- boxRoot.bind("<Escape>", __enterboxCancel)
-
- # ------------- define the messageFrame ---------------------------------
- messageFrame = Frame(master=boxRoot)
- messageFrame.pack(side=TOP, fill=BOTH)
-
- # ------------- define the imageFrame ---------------------------------
- tk_Image = None
- if image:
- imageFilename = os.path.normpath(image)
- junk,ext = os.path.splitext(imageFilename)
-
- if os.path.exists(imageFilename):
- if ext.lower() in [".gif", ".pgm", ".ppm"]:
- tk_Image = PhotoImage(master=boxRoot, file=imageFilename)
- else:
- if PILisLoaded:
- try:
- pil_Image = PILImage.open(imageFilename)
- tk_Image = PILImageTk.PhotoImage(pil_Image, master=boxRoot)
- except:
- msg += ImageErrorMsg % (imageFilename,
- "\nThe Python Imaging Library (PIL) could not convert this file to a displayable image."
- "\n\nPIL reports:\n" + exception_format())
-
- else: # PIL is not loaded
- msg += ImageErrorMsg % (imageFilename,
- "\nI could not import the Python Imaging Library (PIL) to display the image.\n\n"
- "You may need to install PIL\n"
- "(http://www.pythonware.com/products/pil/)\n"
- "to display " + ext + " image files.")
-
- else:
- msg += ImageErrorMsg % (imageFilename, "\nImage file not found.")
-
- if tk_Image:
- imageFrame = Frame(master=boxRoot)
- imageFrame.pack(side=TOP, fill=BOTH)
- label = Label(imageFrame,image=tk_Image)
- label.image = tk_Image # keep a reference!
- label.pack(side=TOP, expand=YES, fill=X, padx='1m', pady='1m')
-
- # ------------- define the buttonsFrame ---------------------------------
- buttonsFrame = Frame(master=boxRoot)
- buttonsFrame.pack(side=TOP, fill=BOTH)
-
-
- # ------------- define the entryFrame ---------------------------------
- entryFrame = Frame(master=boxRoot)
- entryFrame.pack(side=TOP, fill=BOTH)
-
- # ------------- define the buttonsFrame ---------------------------------
- buttonsFrame = Frame(master=boxRoot)
- buttonsFrame.pack(side=TOP, fill=BOTH)
-
- #-------------------- the msg widget ----------------------------
- messageWidget = Message(messageFrame, width="4.5i", text=msg)
- messageWidget.configure(font=(PROPORTIONAL_FONT_FAMILY,PROPORTIONAL_FONT_SIZE))
- messageWidget.pack(side=RIGHT, expand=1, fill=BOTH, padx='3m', pady='3m')
-
- # --------- entryWidget ----------------------------------------------
- entryWidget = Entry(entryFrame, width=40)
- bindArrows(entryWidget)
- entryWidget.configure(font=(PROPORTIONAL_FONT_FAMILY,TEXT_ENTRY_FONT_SIZE))
- if mask:
- entryWidget.configure(show=mask)
- entryWidget.pack(side=LEFT, padx="3m")
- entryWidget.bind("<Return>", __enterboxGetText)
- entryWidget.bind("<Escape>", __enterboxCancel)
- # put text into the entryWidget
- entryWidget.insert(0,__enterboxDefaultText)
-
- # ------------------ ok button -------------------------------
- okButton = Button(buttonsFrame, takefocus=1, text="OK")
- bindArrows(okButton)
- okButton.pack(expand=1, side=LEFT, padx='3m', pady='3m', ipadx='2m', ipady='1m')
-
- # for the commandButton, bind activation events to the activation event handler
- commandButton = okButton
- handler = __enterboxGetText
- for selectionEvent in STANDARD_SELECTION_EVENTS:
- commandButton.bind("<%s>" % selectionEvent, handler)
-
-
- # ------------------ cancel button -------------------------------
- cancelButton = Button(buttonsFrame, takefocus=1, text="Cancel")
- bindArrows(cancelButton)
- cancelButton.pack(expand=1, side=RIGHT, padx='3m', pady='3m', ipadx='2m', ipady='1m')
-
- # for the commandButton, bind activation events to the activation event handler
- commandButton = cancelButton
- handler = __enterboxCancel
- for selectionEvent in STANDARD_SELECTION_EVENTS:
- commandButton.bind("<%s>" % selectionEvent, handler)
-
- # ------------------- time for action! -----------------
- entryWidget.focus_force() # put the focus on the entryWidget
- boxRoot.deiconify()
- boxRoot.mainloop() # run it!
-
- # -------- after the run has completed ----------------------------------
- if root: root.deiconify()
- boxRoot.destroy() # button_click didn't destroy boxRoot, so we do it now
- return __enterboxText
-
-
-def __enterboxGetText(event):
- global __enterboxText
-
- __enterboxText = entryWidget.get()
- boxRoot.quit()
-
-
-def __enterboxRestore(event):
- global entryWidget
-
- entryWidget.delete(0,len(entryWidget.get()))
- entryWidget.insert(0, __enterboxDefaultText)
-
-
-def __enterboxCancel(event):
- global __enterboxText
-
- __enterboxText = None
- boxRoot.quit()
-
-def denyWindowManagerClose():
- """ don't allow WindowManager close
- """
- x = Tk()
- x.withdraw()
- x.bell()
- x.destroy()
-
-
-
-#-------------------------------------------------------------------
-# multchoicebox
-#-------------------------------------------------------------------
-def multchoicebox(msg="Pick as many items as you like."
- , title=" "
- , choices=()
- , **kwargs
- ):
- """
- Present the user with a list of choices.
- allow him to select multiple items and return them in a list.
- if the user doesn't choose anything from the list, return the empty list.
- return None if he cancelled selection.
-
- @arg msg: the msg to be displayed.
- @arg title: the window title
- @arg choices: a list or tuple of the choices to be displayed
- """
- if len(choices) == 0: choices = ["Program logic error - no choices were specified."]
-
- global __choiceboxMultipleSelect
- __choiceboxMultipleSelect = 1
- return __choicebox(msg, title, choices)
-
-
-#-----------------------------------------------------------------------
-# choicebox
-#-----------------------------------------------------------------------
-def choicebox(msg="Pick something."
- , title=" "
- , choices=()
- ):
- """
- Present the user with a list of choices.
- return the choice that he selects.
- return None if he cancels the selection selection.
-
- @arg msg: the msg to be displayed.
- @arg title: the window title
- @arg choices: a list or tuple of the choices to be displayed
- """
- if len(choices) == 0: choices = ["Program logic error - no choices were specified."]
-
- global __choiceboxMultipleSelect
- __choiceboxMultipleSelect = 0
- return __choicebox(msg,title,choices)
-
-
-#-----------------------------------------------------------------------
-# __choicebox
-#-----------------------------------------------------------------------
-def __choicebox(msg
- , title
- , choices
- ):
- """
- internal routine to support choicebox() and multchoicebox()
- """
- if sys.platform == 'darwin':
- _bring_to_front()
- global boxRoot, __choiceboxResults, choiceboxWidget, defaultText
- global choiceboxWidget, choiceboxChoices
- #-------------------------------------------------------------------
- # If choices is a tuple, we make it a list so we can sort it.
- # If choices is already a list, we make a new list, so that when
- # we sort the choices, we don't affect the list object that we
- # were given.
- #-------------------------------------------------------------------
- choices = list(choices[:])
- if len(choices) == 0:
- choices = ["Program logic error - no choices were specified."]
- defaultButtons = ["OK", "Cancel"]
-
- # make sure all choices are strings
- for index in range(len(choices)):
- choices[index] = str(choices[index])
-
- lines_to_show = min(len(choices), 20)
- lines_to_show = 20
-
- if title is None:
- title = ""
-
- # Initialize __choiceboxResults
- # This is the value that will be returned if the user clicks the close icon
- __choiceboxResults = None
-
- boxRoot = Tk()
- boxRoot.protocol('WM_DELETE_WINDOW', denyWindowManagerClose )
- screen_width = boxRoot.winfo_screenwidth()
- screen_height = boxRoot.winfo_screenheight()
- root_width = int((screen_width * 0.8))
- root_height = int((screen_height * 0.5))
- root_xpos = int((screen_width * 0.1))
- root_ypos = int((screen_height * 0.05))
-
- boxRoot.title(title)
- boxRoot.iconname('Dialog')
- rootWindowPosition = "+0+0"
- boxRoot.geometry(rootWindowPosition)
- boxRoot.expand=NO
- boxRoot.minsize(root_width, root_height)
- rootWindowPosition = "+" + str(root_xpos) + "+" + str(root_ypos)
- boxRoot.geometry(rootWindowPosition)
-
- # ---------------- put the frames in the window -----------------------------------------
- message_and_buttonsFrame = Frame(master=boxRoot)
- message_and_buttonsFrame.pack(side=TOP, fill=X, expand=NO)
-
- messageFrame = Frame(message_and_buttonsFrame)
- messageFrame.pack(side=LEFT, fill=X, expand=YES)
- #messageFrame.pack(side=TOP, fill=X, expand=YES)
-
- buttonsFrame = Frame(message_and_buttonsFrame)
- buttonsFrame.pack(side=RIGHT, expand=NO, pady=0)
- #buttonsFrame.pack(side=TOP, expand=YES, pady=0)
-
- choiceboxFrame = Frame(master=boxRoot)
- choiceboxFrame.pack(side=BOTTOM, fill=BOTH, expand=YES)
-
- # -------------------------- put the widgets in the frames ------------------------------
-
- # ---------- put a msg widget in the msg frame-------------------
- messageWidget = Message(messageFrame, anchor=NW, text=msg, width=int(root_width * 0.9))
- messageWidget.configure(font=(PROPORTIONAL_FONT_FAMILY,PROPORTIONAL_FONT_SIZE))
- messageWidget.pack(side=LEFT, expand=YES, fill=BOTH, padx='1m', pady='1m')
-
- # -------- put the choiceboxWidget in the choiceboxFrame ---------------------------
- choiceboxWidget = Listbox(choiceboxFrame
- , height=lines_to_show
- , borderwidth="1m"
- , relief="flat"
- , bg="white"
- )
-
- if __choiceboxMultipleSelect:
- choiceboxWidget.configure(selectmode=MULTIPLE)
-
- choiceboxWidget.configure(font=(PROPORTIONAL_FONT_FAMILY,PROPORTIONAL_FONT_SIZE))
-
- # add a vertical scrollbar to the frame
- rightScrollbar = Scrollbar(choiceboxFrame, orient=VERTICAL, command=choiceboxWidget.yview)
- choiceboxWidget.configure(yscrollcommand = rightScrollbar.set)
-
- # add a horizontal scrollbar to the frame
- bottomScrollbar = Scrollbar(choiceboxFrame, orient=HORIZONTAL, command=choiceboxWidget.xview)
- choiceboxWidget.configure(xscrollcommand = bottomScrollbar.set)
-
- # pack the Listbox and the scrollbars. Note that although we must define
- # the textArea first, we must pack it last, so that the bottomScrollbar will
- # be located properly.
-
- bottomScrollbar.pack(side=BOTTOM, fill = X)
- rightScrollbar.pack(side=RIGHT, fill = Y)
-
- choiceboxWidget.pack(side=LEFT, padx="1m", pady="1m", expand=YES, fill=BOTH)
-
- #---------------------------------------------------
- # sort the choices
- # eliminate duplicates
- # put the choices into the choiceboxWidget
- #---------------------------------------------------
- for index in range(len(choices)):
- choices[index] = str(choices[index])
-
- if runningPython3:
- choices.sort(key=str.lower)
- else:
- choices.sort( lambda x,y: cmp(x.lower(), y.lower())) # case-insensitive sort
-
- lastInserted = None
- choiceboxChoices = []
- for choice in choices:
- if choice == lastInserted: pass
- else:
- choiceboxWidget.insert(END, choice)
- choiceboxChoices.append(choice)
- lastInserted = choice
-
- boxRoot.bind('<Any-Key>', KeyboardListener)
-
- # put the buttons in the buttonsFrame
- if len(choices) > 0:
- okButton = Button(buttonsFrame, takefocus=YES, text="OK", height=1, width=6)
- bindArrows(okButton)
- okButton.pack(expand=NO, side=TOP, padx='2m', pady='1m', ipady="1m", ipadx="2m")
-
- # for the commandButton, bind activation events to the activation event handler
- commandButton = okButton
- handler = __choiceboxGetChoice
- for selectionEvent in STANDARD_SELECTION_EVENTS:
- commandButton.bind("<%s>" % selectionEvent, handler)
-
- # now bind the keyboard events
- choiceboxWidget.bind("<Return>", __choiceboxGetChoice)
- choiceboxWidget.bind("<Double-Button-1>", __choiceboxGetChoice)
- else:
- # now bind the keyboard events
- choiceboxWidget.bind("<Return>", __choiceboxCancel)
- choiceboxWidget.bind("<Double-Button-1>", __choiceboxCancel)
-
- cancelButton = Button(buttonsFrame, takefocus=YES, text="Cancel", height=1, width=6)
- bindArrows(cancelButton)
- cancelButton.pack(expand=NO, side=BOTTOM, padx='2m', pady='1m', ipady="1m", ipadx="2m")
-
- # for the commandButton, bind activation events to the activation event handler
- commandButton = cancelButton
- handler = __choiceboxCancel
- for selectionEvent in STANDARD_SELECTION_EVENTS:
- commandButton.bind("<%s>" % selectionEvent, handler)
-
-
- # add special buttons for multiple select features
- if len(choices) > 0 and __choiceboxMultipleSelect:
- selectionButtonsFrame = Frame(messageFrame)
- selectionButtonsFrame.pack(side=RIGHT, fill=Y, expand=NO)
-
- selectAllButton = Button(selectionButtonsFrame, text="Select All", height=1, width=6)
- bindArrows(selectAllButton)
-
- selectAllButton.bind("<Button-1>",__choiceboxSelectAll)
- selectAllButton.pack(expand=NO, side=TOP, padx='2m', pady='1m', ipady="1m", ipadx="2m")
-
- clearAllButton = Button(selectionButtonsFrame, text="Clear All", height=1, width=6)
- bindArrows(clearAllButton)
- clearAllButton.bind("<Button-1>",__choiceboxClearAll)
- clearAllButton.pack(expand=NO, side=TOP, padx='2m', pady='1m', ipady="1m", ipadx="2m")
-
-
- # -------------------- bind some keyboard events ----------------------------
- boxRoot.bind("<Escape>", __choiceboxCancel)
-
- # --------------------- the action begins -----------------------------------
- # put the focus on the choiceboxWidget, and the select highlight on the first item
- choiceboxWidget.select_set(0)
- choiceboxWidget.focus_force()
-
- # --- run it! -----
- boxRoot.mainloop()
-
- boxRoot.destroy()
- return __choiceboxResults
-
-
-def __choiceboxGetChoice(event):
- global boxRoot, __choiceboxResults, choiceboxWidget
-
- if __choiceboxMultipleSelect:
- __choiceboxResults = [choiceboxWidget.get(index) for index in choiceboxWidget.curselection()]
-
- else:
- choice_index = choiceboxWidget.curselection()
- __choiceboxResults = choiceboxWidget.get(choice_index)
-
- # writeln("Debugging> mouse-event=", event, " event.type=", event.type)
- # writeln("Debugging> choice=", choice_index, __choiceboxResults)
- boxRoot.quit()
-
-
-def __choiceboxSelectAll(event):
- global choiceboxWidget, choiceboxChoices
-
- choiceboxWidget.selection_set(0, len(choiceboxChoices)-1)
-
-def __choiceboxClearAll(event):
- global choiceboxWidget, choiceboxChoices
-
- choiceboxWidget.selection_clear(0, len(choiceboxChoices)-1)
-
-
-
-def __choiceboxCancel(event):
- global boxRoot, __choiceboxResults
-
- __choiceboxResults = None
- boxRoot.quit()
-
-
-def KeyboardListener(event):
- global choiceboxChoices, choiceboxWidget
- key = event.keysym
- if len(key) <= 1:
- if key in string.printable:
- # Find the key in the list.
- # before we clear the list, remember the selected member
- try:
- start_n = int(choiceboxWidget.curselection()[0])
- except IndexError:
- start_n = -1
-
- ## clear the selection.
- choiceboxWidget.selection_clear(0, 'end')
-
- ## start from previous selection +1
- for n in range(start_n+1, len(choiceboxChoices)):
- item = choiceboxChoices[n]
- if item[0].lower() == key.lower():
- choiceboxWidget.selection_set(first=n)
- choiceboxWidget.see(n)
- return
- else:
- # has not found it so loop from top
- for n in range(len(choiceboxChoices)):
- item = choiceboxChoices[n]
- if item[0].lower() == key.lower():
- choiceboxWidget.selection_set(first = n)
- choiceboxWidget.see(n)
- return
-
- # nothing matched -- we'll look for the next logical choice
- for n in range(len(choiceboxChoices)):
- item = choiceboxChoices[n]
- if item[0].lower() > key.lower():
- if n > 0:
- choiceboxWidget.selection_set(first = (n-1))
- else:
- choiceboxWidget.selection_set(first = 0)
- choiceboxWidget.see(n)
- return
-
- # still no match (nothing was greater than the key)
- # we set the selection to the first item in the list
- lastIndex = len(choiceboxChoices)-1
- choiceboxWidget.selection_set(first = lastIndex)
- choiceboxWidget.see(lastIndex)
- return
-
-#-----------------------------------------------------------------------
-# exception_format
-#-----------------------------------------------------------------------
-def exception_format():
- """
- Convert exception info into a string suitable for display.
- """
- return "".join(traceback.format_exception(
- sys.exc_info()[0]
- , sys.exc_info()[1]
- , sys.exc_info()[2]
- ))
-
-#-----------------------------------------------------------------------
-# exceptionbox
-#-----------------------------------------------------------------------
-def exceptionbox(msg=None, title=None):
- """
- Display a box that gives information about
- an exception that has just been raised.
-
- The caller may optionally pass in a title for the window, or a
- msg to accompany the error information.
-
- Note that you do not need to (and cannot) pass an exception object
- as an argument. The latest exception will automatically be used.
- """
- if title is None:
- title = "Error Report"
- if msg is None:
- msg = "An error (exception) has occurred in the program."
-
- codebox(msg, title, exception_format())
-
-#-------------------------------------------------------------------
-# codebox
-#-------------------------------------------------------------------
-
-def codebox(msg=""
- , title=" "
- , text=""
- ):
- """
- Display some text in a monospaced font, with no line wrapping.
- This function is suitable for displaying code and text that is
- formatted using spaces.
-
- The text parameter should be a string, or a list or tuple of lines to be
- displayed in the textbox.
- """
- return textbox(msg, title, text, codebox=1 )
-
-#-------------------------------------------------------------------
-# textbox
-#-------------------------------------------------------------------
-def textbox(msg=""
- , title=" "
- , text=""
- , codebox=0
- ):
- """
- Display some text in a proportional font with line wrapping at word breaks.
- This function is suitable for displaying general written text.
-
- The text parameter should be a string, or a list or tuple of lines to be
- displayed in the textbox.
- """
- if sys.platform == 'darwin':
- _bring_to_front()
- if msg is None:
- msg = ""
- if title is None:
- title = ""
-
- global boxRoot, __replyButtonText, __widgetTexts, buttonsFrame
- global rootWindowPosition
- choices = ["OK"]
- __replyButtonText = choices[0]
-
-
- boxRoot = Tk()
-
- boxRoot.protocol('WM_DELETE_WINDOW', denyWindowManagerClose )
-
- screen_width = boxRoot.winfo_screenwidth()
- screen_height = boxRoot.winfo_screenheight()
- root_width = int((screen_width * 0.8))
- root_height = int((screen_height * 0.5))
- root_xpos = int((screen_width * 0.1))
- root_ypos = int((screen_height * 0.05))
-
- boxRoot.title(title)
- boxRoot.iconname('Dialog')
- rootWindowPosition = "+0+0"
- boxRoot.geometry(rootWindowPosition)
- boxRoot.expand=NO
- boxRoot.minsize(root_width, root_height)
- rootWindowPosition = "+" + str(root_xpos) + "+" + str(root_ypos)
- boxRoot.geometry(rootWindowPosition)
-
- mainframe = Frame(master=boxRoot)
- mainframe.pack(side=TOP, fill=BOTH, expand=YES)
-
- # ---- put frames in the window -----------------------------------
- # we pack the textboxFrame first, so it will expand first
- textboxFrame = Frame(mainframe, borderwidth=3)
- textboxFrame.pack(side=BOTTOM , fill=BOTH, expand=YES)
-
- message_and_buttonsFrame = Frame(mainframe)
- message_and_buttonsFrame.pack(side=TOP, fill=X, expand=NO)
-
- messageFrame = Frame(message_and_buttonsFrame)
- messageFrame.pack(side=LEFT, fill=X, expand=YES)
-
- buttonsFrame = Frame(message_and_buttonsFrame)
- buttonsFrame.pack(side=RIGHT, expand=NO)
-
- # -------------------- put widgets in the frames --------------------
-
- # put a textArea in the top frame
- if codebox:
- character_width = int((root_width * 0.6) / MONOSPACE_FONT_SIZE)
- textArea = Text(textboxFrame,height=25,width=character_width, padx="2m", pady="1m")
- textArea.configure(wrap=NONE)
- textArea.configure(font=(MONOSPACE_FONT_FAMILY, MONOSPACE_FONT_SIZE))
-
- else:
- character_width = int((root_width * 0.6) / MONOSPACE_FONT_SIZE)
- textArea = Text(
- textboxFrame
- , height=25
- , width=character_width
- , padx="2m"
- , pady="1m"
- )
- textArea.configure(wrap=WORD)
- textArea.configure(font=(PROPORTIONAL_FONT_FAMILY,PROPORTIONAL_FONT_SIZE))
-
-
- # some simple keybindings for scrolling
- mainframe.bind("<Next>" , textArea.yview_scroll( 1,PAGES))
- mainframe.bind("<Prior>", textArea.yview_scroll(-1,PAGES))
-
- mainframe.bind("<Right>", textArea.xview_scroll( 1,PAGES))
- mainframe.bind("<Left>" , textArea.xview_scroll(-1,PAGES))
-
- mainframe.bind("<Down>", textArea.yview_scroll( 1,UNITS))
- mainframe.bind("<Up>" , textArea.yview_scroll(-1,UNITS))
-
-
- # add a vertical scrollbar to the frame
- rightScrollbar = Scrollbar(textboxFrame, orient=VERTICAL, command=textArea.yview)
- textArea.configure(yscrollcommand = rightScrollbar.set)
-
- # add a horizontal scrollbar to the frame
- bottomScrollbar = Scrollbar(textboxFrame, orient=HORIZONTAL, command=textArea.xview)
- textArea.configure(xscrollcommand = bottomScrollbar.set)
-
- # pack the textArea and the scrollbars. Note that although we must define
- # the textArea first, we must pack it last, so that the bottomScrollbar will
- # be located properly.
-
- # Note that we need a bottom scrollbar only for code.
- # Text will be displayed with wordwrap, so we don't need to have a horizontal
- # scroll for it.
- if codebox:
- bottomScrollbar.pack(side=BOTTOM, fill=X)
- rightScrollbar.pack(side=RIGHT, fill=Y)
-
- textArea.pack(side=LEFT, fill=BOTH, expand=YES)
-
-
- # ---------- put a msg widget in the msg frame-------------------
- messageWidget = Message(messageFrame, anchor=NW, text=msg, width=int(root_width * 0.9))
- messageWidget.configure(font=(PROPORTIONAL_FONT_FAMILY,PROPORTIONAL_FONT_SIZE))
- messageWidget.pack(side=LEFT, expand=YES, fill=BOTH, padx='1m', pady='1m')
-
- # put the buttons in the buttonsFrame
- okButton = Button(buttonsFrame, takefocus=YES, text="OK", height=1, width=6)
- okButton.pack(expand=NO, side=TOP, padx='2m', pady='1m', ipady="1m", ipadx="2m")
-
- # for the commandButton, bind activation events to the activation event handler
- commandButton = okButton
- handler = __textboxOK
- for selectionEvent in ["Return","Button-1","Escape"]:
- commandButton.bind("<%s>" % selectionEvent, handler)
-
-
- # ----------------- the action begins ----------------------------------------
- try:
- # load the text into the textArea
- if type(text) == type("abc"): pass
- else:
- try:
- text = "".join(text) # convert a list or a tuple to a string
- except:
- msgbox("Exception when trying to convert "+ str(type(text)) + " to text in textArea")
- sys.exit(16)
- textArea.insert(END,text, "normal")
-
- except:
- msgbox("Exception when trying to load the textArea.")
- sys.exit(16)
-
- try:
- okButton.focus_force()
- except:
- msgbox("Exception when trying to put focus on okButton.")
- sys.exit(16)
-
- boxRoot.mainloop()
-
- # this line MUST go before the line that destroys boxRoot
- areaText = textArea.get(0.0,END)
- boxRoot.destroy()
- return areaText # return __replyButtonText
-
-#-------------------------------------------------------------------
-# __textboxOK
-#-------------------------------------------------------------------
-def __textboxOK(event):
- global boxRoot
- boxRoot.quit()
-
-
-
-#-------------------------------------------------------------------
-# diropenbox
-#-------------------------------------------------------------------
-def diropenbox(msg=None
- , title=None
- , default=None
- ):
- """
- A dialog to get a directory name.
- Note that the msg argument, if specified, is ignored.
-
- Returns the name of a directory, or None if user chose to cancel.
-
- If the "default" argument specifies a directory name, and that
- directory exists, then the dialog box will start with that directory.
- """
- if sys.platform == 'darwin':
- _bring_to_front()
- title=getFileDialogTitle(msg,title)
- localRoot = Tk()
- localRoot.withdraw()
- if not default: default = None
- f = tk_FileDialog.askdirectory(
- parent=localRoot
- , title=title
- , initialdir=default
- , initialfile=None
- )
- localRoot.destroy()
- if not f: return None
- return os.path.normpath(f)
-
-
-
-#-------------------------------------------------------------------
-# getFileDialogTitle
-#-------------------------------------------------------------------
-def getFileDialogTitle(msg
- , title
- ):
- if msg and title: return "%s - %s" % (title,msg)
- if msg and not title: return str(msg)
- if title and not msg: return str(title)
- return None # no message and no title
-
-#-------------------------------------------------------------------
-# class FileTypeObject for use with fileopenbox
-#-------------------------------------------------------------------
-class FileTypeObject:
- def __init__(self,filemask):
- if len(filemask) == 0:
- raise AssertionError('Filetype argument is empty.')
-
- self.masks = []
-
- if type(filemask) == type("abc"): # a string
- self.initializeFromString(filemask)
-
- elif type(filemask) == type([]): # a list
- if len(filemask) < 2:
- raise AssertionError('Invalid filemask.\n'
- +'List contains less than 2 members: "%s"' % filemask)
- else:
- self.name = filemask[-1]
- self.masks = list(filemask[:-1] )
- else:
- raise AssertionError('Invalid filemask: "%s"' % filemask)
-
- def __eq__(self,other):
- if self.name == other.name: return True
- return False
-
- def add(self,other):
- for mask in other.masks:
- if mask in self.masks: pass
- else: self.masks.append(mask)
-
- def toTuple(self):
- return (self.name,tuple(self.masks))
-
- def isAll(self):
- if self.name == "All files": return True
- return False
-
- def initializeFromString(self, filemask):
- # remove everything except the extension from the filemask
- self.ext = os.path.splitext(filemask)[1]
- if self.ext == "" : self.ext = ".*"
- if self.ext == ".": self.ext = ".*"
- self.name = self.getName()
- self.masks = ["*" + self.ext]
-
- def getName(self):
- e = self.ext
- if e == ".*" : return "All files"
- if e == ".txt": return "Text files"
- if e == ".py" : return "Python files"
- if e == ".pyc" : return "Python files"
- if e == ".xls": return "Excel files"
- if e.startswith("."):
- return e[1:].upper() + " files"
- return e.upper() + " files"
-
-
-#-------------------------------------------------------------------
-# fileopenbox
-#-------------------------------------------------------------------
-def fileopenbox(msg=None
- , title=None
- , default="*"
- , filetypes=None
- ):
- """
- A dialog to get a file name.
-
- About the "default" argument
- ============================
- The "default" argument specifies a filepath that (normally)
- contains one or more wildcards.
- fileopenbox will display only files that match the default filepath.
- If omitted, defaults to "*" (all files in the current directory).
-
- WINDOWS EXAMPLE::
- ...default="c:/myjunk/*.py"
- will open in directory c:\myjunk\ and show all Python files.
-
- WINDOWS EXAMPLE::
- ...default="c:/myjunk/test*.py"
- will open in directory c:\myjunk\ and show all Python files
- whose names begin with "test".
-
-
- Note that on Windows, fileopenbox automatically changes the path
- separator to the Windows path separator (backslash).
-
- About the "filetypes" argument
- ==============================
- If specified, it should contain a list of items,
- where each item is either::
- - a string containing a filemask # e.g. "*.txt"
- - a list of strings, where all of the strings except the last one
- are filemasks (each beginning with "*.",
- such as "*.txt" for text files, "*.py" for Python files, etc.).
- and the last string contains a filetype description
-
- EXAMPLE::
- filetypes = ["*.css", ["*.htm", "*.html", "HTML files"] ]
-
- NOTE THAT
- =========
-
- If the filetypes list does not contain ("All files","*"),
- it will be added.
-
- If the filetypes list does not contain a filemask that includes
- the extension of the "default" argument, it will be added.
- For example, if default="*abc.py"
- and no filetypes argument was specified, then
- "*.py" will automatically be added to the filetypes argument.
-
- @rtype: string or None
- @return: the name of a file, or None if user chose to cancel
-
- @arg msg: the msg to be displayed.
- @arg title: the window title
- @arg default: filepath with wildcards
- @arg filetypes: filemasks that a user can choose, e.g. "*.txt"
- """
- if sys.platform == 'darwin':
- _bring_to_front()
- localRoot = Tk()
- localRoot.withdraw()
-
- initialbase, initialfile, initialdir, filetypes = fileboxSetup(default,filetypes)
-
- #------------------------------------------------------------
- # if initialfile contains no wildcards; we don't want an
- # initial file. It won't be used anyway.
- # Also: if initialbase is simply "*", we don't want an
- # initialfile; it is not doing any useful work.
- #------------------------------------------------------------
- if (initialfile.find("*") < 0) and (initialfile.find("?") < 0):
- initialfile = None
- elif initialbase == "*":
- initialfile = None
-
- f = tk_FileDialog.askopenfilename(parent=localRoot
- , title=getFileDialogTitle(msg,title)
- , initialdir=initialdir
- , initialfile=initialfile
- , filetypes=filetypes
- )
-
- localRoot.destroy()
-
- if not f: return None
- return os.path.normpath(f)
-
-
-#-------------------------------------------------------------------
-# filesavebox
-#-------------------------------------------------------------------
-def filesavebox(msg=None
- , title=None
- , default=""
- , filetypes=None
- ):
- """
- A file to get the name of a file to save.
- Returns the name of a file, or None if user chose to cancel.
-
- The "default" argument should contain a filename (i.e. the
- current name of the file to be saved). It may also be empty,
- or contain a filemask that includes wildcards.
-
- The "filetypes" argument works like the "filetypes" argument to
- fileopenbox.
- """
- if sys.platform == 'darwin':
- _bring_to_front()
- localRoot = Tk()
- localRoot.withdraw()
-
- initialbase, initialfile, initialdir, filetypes = fileboxSetup(default,filetypes)
-
- f = tk_FileDialog.asksaveasfilename(parent=localRoot
- , title=getFileDialogTitle(msg,title)
- , initialfile=initialfile
- , initialdir=initialdir
- , filetypes=filetypes
- )
- localRoot.destroy()
- if not f: return None
- return os.path.normpath(f)
-
-
-#-------------------------------------------------------------------
-#
-# fileboxSetup
-#
-#-------------------------------------------------------------------
-def fileboxSetup(default,filetypes):
- if not default: default = os.path.join(".","*")
- initialdir, initialfile = os.path.split(default)
- if not initialdir : initialdir = "."
- if not initialfile: initialfile = "*"
- initialbase, initialext = os.path.splitext(initialfile)
- initialFileTypeObject = FileTypeObject(initialfile)
-
- allFileTypeObject = FileTypeObject("*")
- ALL_filetypes_was_specified = False
-
- if not filetypes: filetypes= []
- filetypeObjects = []
-
- for filemask in filetypes:
- fto = FileTypeObject(filemask)
-
- if fto.isAll():
- ALL_filetypes_was_specified = True # remember this
-
- if fto == initialFileTypeObject:
- initialFileTypeObject.add(fto) # add fto to initialFileTypeObject
- else:
- filetypeObjects.append(fto)
-
- #------------------------------------------------------------------
- # make sure that the list of filetypes includes the ALL FILES type.
- #------------------------------------------------------------------
- if ALL_filetypes_was_specified:
- pass
- elif allFileTypeObject == initialFileTypeObject:
- pass
- else:
- filetypeObjects.insert(0,allFileTypeObject)
- #------------------------------------------------------------------
- # Make sure that the list includes the initialFileTypeObject
- # in the position in the list that will make it the default.
- # This changed between Python version 2.5 and 2.6
- #------------------------------------------------------------------
- if len(filetypeObjects) == 0:
- filetypeObjects.append(initialFileTypeObject)
-
- if initialFileTypeObject in (filetypeObjects[0], filetypeObjects[-1]):
- pass
- else:
- if runningPython26:
- filetypeObjects.append(initialFileTypeObject)
- else:
- filetypeObjects.insert(0,initialFileTypeObject)
-
- filetypes = [fto.toTuple() for fto in filetypeObjects]
-
- return initialbase, initialfile, initialdir, filetypes
-
-#-------------------------------------------------------------------
-# utility routines
-#-------------------------------------------------------------------
-# These routines are used by several other functions in the EasyGui module.
-
-def __buttonEvent(event):
- """
- Handle an event that is generated by a person clicking a button.
- """
- global boxRoot, __widgetTexts, __replyButtonText
- __replyButtonText = __widgetTexts[event.widget]
- boxRoot.quit() # quit the main loop
-
-
-def __put_buttons_in_buttonframe(choices):
- """Put the buttons in the buttons frame
- """
- global __widgetTexts, __firstWidget, buttonsFrame
-
- __firstWidget = None
- __widgetTexts = {}
-
- i = 0
-
- for buttonText in choices:
- tempButton = Button(buttonsFrame, takefocus=1, text=buttonText)
- bindArrows(tempButton)
- tempButton.pack(expand=YES, side=LEFT, padx='1m', pady='1m', ipadx='2m', ipady='1m')
-
- # remember the text associated with this widget
- __widgetTexts[tempButton] = buttonText
-
- # remember the first widget, so we can put the focus there
- if i == 0:
- __firstWidget = tempButton
- i = 1
-
- # for the commandButton, bind activation events to the activation event handler
- commandButton = tempButton
- handler = __buttonEvent
- for selectionEvent in STANDARD_SELECTION_EVENTS:
- commandButton.bind("<%s>" % selectionEvent, handler)
-
-##-----------------------------------------------------------------------
-##
-## class EgStore
-##
-##-----------------------------------------------------------------------
-#class EgStore:
-# r"""
-#A class to support persistent storage.
-#
-#You can use EgStore to support the storage and retrieval
-#of user settings for an EasyGui application.
-#
-#
-## Example A
-##-----------------------------------------------------------------------
-## define a class named Settings as a subclass of EgStore
-##-----------------------------------------------------------------------
-#class Settings(EgStore):
-#::
-# def __init__(self, filename): # filename is required
-# #-------------------------------------------------
-# # Specify default/initial values for variables that
-# # this particular application wants to remember.
-# #-------------------------------------------------
-# self.userId = ""
-# self.targetServer = ""
-#
-# #-------------------------------------------------
-# # For subclasses of EgStore, these must be
-# # the last two statements in __init__
-# #-------------------------------------------------
-# self.filename = filename # this is required
-# self.restore() # restore values from the storage file if possible
-#
-#
-#
-## Example B
-##-----------------------------------------------------------------------
-## create settings, a persistent Settings object
-##-----------------------------------------------------------------------
-#settingsFile = "myApp_settings.txt"
-#settings = Settings(settingsFile)
-#
-#user = "obama_barak"
-#server = "whitehouse1"
-#settings.userId = user
-#settings.targetServer = server
-#settings.store() # persist the settings
-#
-## run code that gets a new value for userId, and persist the settings
-#user = "biden_joe"
-#settings.userId = user
-#settings.store()
-#
-#
-## Example C
-##-----------------------------------------------------------------------
-## recover the Settings instance, change an attribute, and store it again.
-##-----------------------------------------------------------------------
-#settings = Settings(settingsFile)
-#settings.userId = "vanrossum_g"
-#settings.store()
-#
-#"""
-# def __init__(self, filename): # obtaining filename is required
-# self.filename = None
-# raise NotImplementedError()
-#
-# def restore(self):
-# """
-# Set the values of whatever attributes are recoverable
-# from the pickle file.
-#
-# Populate the attributes (the __dict__) of the EgStore object
-# from the attributes (the __dict__) of the pickled object.
-#
-# If the pickled object has attributes that have been initialized
-# in the EgStore object, then those attributes of the EgStore object
-# will be replaced by the values of the corresponding attributes
-# in the pickled object.
-#
-# If the pickled object is missing some attributes that have
-# been initialized in the EgStore object, then those attributes
-# of the EgStore object will retain the values that they were
-# initialized with.
-#
-# If the pickled object has some attributes that were not
-# initialized in the EgStore object, then those attributes
-# will be ignored.
-#
-# IN SUMMARY:
-#
-# After the recover() operation, the EgStore object will have all,
-# and only, the attributes that it had when it was initialized.
-#
-# Where possible, those attributes will have values recovered
-# from the pickled object.
-# """
-# if not os.path.exists(self.filename): return self
-# if not os.path.isfile(self.filename): return self
-#
-# try:
-# f = open(self.filename,"rb")
-# unpickledObject = pickle.load(f)
-# f.close()
-#
-# for key in list(self.__dict__.keys()):
-# default = self.__dict__[key]
-# self.__dict__[key] = unpickledObject.__dict__.get(key,default)
-# except:
-# pass
-#
-# return self
-#
-# def store(self):
-# """
-# Save the attributes of the EgStore object to a pickle file.
-# Note that if the directory for the pickle file does not already exist,
-# the store operation will fail.
-# """
-# f = open(self.filename, "wb")
-# pickle.dump(self, f)
-# f.close()
-#
-#
-# def kill(self):
-# """
-# Delete my persistent file (i.e. pickle file), if it exists.
-# """
-# if os.path.isfile(self.filename):
-# os.remove(self.filename)
-# return
-#
-# def __str__(self):
-# """
-# return my contents as a string in an easy-to-read format.
-# """
-# # find the length of the longest attribute name
-# longest_key_length = 0
-# keys = []
-# for key in self.__dict__.keys():
-# keys.append(key)
-# longest_key_length = max(longest_key_length, len(key))
-#
-# keys.sort() # sort the attribute names
-# lines = []
-# for key in keys:
-# value = self.__dict__[key]
-# key = key.ljust(longest_key_length)
-# lines.append("%s : %s\n" % (key,repr(value)) )
-# return "".join(lines) # return a string showing the attributes
-
-
-
-
-##-----------------------------------------------------------------------
-##
-## test/demo easygui
-##
-##-----------------------------------------------------------------------
-#def egdemo():
-# """
-# Run the EasyGui demo.
-# """
-# # clear the console
-# writeln("\n" * 100)
-#
-# intro_message = ("Pick the kind of box that you wish to demo.\n"
-# + "\n * Python version " + sys.version
-# + "\n * EasyGui version " + egversion
-# + "\n * Tk version " + str(TkVersion)
-# )
-#
-# #========================================== END DEMONSTRATION DATA
-#
-#
-# while 1: # do forever
-# choices = [
-# "msgbox",
-# "buttonbox",
-# "buttonbox(image) -- a buttonbox that displays an image",
-# "choicebox",
-# "multchoicebox",
-# "textbox",
-# "ynbox",
-# "ccbox",
-# "enterbox",
-# "enterbox(image) -- an enterbox that displays an image",
-# "exceptionbox",
-# "codebox",
-# "integerbox",
-# "boolbox",
-# "indexbox",
-# "filesavebox",
-# "fileopenbox",
-# "passwordbox",
-# "multenterbox",
-# "multpasswordbox",
-# "diropenbox",
-# "About EasyGui",
-# " Help"
-# ]
-# choice = choicebox(msg=intro_message
-# , title="EasyGui " + egversion
-# , choices=choices)
-#
-# if not choice: return
-#
-# reply = choice.split()
-#
-# if reply[0] == "msgbox":
-# reply = msgbox("short msg", "This is a long title")
-# writeln("Reply was: %s" % repr(reply))
-#
-# elif reply[0] == "About":
-# reply = abouteasygui()
-#
-# elif reply[0] == "Help":
-# _demo_help()
-#
-# elif reply[0] == "buttonbox":
-# reply = buttonbox()
-# writeln("Reply was: %s" % repr(reply))
-#
-# title = "Demo of Buttonbox with many, many buttons!"
-# msg = "This buttonbox shows what happens when you specify too many buttons."
-# reply = buttonbox(msg=msg, title=title, choices=choices)
-# writeln("Reply was: %s" % repr(reply))
-#
-# elif reply[0] == "buttonbox(image)":
-# _demo_buttonbox_with_image()
-#
-# elif reply[0] == "boolbox":
-# reply = boolbox()
-# writeln("Reply was: %s" % repr(reply))
-#
-# elif reply[0] == "enterbox":
-# image = "python_and_check_logo.gif"
-# message = "Enter the name of your best friend."\
-# "\n(Result will be stripped.)"
-# reply = enterbox(message, "Love!", " Suzy Smith ")
-# writeln("Reply was: %s" % repr(reply))
-#
-# message = "Enter the name of your best friend."\
-# "\n(Result will NOT be stripped.)"
-# reply = enterbox(message, "Love!", " Suzy Smith ",strip=False)
-# writeln("Reply was: %s" % repr(reply))
-#
-# reply = enterbox("Enter the name of your worst enemy:", "Hate!")
-# writeln("Reply was: %s" % repr(reply))
-#
-# elif reply[0] == "enterbox(image)":
-# image = "python_and_check_logo.gif"
-# message = "What kind of snake is this?"
-# reply = enterbox(message, "Quiz",image=image)
-# writeln("Reply was: %s" % repr(reply))
-#
-# elif reply[0] == "exceptionbox":
-# try:
-# thisWillCauseADivideByZeroException = 1/0
-# except:
-# exceptionbox()
-#
-# elif reply[0] == "integerbox":
-# reply = integerbox(
-# "Enter a number between 3 and 333",
-# "Demo: integerbox WITH a default value",
-# 222, 3, 333)
-# writeln("Reply was: %s" % repr(reply))
-#
-# reply = integerbox(
-# "Enter a number between 0 and 99",
-# "Demo: integerbox WITHOUT a default value"
-# )
-# writeln("Reply was: %s" % repr(reply))
-#
-# elif reply[0] == "diropenbox" : _demo_diropenbox()
-# elif reply[0] == "fileopenbox": _demo_fileopenbox()
-# elif reply[0] == "filesavebox": _demo_filesavebox()
-#
-# elif reply[0] == "indexbox":
-# title = reply[0]
-# msg = "Demo of " + reply[0]
-# choices = ["Choice1", "Choice2", "Choice3", "Choice4"]
-# reply = indexbox(msg, title, choices)
-# writeln("Reply was: %s" % repr(reply))
-#
-# elif reply[0] == "passwordbox":
-# reply = passwordbox("Demo of password box WITHOUT default"
-# + "\n\nEnter your secret password", "Member Logon")
-# writeln("Reply was: %s" % str(reply))
-#
-# reply = passwordbox("Demo of password box WITH default"
-# + "\n\nEnter your secret password", "Member Logon", "alfie")
-# writeln("Reply was: %s" % str(reply))
-#
-# elif reply[0] == "multenterbox":
-# msg = "Enter your personal information"
-# title = "Credit Card Application"
-# fieldNames = ["Name","Street Address","City","State","ZipCode"]
-# fieldValues = [] # we start with blanks for the values
-# fieldValues = multenterbox(msg,title, fieldNames)
-#
-# # make sure that none of the fields was left blank
-# while 1:
-# if fieldValues == None: break
-# errmsg = ""
-# for i in range(len(fieldNames)):
-# if fieldValues[i].strip() == "":
-# errmsg = errmsg + ('"%s" is a required field.\n\n' % fieldNames[i])
-# if errmsg == "": break # no problems found
-# fieldValues = multenterbox(errmsg, title, fieldNames, fieldValues)
-#
-# writeln("Reply was: %s" % str(fieldValues))
-#
-# elif reply[0] == "multpasswordbox":
-# msg = "Enter logon information"
-# title = "Demo of multpasswordbox"
-# fieldNames = ["Server ID", "User ID", "Password"]
-# fieldValues = [] # we start with blanks for the values
-# fieldValues = multpasswordbox(msg,title, fieldNames)
-#
-# # make sure that none of the fields was left blank
-# while 1:
-# if fieldValues == None: break
-# errmsg = ""
-# for i in range(len(fieldNames)):
-# if fieldValues[i].strip() == "":
-# errmsg = errmsg + ('"%s" is a required field.\n\n' % fieldNames[i])
-# if errmsg == "": break # no problems found
-# fieldValues = multpasswordbox(errmsg, title, fieldNames, fieldValues)
-#
-# writeln("Reply was: %s" % str(fieldValues))
-#
-# elif reply[0] == "ynbox":
-# title = "Demo of ynbox"
-# msg = "Were you expecting the Spanish Inquisition?"
-# reply = ynbox(msg, title)
-# writeln("Reply was: %s" % repr(reply))
-# if reply:
-# msgbox("NOBODY expects the Spanish Inquisition!", "Wrong!")
-#
-# elif reply[0] == "ccbox":
-# title = "Demo of ccbox"
-# reply = ccbox(msg,title)
-# writeln("Reply was: %s" % repr(reply))
-#
-# elif reply[0] == "choicebox":
-# title = "Demo of choicebox"
-# longchoice = "This is an example of a very long option which you may or may not wish to choose."*2
-# listChoices = ["nnn", "ddd", "eee", "fff", "aaa", longchoice
-# , "aaa", "bbb", "ccc", "ggg", "hhh", "iii", "jjj", "kkk", "LLL", "mmm" , "nnn", "ooo", "ppp", "qqq", "rrr", "sss", "ttt", "uuu", "vvv"]
-#
-# msg = "Pick something. " + ("A wrapable sentence of text ?! "*30) + "\nA separate line of text."*6
-# reply = choicebox(msg=msg, choices=listChoices)
-# writeln("Reply was: %s" % repr(reply))
-#
-# msg = "Pick something. "
-# reply = choicebox(msg=msg, title=title, choices=listChoices)
-# writeln("Reply was: %s" % repr(reply))
-#
-# msg = "Pick something. "
-# reply = choicebox(msg="The list of choices is empty!", choices=[])
-# writeln("Reply was: %s" % repr(reply))
-#
-# elif reply[0] == "multchoicebox":
-# listChoices = ["aaa", "bbb", "ccc", "ggg", "hhh", "iii", "jjj", "kkk"
-# , "LLL", "mmm" , "nnn", "ooo", "ppp", "qqq"
-# , "rrr", "sss", "ttt", "uuu", "vvv"]
-#
-# msg = "Pick as many choices as you wish."
-# reply = multchoicebox(msg,"Demo of multchoicebox", listChoices)
-# writeln("Reply was: %s" % repr(reply))
-#
-# elif reply[0] == "textbox": _demo_textbox(reply[0])
-# elif reply[0] == "codebox": _demo_codebox(reply[0])
-#
-# else:
-# msgbox("Choice\n\n" + choice + "\n\nis not recognized", "Program Logic Error")
-# return
-#
-#
-#def _demo_textbox(reply):
-# text_snippet = ((\
-#"""It was the best of times, and it was the worst of times. The rich ate cake, and the poor had cake recommended to them, but wished only for enough cash to buy bread. The time was ripe for revolution! """ \
-#*5)+"\n\n")*10
-# title = "Demo of textbox"
-# msg = "Here is some sample text. " * 16
-# reply = textbox(msg, title, text_snippet)
-# writeln("Reply was: %s" % str(reply))
-#
-#def _demo_codebox(reply):
-# code_snippet = ("dafsdfa dasflkj pp[oadsij asdfp;ij asdfpjkop asdfpok asdfpok asdfpok"*3) +"\n"+\
-#"""# here is some dummy Python code
-#for someItem in myListOfStuff:
-# do something(someItem)
-# do something()
-# do something()
-# if somethingElse(someItem):
-# doSomethingEvenMoreInteresting()
-#
-#"""*16
-# msg = "Here is some sample code. " * 16
-# reply = codebox(msg, "Code Sample", code_snippet)
-# writeln("Reply was: %s" % repr(reply))
-#
-#
-#def _demo_buttonbox_with_image():
-#
-# msg = "Do you like this picture?\nIt is "
-# choices = ["Yes","No","No opinion"]
-#
-# for image in [
-# "python_and_check_logo.gif"
-# ,"python_and_check_logo.jpg"
-# ,"python_and_check_logo.png"
-# ,"zzzzz.gif"]:
-#
-# reply=buttonbox(msg + image,image=image,choices=choices)
-# writeln("Reply was: %s" % repr(reply))
-#
-#
-#def _demo_help():
-# savedStdout = sys.stdout # save the sys.stdout file object
-# sys.stdout = capturedOutput = StringIO()
-# help("easygui")
-# sys.stdout = savedStdout # restore the sys.stdout file object
-# codebox("EasyGui Help",text=capturedOutput.getvalue())
-#
-#def _demo_filesavebox():
-# filename = "myNewFile.txt"
-# title = "File SaveAs"
-# msg ="Save file as:"
-#
-# f = filesavebox(msg,title,default=filename)
-# writeln("You chose to save file: %s" % f)
-#
-#def _demo_diropenbox():
-# title = "Demo of diropenbox"
-# msg = "Pick the directory that you wish to open."
-# d = diropenbox(msg, title)
-# writeln("You chose directory...: %s" % d)
-#
-# d = diropenbox(msg, title,default="./")
-# writeln("You chose directory...: %s" % d)
-#
-# d = diropenbox(msg, title,default="c:/")
-# writeln("You chose directory...: %s" % d)
-#
-#
-#def _demo_fileopenbox():
-# msg = "Python files"
-# title = "Open files"
-# default="*.py"
-# f = fileopenbox(msg,title,default=default)
-# writeln("You chose to open file: %s" % f)
-#
-# default="./*.gif"
-# filetypes = ["*.jpg",["*.zip","*.tgs","*.gz", "Archive files"],["*.htm", "*.html","HTML files"]]
-# f = fileopenbox(msg,title,default=default,filetypes=filetypes)
-# writeln("You chose to open file: %s" % f)
-#
-# """#deadcode -- testing ----------------------------------------
-# f = fileopenbox(None,None,default=default)
-# writeln("You chose to open file: %s" % f)
-#
-# f = fileopenbox(None,title,default=default)
-# writeln("You chose to open file: %s" % f)
-#
-# f = fileopenbox(msg,None,default=default)
-# writeln("You chose to open file: %s" % f)
-#
-# f = fileopenbox(default=default)
-# writeln("You chose to open file: %s" % f)
-#
-# f = fileopenbox(default=None)
-# writeln("You chose to open file: %s" % f)
-# #----------------------------------------------------deadcode """
-#
-#
-#def _dummy():
-# pass
-#
-#EASYGUI_ABOUT_INFORMATION = '''
-#========================================================================
-#0.96(2010-08-29)
-#========================================================================
-#This version fixes some problems with version independence.
-#
-#BUG FIXES
-#------------------------------------------------------
-# * A statement with Python 2.x-style exception-handling syntax raised
-# a syntax error when running under Python 3.x.
-# Thanks to David Williams for reporting this problem.
-#
-# * Under some circumstances, PIL was unable to display non-gif images
-# that it should have been able to display.
-# The cause appears to be non-version-independent import syntax.
-# PIL modules are now imported with a version-independent syntax.
-# Thanks to Horst Jens for reporting this problem.
-#
-#LICENSE CHANGE
-#------------------------------------------------------
-#Starting with this version, EasyGui is licensed under what is generally known as
-#the "modified BSD license" (aka "revised BSD", "new BSD", "3-clause BSD").
-#This license is GPL-compatible but less restrictive than GPL.
-#Earlier versions were licensed under the Creative Commons Attribution License 2.0.
-#
-#
-#========================================================================
-#0.95(2010-06-12)
-#========================================================================
-#
-#ENHANCEMENTS
-#------------------------------------------------------
-# * Previous versions of EasyGui could display only .gif image files using the
-# msgbox "image" argument. This version can now display all image-file formats
-# supported by PIL the Python Imaging Library) if PIL is installed.
-# If msgbox is asked to open a non-gif image file, it attempts to import
-# PIL and to use PIL to convert the image file to a displayable format.
-# If PIL cannot be imported (probably because PIL is not installed)
-# EasyGui displays an error message saying that PIL must be installed in order
-# to display the image file.
-#
-# Note that
-# http://www.pythonware.com/products/pil/
-# says that PIL doesn't yet support Python 3.x.
-#
-#
-#========================================================================
-#0.94(2010-06-06)
-#========================================================================
-#
-#ENHANCEMENTS
-#------------------------------------------------------
-# * The codebox and textbox functions now return the contents of the box, rather
-# than simply the name of the button ("Yes"). This makes it possible to use
-# codebox and textbox as data-entry widgets. A big "thank you!" to Dominic
-# Comtois for requesting this feature, patiently explaining his requirement,
-# and helping to discover the tkinter techniques to implement it.
-#
-# NOTE THAT in theory this change breaks backward compatibility. But because
-# (in previous versions of EasyGui) the value returned by codebox and textbox
-# was meaningless, no application should have been checking it. So in actual
-# practice, this change should not break backward compatibility.
-#
-# * Added support for SPACEBAR to command buttons. Now, when keyboard
-# focus is on a command button, a press of the SPACEBAR will act like
-# a press of the ENTER key; it will activate the command button.
-#
-# * Added support for keyboard navigation with the arrow keys (up,down,left,right)
-# to the fields and buttons in enterbox, multenterbox and multpasswordbox,
-# and to the buttons in choicebox and all buttonboxes.
-#
-# * added highlightthickness=2 to entry fields in multenterbox and
-# multpasswordbox. Now it is easier to tell which entry field has
-# keyboard focus.
-#
-#
-#BUG FIXES
-#------------------------------------------------------
-# * In EgStore, the pickle file is now opened with "rb" and "wb" rather than
-# with "r" and "w". This change is necessary for compatibility with Python 3+.
-# Thanks to Marshall Mattingly for reporting this problem and providing the fix.
-#
-# * In integerbox, the actual argument names did not match the names described
-# in the docstring. Thanks to Daniel Zingaro of at University of Toronto for
-# reporting this problem.
-#
-# * In integerbox, the "argLowerBound" and "argUpperBound" arguments have been
-# renamed to "lowerbound" and "upperbound" and the docstring has been corrected.
-#
-# NOTE THAT THIS CHANGE TO THE ARGUMENT-NAMES BREAKS BACKWARD COMPATIBILITY.
-# If argLowerBound or argUpperBound are used, an AssertionError with an
-# explanatory error message is raised.
-#
-# * In choicebox, the signature to choicebox incorrectly showed choicebox as
-# accepting a "buttons" argument. The signature has been fixed.
-#
-#
-#========================================================================
-#0.93(2009-07-07)
-#========================================================================
-#
-#ENHANCEMENTS
-#------------------------------------------------------
-#
-# * Added exceptionbox to display stack trace of exceptions
-#
-# * modified names of some font-related constants to make it
-# easier to customize them
-#
-#
-#========================================================================
-#0.92(2009-06-22)
-#========================================================================
-#
-#ENHANCEMENTS
-#------------------------------------------------------
-#
-# * Added EgStore class to to provide basic easy-to-use persistence.
-#
-#BUG FIXES
-#------------------------------------------------------
-#
-# * Fixed a bug that was preventing Linux users from copying text out of
-# a textbox and a codebox. This was not a problem for Windows users.
-#
-#'''
-#
-#def abouteasygui():
-# """
-# shows the easygui revision history
-# """
-# codebox("About EasyGui\n"+egversion,"EasyGui",EASYGUI_ABOUT_INFORMATION)
-# return None
-#
-#
-#
-#if __name__ == '__main__':
-# if True:
-# egdemo()
-# else:
-# # test the new root feature
-# root = Tk()
-# msg = """This is a test of a main Tk() window in which we will place an easygui msgbox.
-# It will be an interesting experiment.\n\n"""
-# messageWidget = Message(root, text=msg, width=1000)
-# messageWidget.pack(side=TOP, expand=YES, fill=X, padx='3m', pady='3m')
-# messageWidget = Message(root, text=msg, width=1000)
-# messageWidget.pack(side=TOP, expand=YES, fill=X, padx='3m', pady='3m')
-#
-#
-# msgbox("this is a test of passing in boxRoot", root=root)
-# msgbox("this is a second test of passing in boxRoot", root=root)
-#
-# reply = enterbox("Enter something", root=root)
-# writeln("You wrote:", reply)
-#
-# reply = enterbox("Enter something else", root=root)
-# writeln("You wrote:", reply)
-# root.destroy()
+++ /dev/null
-#!/usr/bin/env python
-from subprocess import PIPE, Popen
-
-from canari.resource import external_resource
-from canari.utils.stack import modulecallee
-
-import os
-import re
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.3'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-__all__ = [
- 'privileged',
- 'specification'
-]
-
-
-def superuser(f):
- f.privileged = True
- return f
-
-
-def deprecated(f):
- f.deprecated = True
- return f
-
-
-class configure(object):
-
- def __init__(self, **kwargs):
- diff = set(['label', 'uuids', 'inputs']).difference(kwargs)
- if diff:
- raise TypeError('Missing transform specification properties: %s' % ', '.join(diff))
- if not isinstance(kwargs['uuids'], list):
- raise TypeError('Expected type list (got %s instead)' % type(kwargs['uuids']).__name__)
- if not isinstance(kwargs['inputs'], list):
- raise TypeError('Expected type list (got %s instead)' % type(kwargs['inputs']))
- kwargs['description'] = kwargs.get('description', '')
- kwargs['debug'] = kwargs.get('debug', False)
- self.function = kwargs.get('cmd', None)
- self.specification = kwargs
-
- def __call__(self, f):
- if callable(self.function):
- self.function.__dict__.update(f.__dict__)
- f = self.function
- f.__dict__.update(self.specification)
- return f
-
-
-class ExternalCommand(object):
-
- def __init__(self, transform_name, transform_args=[], interpreter=None, is_resource=True):
- self._extra_external_args = []
-
- if interpreter is not None:
- self._extra_external_args.append(interpreter)
- libpath = external_resource(
- os.path.dirname(transform_name),
- '%s.resources.external' % modulecallee().__name__.split('.')[0]
- )
- if interpreter.startswith('perl') or interpreter.startswith('ruby'):
- self._extra_external_args.extend([ '-I', libpath ])
- elif interpreter.startswith('java'):
- self._extra_external_args.extend([ '-cp', libpath ])
-
- if ' ' in transform_name:
- raise ValueError('Transform name %s cannot have spaces.' % repr(transform_name))
- elif not is_resource:
- self._extra_external_args.append(transform_name)
- else:
- self._extra_external_args.append(
- external_resource(
- transform_name,
- '%s.resources.external' % modulecallee().__name__.split('.')[0]
- )
- )
-
- if isinstance(transform_args, basestring):
- self._extra_external_args = re.split('\s+', transform_args)
- else:
- self._extra_external_args.extend(transform_args)
-
- def __call__(self, request, request_xml):
- args = [request.value]
- if isinstance(request.params, list) and request.params:
- args.extend(request.params)
- if request.fields:
- args.append('#'.join(['%s=%s' % (k, v) for k, v in request.fields.iteritems()]))
- if isinstance(request_xml, basestring):
- p = Popen(self._extra_external_args + list(args), stdin=PIPE, stdout=PIPE)
- out, err = p.communicate(request_xml)
- return out
- p = Popen(self._extra_external_args + list(args))
- p.communicate()
- exit(p.returncode)
+++ /dev/null
-#!/usr/bin/env python
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-__all__ = [
- 'message',
- 'utils'
-]
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-from canari.xmltools.oxml import XMLAttribute, XSAttributeType, XMLSubElement, XSSubElementType
-from message import MaltegoElement
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-__all__ = [
- 'BuiltInTransformSets',
- 'TransformAdapter',
- 'MaltegoTransform',
- 'InputConstraint',
- 'OutputEntity',
- 'InputEntity',
- 'PropertyType',
- 'TransformProperty',
- 'TransformPropertySetting',
- 'CmdLineTransformProperty',
- 'CmdLineTransformPropertySetting',
- 'CmdParmTransformProperty',
- 'CmdParmTransformPropertySetting',
- 'CmdCwdTransformProperty',
- 'CmdCwdTransformPropertySetting',
- 'CmdDbgTransformProperty',
- 'CmdDbgTransformPropertySetting',
- 'TransformSettings',
- 'TransformSet'
-]
-
-
-class TransformAdapter(object):
- Local ='com.paterva.maltego.transform.protocol.v2.LocalTransformAdapterV2'
- Remote ='com.paterva.maltego.transform.protocol.v2.RemoteTransformAdapterV2'
-
-
-@XMLAttribute(name='abstract', type=XSAttributeType.Bool, default=False)
-@XMLAttribute(name='author', default='')
-@XMLAttribute(name='description', default='')
-@XMLAttribute(name='displayName', propname='displayname')
-@XMLAttribute(name='name')
-@XMLAttribute(name='requireDisplayInfo', propname='requireinfo', type=XSAttributeType.Bool, default=False)
-@XMLAttribute(name='template', type=XSAttributeType.Bool, default=False)
-@XMLAttribute(name='visibility', default='public')
-@XMLAttribute(name='helpURL', propname='helpurl')
-@XMLAttribute(name='owner')
-@XMLAttribute(name='version', default='1.0')
-@XMLAttribute(name='locationRelevance', propname='locrel')
-@XMLSubElement(name='TransformAdapter', propname='adapter', type=XSSubElementType.Enum, choices=[TransformAdapter.Local, TransformAdapter.Remote], default=TransformAdapter.Local)
-@XMLSubElement(name='StealthLevel', propname='stealthlvl', type=XSSubElementType.Integer, default=0)
-@XMLSubElement(name='defaultSets', propname='sets', type=XSSubElementType.List)
-@XMLSubElement(name='Disclaimer', propname='disclaimer', type=XSSubElementType.CData)
-@XMLSubElement(name='Help', propname='help', type=XSSubElementType.CData)
-@XMLSubElement(name='OutputEntities', propname='output', type=XSSubElementType.List)
-@XMLSubElement(name='InputConstraints', propname='input', type=XSSubElementType.List)
-@XMLSubElement(name='Properties/Fields', propname='properties', type=XSSubElementType.List)
-class MaltegoTransform(MaltegoElement):
- def __init__(self, name, displayname, **kwargs):
- super(MaltegoTransform, self).__init__(self.__class__.__name__)
- self.name = name
- self.displayname = displayname
- self.abstract = kwargs.get('abstract', self.abstract)
- self.author = kwargs.get('author', self.author)
- self.description = kwargs.get('description', self.description)
- self.requireinfo = kwargs.get('requireinfo', self.requireinfo)
- self.template = kwargs.get('template', self.template)
- self.visibility = kwargs.get('visibility', self.visibility)
- self.helpurl = kwargs.get('helpurl', self.helpurl)
- self.owner = kwargs.get('owner', self.owner)
- self.version = kwargs.get('version', self.version)
- self.locrel = kwargs.get('locrel', self.locrel)
- self.adapter = kwargs.get('adapter', self.adapter)
- self.stealthlvl = kwargs.get('stealthlvl', self.stealthlvl)
- self.disclaimer = kwargs.get('disclaimer')
- self.help = kwargs.get('help')
- self.appendelements(kwargs.get('sets'))
- self.appendelements(kwargs.get('input'))
- self.appendelements(kwargs.get('output'))
- self.appendelements(kwargs.get('properties'))
-
- def appendelement(self, other):
- if isinstance(other, TransformSet):
- self.sets += other
- elif isinstance(other, TransformProperty):
- self.properties += other
- elif isinstance(other, InputConstraint) or isinstance(other, InputEntity):
- self.input += other
- elif isinstance(other, OutputEntity):
- self.output += other
-
- def removeelement(self, other):
- if isinstance(other, TransformSet):
- self.sets -= other
- if isinstance(other, TransformProperty):
- self.properties -= other
- elif isinstance(other, InputConstraint) or isinstance(other, InputEntity):
- self.input -= other
- elif isinstance(other, OutputEntity):
- self.output -= other
-
-
-class BuiltInTransformSets(object):
- ConvertToDomain = "Convert to Domain"
- DomainsUsingMXNS = "Domains using MX NS"
- FindOnWebpage = "Find on webpage"
- RelatedEmailAddresses = "Related Email addresses"
- DNSFromDomain = "DNS from Domain"
- EmailAddressesFromDomain = "Email addresses from Domain"
- IPOwnerDetail = "IP owner detail"
- ResolveToIP = "Resolve to IP"
- DNSFromIP = "DNS from IP"
- EmailAddressesFromPerson = "Email addresses from Person"
- InfoFromNS = "Info from NS"
- DomainFromDNS = "Domain From DNS"
- FilesAndDocumentsFromDomain = "Files and Documents from Domain"
- LinksInAndOutOfSite = "Links in and out of site"
- DomainOwnerDetail = "Domain owner detail"
- FilesAndDocumentsFromPhrase = "Files and Documents from Phrase"
-
-
-@XMLAttribute(name='name')
-class TransformSet(MaltegoElement):
-
- def __init__(self, name):
- super(MaltegoElement, self).__init__('Set')
- self.name = name
-
-
-@XMLAttribute(name='max', type=XSAttributeType.Integer, default=1)
-@XMLAttribute(name='min', type=XSAttributeType.Integer, default=1)
-@XMLAttribute(name='type')
-class InputConstraint(MaltegoElement):
- def __init__(self, type, **kwargs):
- super(InputConstraint, self).__init__('Entity')
- self.type = type
- self.min = kwargs.get('min', self.min)
- self.max = kwargs.get('max', self.max)
-
-
-class OutputEntity(InputConstraint):
- pass
-
-
-class InputEntity(InputConstraint):
- pass
-
-
-class PropertyType(object):
- String = 'string'
- Boolean = 'boolean'
- Integer = 'int'
-
-
-@XMLSubElement(name='DefaultValue', propname='defaultvalue')
-@XMLSubElement(name='SampleValue', propname='samplevalue', default='')
-@XMLAttribute(name='abstract', type=XSAttributeType.Bool, default=False)
-@XMLAttribute(name='description', default='')
-@XMLAttribute(name='displayName', propname='displayname')
-@XMLAttribute(name='hidden', type=XSAttributeType.Bool, default=False)
-@XMLAttribute(name='name')
-@XMLAttribute(name='nullable', type=XSAttributeType.Bool, default=False)
-@XMLAttribute(name='readonly', type=XSAttributeType.Bool, default=False)
-@XMLAttribute(name='popup', type=XSAttributeType.Bool, default=False)
-@XMLAttribute(name='type', default=PropertyType.String)
-@XMLAttribute(name='visibility', default='public')
-class TransformProperty(MaltegoElement):
-
- def __init__(self, name, default, displayname, description, **kwargs):
- super(TransformProperty, self).__init__("Property")
- self.name = name
- self.displayname = displayname
- self.defaultvalue = default
- self.description = description
- self.abstract = kwargs.get('abstract', self.abstract)
- self.samplevalue = kwargs.get('sample', self.samplevalue)
- self.hidden = kwargs.get('hidden', self.hidden)
- self.nullable = kwargs.get('nullable', self.nullable)
- self.popup = kwargs.get('popup', self.popup)
- self.readonly = kwargs.get('readonly', self.readonly)
- self.type = kwargs.get('type', self.type)
- self.visibility = kwargs.get('visibility', self.visibility)
-
-
-@XMLAttribute(name='name')
-@XMLAttribute(name='popup', type=XSAttributeType.Bool, default=False)
-@XMLAttribute(name='type', default=PropertyType.String)
-class TransformPropertySetting(MaltegoElement):
-
- def __init__(self, name, value, **kwargs):
- super(TransformPropertySetting, self).__init__("Property")
- self.name = name
- self.text = value
- self.popup = kwargs.get('popup', self.popup)
- self.type = kwargs.get('type', self.type)
-
-
-def CmdLineTransformProperty(cmd=''):
- return TransformProperty(
- 'transform.local.command',
- cmd,
- 'Command line',
- 'The command to execute for this transform'
- )
-
-
-def CmdLineTransformPropertySetting(cmd=''):
- return TransformPropertySetting(
- 'transform.local.command',
- cmd
- )
-
-
-def CmdParmTransformProperty(params=''):
- return TransformProperty(
- 'transform.local.parameters',
- params,
- 'Command parameters',
- 'The parameters to pass to the transform command'
- )
-
-
-def CmdParmTransformPropertySetting(params=''):
- return TransformPropertySetting(
- 'transform.local.parameters',
- params
- )
-
-
-def CmdCwdTransformProperty(cwd=''):
- return TransformProperty(
- 'transform.local.working-directory',
- cwd,
- 'Working directory',
- 'The working directory used when invoking the executable',
- sample_val='/'
- )
-
-
-def CmdCwdTransformPropertySetting(cwd=''):
- return TransformPropertySetting(
- 'transform.local.working-directory',
- cwd
- )
-
-
-def CmdDbgTransformProperty(dbg=False):
- return TransformProperty(
- 'transform.local.debug',
- str(dbg).lower(),
- 'Show debug info',
- "When this is set, the transform's text output will be printed to the output window",
- sample_val=False,
- type=PropertyType.Boolean
- )
-
-
-def CmdDbgTransformPropertySetting(dbg=False):
- return TransformPropertySetting(
- 'transform.local.debug',
- str(dbg).lower(),
- type=PropertyType.Boolean
- )
-
-
-@XMLAttribute(name='enabled', type=XSAttributeType.Bool, default=True)
-@XMLAttribute(name='disclaimerAccepted', propname='accepted', type=XSAttributeType.Bool, default=False)
-@XMLAttribute(name='showHelp', propname='show', type=XSAttributeType.Bool, default=True)
-@XMLSubElement(name='Properties', propname='properties', type=XSSubElementType.List)
-class TransformSettings(MaltegoElement):
-
- def __init__(self, **kwargs):
- super(TransformSettings, self).__init__(self.__class__.__name__)
- self.enabled = kwargs.get('enabled', self.enabled)
- self.accepted = kwargs.get('accepted', self.accepted)
- self.show = kwargs.get('show', self.show)
- self.appendelements(kwargs.get('properties'))
-
- def appendelement(self, other):
- if isinstance(other, TransformPropertySetting):
- self.properties += other
-
- def removeelement(self, other):
- if isinstance(other, TransformPropertySetting):
- self.properties -= other
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-from message import Entity, EntityField, EntityFieldType
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-__all__ = [
- 'Affiliation',
- 'AffiliationBebo',
- 'AffiliationFacebook',
- 'AffiliationFlickr',
- 'AffiliationLinkedin',
- 'AffiliationMySpace',
- 'AffiliationOrkut',
- 'AffiliationSpock',
- 'AffiliationTwitter',
- 'AffiliationWikiEdit',
- 'AffiliationZoominfo',
- 'Alias',
- 'AS',
- 'Banner',
- 'BuiltWithTechnology',
- 'Device',
- 'DNSName',
- 'Document',
- 'Domain',
- 'EmailAddress',
- 'FacebookObject',
- 'File',
- 'GPS',
- 'Image',
- 'IPv4Address',
- 'Location',
- 'MXRecord',
- 'Netblock',
- 'NominatimLocation',
- 'NSRecord',
- 'Person',
- 'PhoneNumber',
- 'Phrase',
- 'Port',
- 'Service',
- 'Twit',
- 'URL',
- 'Vuln',
- 'Webdir',
- 'Website',
- 'WebTitle'
-]
-
-
-@EntityField(name='properties.gps', displayname='GPS Co-ordinate')
-@EntityField(name='latitude', displayname='Latitude', type=EntityFieldType.Float)
-@EntityField(name='longitude', displayname='Longitude', type=EntityFieldType.Float)
-class GPS(Entity):
- pass
-
-
-@EntityField(name='properties.device', displayname='Device')
-class Device(Entity):
- pass
-
-
-@EntityField(name='properties.builtwithtechnology', propname='builtwith', displayname='BuiltWith Technology')
-class BuiltWithTechnology(Entity):
- pass
-
-
-
-@EntityField(name='fqdn', displayname='Domain Name')
-@EntityField(name='whois', displayname='WHOIS Info')
-class Domain(Entity):
- pass
-
-
-@EntityField(name='fqdn', displayname='DNS Name')
-class DNSName(Entity):
- pass
-
-
-@EntityField(name='fqdn', displayname='MX Record')
-@EntityField(name='mxrecord.priority', propname='mxpriority', type=EntityFieldType.Integer)
-class MXRecord(Entity):
- pass
-
-
-@EntityField(name='fqdn', displayname='NS Record')
-class NSRecord(Entity):
- pass
-
-
-@EntityField(name='ipv4-address', propname='ipv4address', displayname='IP Address')
-@EntityField(name='ipaddress.internal', propname='internal', displayname='Internal', type=EntityFieldType.Bool)
-class IPv4Address(Entity):
- pass
-
-
-@EntityField(name='ipv4-range', propname='ipv4range', displayname='IP Range')
-class Netblock(Entity):
- pass
-
-
-@EntityField(name='as.number', propname='number', displayname='AS Number', type=EntityFieldType.Integer)
-class AS(Entity):
- pass
-
-
-@EntityField(name='website.ssl-enabled', displayname='SSL Enabled', type=EntityFieldType.Bool)
-@EntityField(name='fqdn', displayname='Website')
-@EntityField(name='ports', displayname='Ports', type=EntityFieldType.Integer)
-class Website(Entity):
- pass
-
-
-@EntityField(name='maltego.v2.value.property', propname='shorttitle', displayname='Short title')
-@EntityField(name='theurl', propname='url', displayname='URL')
-@EntityField(name='fulltitle', displayname='Title')
-class URL(Entity):
- pass
-
-
-@EntityField(name='text', displayname='Text')
-class Phrase(Entity):
- pass
-
-
-@EntityField(name='maltego.v2.value.property', propname='title', displayname='Title')
-@EntityField(name='link', propname='url', displayname='URL')
-@EntityField(name='metainfo', propname='metadata', displayname='Meta-Data')
-class Document(Entity):
- pass
-
-
-@EntityField(name='lastname', propname='lastname', displayname='Surname')
-@EntityField(name='firstname', propname='firstnames', displayname='First Names')
-@EntityField(name='person.fullname', propname='fullname', displayname='Full Name')
-class Person(Entity):
- pass
-
-
-@EntityField(name='email', displayname='Email Address')
-class EmailAddress(Entity):
- pass
-
-
-@EntityField(name='content', displayname='Content')
-@EntityField(name='pubdate', displayname='Date published')
-@EntityField(name='imglink', displayname='Image Link')
-@EntityField(name='author', displayname='Author')
-@EntityField(name='title', displayname='Title')
-@EntityField(name='author_uri', propname='authoruri', displayname='Author URI')
-@EntityField(name='twit.name', propname='twitname', displayname='Twit')
-@EntityField(name='id', displayname='Twit ID')
-class Twit(Entity):
- pass
-
-
-@EntityField(name='person.name', propname='name', displayname='Name')
-@EntityField(name='uid', displayname='UID')
-@EntityField(name='network', displayname='Network')
-@EntityField(name='profile_url', propname='profileurl', displayname='Profile URL')
-class Affiliation(Entity):
- pass
-
-
-class AffiliationBebo(Affiliation):
- pass
-
-
-class AffiliationFacebook(Affiliation):
- name = "affiliation.Facebook"
-
-
-class AffiliationFlickr(Affiliation):
- name = "affiliation.Flickr"
-
-
-class AffiliationLinkedin(Affiliation):
- pass
-
-
-class AffiliationMySpace(Affiliation):
- pass
-
-
-class AffiliationOrkut(Affiliation):
- pass
-
-
-class AffiliationSpock(Affiliation):
- pass
-
-
-@EntityField(name='properties.facebookobject', propname='object', displayname='Facebook Object')
-class FacebookObject(Entity):
- pass
-
-
-@EntityField(name='twitter.number', propname='number', displayname='Twitter Number', type=EntityFieldType.Integer)
-@EntityField(name='twitter.screen-name', propname='screenname', displayname='Screen Name')
-@EntityField(name='twitter.friendcount', propname='friendcount', displayname='Friend Count', type=EntityFieldType.Integer)
-@EntityField(name='person.fullname', propname='fullname', displayname='Real Name')
-class AffiliationTwitter(Affiliation):
- name = "affiliation.Twitter"
-
-
-class AffiliationZoominfo(Affiliation):
- pass
-
-
-class AffiliationWikiEdit(Affiliation):
- pass
-
-
-@EntityField(name='city', displayname='City')
-@EntityField(name='countrysc', propname='countrycode', displayname='Country Code')
-@EntityField(name='area', displayname='Area')
-@EntityField(name='country', displayname='Country')
-@EntityField(name='long', propname='longitude', displayname='Longitude', type=EntityFieldType.Float)
-@EntityField(name='lat', propname='latitude', displayname='Latitude', type=EntityFieldType.Float)
-@EntityField(name='streetaddress', displayname='Street Address')
-@EntityField(name='location.areacode', displayname='Area Code')
-@EntityField(name='location.name', propname='locationname', displayname='Name')
-class Location(Entity):
- pass
-
-
-@EntityField(name='properties.nominatimlocation', propname='nominatim', displayname='Nominatim Location')
-class NominatimLocation(Entity):
- pass
-
-
-@EntityField(name='areacode', displayname='Area Code')
-@EntityField(name='lastnumbers', displayname='Last Digits')
-@EntityField(name='citycode', displayname='City Code')
-@EntityField(name='phonenumber', displayname='Phone Number')
-@EntityField(name='countrycode', displayname='Country Code')
-class PhoneNumber(Entity):
- pass
-
-
-@EntityField(name='properties.alias', propname='alias', displayname='Alias')
-class Alias(Entity):
- pass
-
-
-@EntityField(name='properties.image', propname='description', displayname='Description')
-@EntityField(name='fullImage', propname='url', displayname='URL')
-class Image(Entity):
- pass
-
-
-@EntityField(name='source', displayname='Source')
-@EntityField(name='description', displayname='Description')
-class File(Entity):
- pass
-
-
-class Banner(Entity):
- pass
-
-
-class Port(Entity):
- pass
-
-
-class Service(Entity):
- pass
-
-
-class Vuln(Entity):
- pass
-
-
-class Webdir(Entity):
- pass
-
-
-@EntityField(name='title', displayname='Title')
-class WebTitle(Entity):
- pass
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-from canari.xmltools.oxml import ElementTree, Element
-
-from cStringIO import StringIO
-from copy import deepcopy
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-__all__ = [
- 'HTML',
- 'TABLE',
- 'TR',
- 'TD',
- 'A',
- 'IMG',
- 'Table'
-]
-
-
-class HTML(Element, object):
-
- def __init__(self, tag='html', attrib={}, **extra):
- attrib = attrib.copy()
- attrib.update(extra)
- super(HTML, self).__init__(tag, attrib)
-
- def __add__(self, other):
- newobj = deepcopy(self)
- newobj.append(other)
- return newobj
-
- def __iadd__(self, other):
- self.append(other)
- return self
-
- def __sub__(self, other):
- self.remove(other)
- newobj = deepcopy(self)
- self.append(other)
- return newobj
-
- def __isub__(self, other):
- self.remove(other)
- return self
-
- def __str__(self):
- sio = StringIO()
- ElementTree(self).write(sio)
- return sio.getvalue()
-
-
-class TABLE(HTML):
-
- def __init__(self, title="GENERAL INFORMATION", colspan="2", **kwargs):
- super(TABLE, self).__init__(
- "table",
- attrib={
- 'width' : '100%',
- 'border' : '1',
- 'rules' : 'cols',
- 'frame' : 'box',
- 'cellpadding' : '2'
- }
- )
-
- tr = TR()
- self.append(tr)
- tr.append(TD(title, colspan=colspan, css_class=TD.ONE))
-
- for i in kwargs:
- self.set(i, str(kwargs[i]) if not isinstance(kwargs[i], basestring) else kwargs[i])
-
-class TR(HTML):
-
- def __init__(self):
- super(TR, self).__init__('tr')
-
-
-class A(HTML):
-
- def __init__(self, label, href, **kwargs):
- attrib = { 'href' : href }
- attrib.update(kwargs)
- super(A, self).__init__(
- 'a',
- attrib=attrib
- )
- self.text = label
-
-
-class IMG(HTML):
-
- def __init__(self, src, **kwargs):
- attrib = { 'src' : src }
- attrib.update(kwargs)
-
- super(IMG, self).__init__(
- 'img',
- attrib=attrib
- )
-
-class TD(HTML):
-
- ONE = "one"
- TWO = "two"
- THREE = "three"
- VALUE = "value"
-
- def __init__(self, value, css_class=TWO, align="center", **kwargs):
- super(TD, self).__init__(
- 'td',
- attrib={
- 'class' : css_class,
- 'align' : align,
- }
- )
- self.text = str(value) if not isinstance(value, basestring) else value
-
- for i in kwargs:
- self.set(i, str(kwargs[i]) if not isinstance(kwargs[i], basestring) else kwargs[i])
-
-
-class Table(object):
-
- def __init__(self, columns, title='GENERAL INFORMATION'):
- self._rows = []
- self._title = title
- self._rows.append([ TD(c, TD.THREE) for c in columns ])
-
- def addrow(self, columns):
- self._rows.append([ TD(c) for c in columns ])
-
- def __str__(self):
- self.table = TABLE(self._title, colspan=len(self._rows[0]))
- for r in self._rows:
- tr = TR()
- c = tr.getchildren()
- c += r
- self.table += tr
- return str(self.table)
+++ /dev/null
-#!/usr/bin/env python
-
-from canari.xmltools.oxml import *
-
-from datetime import datetime, date, timedelta
-from numbers import Number
-from re import sub, compile, match
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.3'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-__all__ = [
- 'timespan',
- 'Message',
- 'MaltegoElement',
- 'MaltegoMessage',
- 'MaltegoTransformExceptionMessage',
- 'MaltegoException',
- 'MaltegoTransformResponseMessage',
- 'Label',
- 'MatchingRule',
- 'Field',
- 'StringEntityField',
- 'EnumEntityField',
- 'IntegerEntityField',
- 'BooleanEntityField',
- 'FloatEntityField',
- 'LongEntityField',
- 'DateTimeEntityField',
- 'TimeSpanEntityField',
- 'DateEntityField',
- 'EntityFieldType',
- 'RegexEntityField'
- 'ColorEntityField'
- 'EntityField',
- 'UIMessageType',
- 'UIMessage',
- 'Entity',
-]
-
-
-class Message(ElementTree):
- pass
-
-
-class MaltegoElement(Element):
- pass
-
-
-class MaltegoMessage(MaltegoElement):
-
- def __init__(self, message):
- super(MaltegoMessage, self).__init__(self.__class__.__name__)
- self.append(message)
-
-
-@XMLSubElement(name='Exceptions', propname='exceptions', type=XSSubElementType.List)
-class MaltegoTransformExceptionMessage(MaltegoElement):
-
- def __init__(self, **kwargs):
- super(MaltegoTransformExceptionMessage, self).__init__(self.__class__.__name__)
- self.appendelements(kwargs.get('exceptions'))
-
- def appendelement(self, exception):
- if isinstance(exception, MaltegoException):
- self.exceptions += exception
- else:
- self.exceptions += MaltegoException(str(exception))
-
-
-class MaltegoException(MaltegoElement, Exception):
-
- def __init__(self, message):
- super(MaltegoException, self).__init__('Exception')
- Exception.__init__(self, message)
- self.text = message if not isinstance(message, basestring) else message
-
-
-class MaltegoTransformRequestMessage(object):
-
- def __init__(self, value, fields, parameters, limits=None):
- self.value = value
- self.fields = fields
- self.params = parameters
- if limits is None:
- self.limits = dict(soft=500, hard=10000)
- else:
- self.limits = dict(soft=limits.get('SoftLimit', 500), hard=limits.get('HardLimit', 10000))
-
-
-@XMLSubElement(name='UIMessages', propname='uimessages', type=XSSubElementType.List)
-@XMLSubElement(name='Entities', propname='entities', type=XSSubElementType.List)
-class MaltegoTransformResponseMessage(MaltegoElement):
-
- def __init__(self, **kwargs):
- super(MaltegoTransformResponseMessage, self).__init__(self.__class__.__name__)
- self.appendelements(kwargs.get('entities'))
- self.appendelements(kwargs.get('uimessages'))
-
- def appendelement(self, other):
- if isinstance(other, Entity):
- self.entities += other
- elif isinstance(other, UIMessage):
- self.uimessages += other
-
- def removeelement(self, other):
- if isinstance(other, Entity):
- self.entities -= other
- elif isinstance(other, UIMessage):
- self.uimessages -= other
-
-
-@XMLAttribute(name='Name', propname='name')
-@XMLAttribute(name='Type', propname='type', default='text/text')
-@XMLSubElement(name='CDATA', propname='cdata')
-class Label(MaltegoElement):
-
- def __init__(self, name, value, **kwargs):
- super(Label, self).__init__(self.__class__.__name__)
- self.name = name
- self.type = kwargs.get('type', self.type)
-
- if self.type == 'text/html':
- self.cdata = value
- else:
- self.text = str(value) if not isinstance(value, basestring) else value
-
-
-class MatchingRule(object):
- Strict = "strict"
- Loose = "loose"
-
-
-@XMLAttribute(name='Name', propname='name')
-@XMLAttribute(name='DisplayName', propname='displayname')
-@XMLAttribute(name='MatchingRule', propname='matchingrule', default=MatchingRule.Strict)
-class Field(MaltegoElement):
-
- def __init__(self, name, value, **kwargs):
- super(Field, self).__init__(self.__class__.__name__)
- self.name = name
- self.matchingrule = kwargs.get('matchingrule', self.matchingrule)
- self.displayname = kwargs.get('displayname', None)
- self.text = str(value) if not isinstance(value, basestring) else value
-
-
-class StringEntityField(object):
-
- def __init__(self, name, displayname=None, decorator=None, matchingrule=MatchingRule.Strict):
- self.name = name
- self.displayname = displayname
- self.decorator = decorator
- self.matchingrule = matchingrule
-
- def _find(self, obj):
- for f in obj.fields:
- if f.name == self.name:
- return f
- return None
-
- def __get__(self, obj, objtype):
- o = self._find(obj)
- return o.text if o is not None else None
-
- def __set__(self, obj, val):
- f = self._find(obj)
- if not isinstance(val, basestring) and val is not None:
- val = str(val)
- if f is None and val is not None:
- f = Field(self.name, val, displayname=self.displayname, matchingrule=self.matchingrule)
- obj += f
- elif f is not None and val is None:
- obj -= f
- else:
- f.text = val
- if self.decorator is not None:
- self.decorator(obj, val)
-
-
-class EnumEntityField(StringEntityField):
-
- def __init__(self, name, displayname=None, choices=[], decorator=None, matchingrule=MatchingRule.Strict):
- self.choices = [ str(c) if not isinstance(c, basestring) else c for c in choices ]
- super(EnumEntityField, self).__init__(name, displayname, decorator, matchingrule)
-
- def __set__(self, obj, val):
- val = str(val) if not isinstance(val, basestring) else val
- if val not in self.choices:
- raise ValueError('Expected one of %s (got %s instead)' % (self.choices, val))
- super(EnumEntityField, self).__set__(obj, val)
-
-
-class IntegerEntityField(StringEntityField):
-
- def __get__(self, obj, objtype):
- i = super(IntegerEntityField, self).__get__(obj, objtype)
- return int(i) if i is not None else None
-
- def __set__(self, obj, val):
- if not isinstance(val, Number):
- raise TypeError('Expected an instance of int (got %s instance instead)' % type(val).__name__)
- super(IntegerEntityField, self).__set__(obj, val)
-
-
-class BooleanEntityField(StringEntityField):
-
- def __get__(self, obj, objtype):
- b = super(BooleanEntityField, self).__get__(obj, objtype)
- return b == 'true' if b is not None else None
-
- def __set__(self, obj, val):
- if not isinstance(val, bool):
- raise TypeError('Expected an instance of bool (got %s instance instead)' % type(val).__name__)
- super(BooleanEntityField, self).__set__(obj, str(val).lower())
-
-
-class FloatEntityField(StringEntityField):
-
- def __get__(self, obj, objtype):
- f = super(FloatEntityField, self).__get__(obj, objtype)
- return float(f) if f is not None else None
-
- def __set__(self, obj, val):
- if not isinstance(val, Number):
- raise TypeError('Expected an instance of float (got %s instance instead)' % type(val).__name__)
- super(FloatEntityField, self).__set__(obj, val)
-
-
-class LongEntityField(StringEntityField):
-
- def __get__(self, obj, objtype):
- l = super(LongEntityField, self).__get__(obj, objtype)
- return long(l) if l is not None else None
-
- def __set__(self, obj, val):
- if not isinstance(val, Number):
- raise TypeError('Expected an instance of float (got %s instance instead)' % type(val).__name__)
- super(LongEntityField, self).__set__(obj, val)
-
-
-class DateTimeEntityField(StringEntityField):
-
- def __get__(self, obj, objtype):
- d = super(DateTimeEntityField, self).__get__(obj, objtype)
- return datetime.strptime(d, '%Y-%m-%d %H:%M:%S.%f') if d is not None else None
-
- def __set__(self, obj, val):
- if not isinstance(val, datetime):
- raise TypeError('Expected an instance of datetime (got %s instance instead)' % type(val).__name__)
- super(DateTimeEntityField, self).__set__(obj, val)
-
-
-class DateEntityField(StringEntityField):
-
- def __get__(self, obj, objtype):
- d = super(DateEntityField, self).__get__(obj, objtype)
- return datetime.strptime(d, '%Y-%m-%d').date() if d is not None else None
-
- def __set__(self, obj, val):
- if not isinstance(val, date):
- raise TypeError('Expected an instance of date (got %s instance instead)' % type(val).__name__)
- super(DateEntityField, self).__set__(obj, val)
-
-
-class timespan(timedelta):
-
- matcher = compile('(\d+)d (\d+)h(\d+)m(\d+)\.(\d+)s')
-
- def __str__(self):
- return '%dd %dh%dm%d.%03ds' % (
- abs(self.days),
- int(self.seconds) // 3600,
- int(self.seconds) % 3600 // 60,
- int(self.seconds) % 60,
- int(self.microseconds)
- )
-
- @classmethod
- def fromstring(cls, ts):
- m = cls.matcher.match(ts)
- if m is None:
- raise ValueError('Time span must be in "%%dd %%Hh%%Mm%%S.%%fs" format')
- days, hours, minutes, seconds, useconds = [ int(i) for i in m.groups() ]
- return timespan(days, (hours * 3600) + (minutes * 60) + seconds, useconds)
-
-
-class TimeSpanEntityField(StringEntityField):
-
- def __get__(self, obj, objtype):
- d = super(TimeSpanEntityField, self).__get__(obj, objtype)
- return timespan.fromstring(d) if d is not None else None
-
- def __set__(self, obj, val):
- if not isinstance(val, timespan) or not isinstance(val, timedelta):
- raise TypeError('Expected an instance of timedelta (got %s instance instead)' % type(val).__name__)
- if val.__class__ is timedelta:
- val = timespan(val.days, val.seconds, val.microseconds)
- super(TimeSpanEntityField, self).__set__(obj, val)
-
-
-class RegexEntityField(StringEntityField):
-
- pattern = '.*'
-
- def __set__(self, obj, val):
- if not isinstance(val, basestring):
- val = str(val)
- if match(self.pattern, val) is None:
- raise ValueError('Failed match for %s, expected pattern %s instead.' % (repr(val), repr(self.pattern)))
- super(RegexEntityField, self).__set__(obj, val)
-
-
-class ColorEntityField(RegexEntityField):
-
- pattern = '^#[0-9a-fA-F]{6}$'
-
-
-
-class EntityFieldType(object):
- String = StringEntityField
- Integer = IntegerEntityField
- Long = LongEntityField
- Float = FloatEntityField
- Bool = BooleanEntityField
- Enum = EnumEntityField
- Date = DateEntityField
- DateTime = DateTimeEntityField
- TimeSpan = TimeSpanEntityField
- Color = ColorEntityField
-
-
-class EntityField(object):
-
- def __init__(self, link=False, **kwargs):
- self.name = kwargs.get('name')
- if self.name is None:
- raise ValueError("Keyword argument 'name' is required.")
- self.property = kwargs.get('propname', sub('[^\w]+', '_', self.name))
- if not link:
- self.displayname = kwargs.get('displayname', self.name.title())
- else:
- self.displayname = kwargs.get('displayname', None)
- self.type = kwargs.get('type', EntityFieldType.String)
- self.required = kwargs.get('required', False)
- self.choices = kwargs.get('choices')
- self.matchingrule = kwargs.get('matchingrule', MatchingRule.Strict)
- self.decorator = kwargs.get('decorator')
-
- def __call__(self, cls):
- if self.type is EntityFieldType.Enum:
- setattr(
- cls,
- self.property,
- self.type(self.name, self.displayname, self.choices, self.decorator, self.matchingrule)
- )
- else:
- setattr(
- cls,
- self.property,
- self.type(self.name, self.displayname, self.decorator, self.matchingrule)
- )
- return cls
-
-
-class EntityLinkField(EntityField):
-
- def __init__(self, **kwargs):
- kwargs['name'] = 'link#%s' % kwargs.get('name')
- super(EntityLinkField, self).__init__(link=True, **kwargs)
-
-
-class UIMessageType(object):
- Fatal = "FatalError"
- Partial = "PartialError"
- Inform = "Inform"
- Debug = "Debug"
-
-
-@XMLAttribute(name='MessageType', propname='type', default=UIMessageType.Inform)
-class UIMessage(MaltegoElement):
-
- def __init__(self, message, **kwargs):
- super(UIMessage, self).__init__(self.__class__.__name__)
- self.type = kwargs.get('type', self.type)
- self.text = str(message) if not isinstance(message, basestring) else message
-
-
-@XMLSubElement(name='Value', propname='value')
-@XMLSubElement(name='Weight', propname='weight', type=XSSubElementType.Integer, default=1)
-@XMLSubElement(name='IconURL', propname='iconurl')
-@XMLSubElement(name='AdditionalFields', propname='fields', type=XSSubElementType.List)
-@XMLSubElement(name='DisplayInformation', propname='labels', type=XSSubElementType.List)
-@XMLSubElement(name='Value', propname='value')
-@XMLAttribute(name='Type', propname='type')
-@EntityField(name='notes#', propname='notes', link=True, matchingrule=MatchingRule.Loose)
-@EntityField(name='bookmark#', propname='bookmark', type=EntityFieldType.Integer, matchingrule=MatchingRule.Loose,
- link=True)
-@EntityLinkField(name='maltego.link.label', propname='linklabel', matchingrule=MatchingRule.Loose)
-@EntityLinkField(name='maltego.link.style', propname='linkstyle', matchingrule=MatchingRule.Loose,
- type=EntityFieldType.Integer)
-@EntityLinkField(name='maltego.link.show-label', propname='linkshowlabel', matchingrule=MatchingRule.Loose,
- type=EntityFieldType.Enum, choices=[0, 1])
-@EntityLinkField(name='maltego.link.color', propname='linkcolor', matchingrule=MatchingRule.Loose)
-@EntityLinkField(name='maltego.link.thickness', propname='linkthickness', matchingrule=MatchingRule.Loose,
- type=EntityFieldType.Integer)
-class Entity(MaltegoElement):
-
- namespace = 'maltego'
- name = None
-
- def __init__(self, value, **kwargs):
- super(Entity, self).__init__("Entity")
- type = kwargs.pop('type', None)
- if type is None:
- self.type = '%s.%s' % (self.namespace, (self.__class__.__name__ if self.name is None else self.name))
- else:
- self.type = type
- self.value = value
- self.weight = kwargs.pop('weight', self.weight)
- self.iconurl = kwargs.pop('iconurl', self.iconurl)
- self.appendelements(kwargs.pop('fields', None))
- self.appendelements(kwargs.pop('labels', None))
- for p in kwargs:
- if hasattr(self, p):
- setattr(self, p, kwargs[p])
-
- def appendelement(self, other):
- if isinstance(other, Field):
-# display_name = other.get('DisplayName')
-# if display_name is None:
-# name = other.get('Name')
-# if name in self.fields.keys():
-# other.set('DisplayName', self.fields[name])
- self.fields += other
- elif isinstance(other, Label):
- self.labels += other
-
- def removeelement(self, other):
- if isinstance(other, Field):
- self.fields -= other
- elif isinstance(other, Label):
- self.labels -= other
-
-
-
-
-
+++ /dev/null
-#!/usr/bin/env python
-
-from message import MaltegoMessage, Message, MaltegoTransformExceptionMessage, MaltegoException
-
-from signal import signal, SIGTERM, SIGINT
-from sys import exit, argv, stderr, stdout
-from cStringIO import StringIO
-from re import split, sub, search
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-__all__ = [
- 'onterminate',
- 'message',
- 'croak',
- 'parseargs',
- 'debug',
- 'progress'
-]
-
-
-def onterminate(func):
- """Register a signal handler to execute when Maltego forcibly terminates the transform."""
- signal(SIGTERM, func)
- signal(SIGINT, func)
-
-
-def message(m, fd=stdout):
- """Write a MaltegoMessage to stdout and exit successfully"""
- sio = StringIO()
- m.entities
- Message(MaltegoMessage(m)).write(sio)
- v = sio.getvalue()
- # Get rid of those nasty unicode 32 characters
- fd.write(sub(r'(&#\d{5};){2}', r'', v))
- exit(0)
-
-
-def croak(error_msg):
- """Throw an exception in the Maltego GUI containing error_msg."""
- Message(MaltegoMessage(MaltegoTransformExceptionMessage(exceptions=MaltegoException(error_msg)))).write()
- exit(0)
-
-
-def parseargs(args=argv):
- """Parse arguments for Maltego local transforms."""
-
- if len(args) < 3:
- stderr.write('usage: %s <transform> [param1 ... paramN] <value> [field1=value1...#fieldN=valueN]\n' % args[0])
- exit(-1)
-
- arg_script = args[1]
- arg_field = args[-1] if search(r'(?<=[^\\])=', args[-1]) is not None else None
- arg_value = (args[-1] if arg_field is None else args[-2]).replace('\=', '=')
- arg_param = []
-
- if arg_field is None and len(args) > 3:
- arg_param = list(args[2:-1])
- elif arg_field is not None and len(args) > 4:
- arg_param = list(args[2:-2])
-
- fields = {}
- if arg_field is not None:
- fs = split(r'(?<=[^\\])#', arg_field)
- if fs is not None:
- fields = dict(
- map(
- lambda x: [
- c.replace('\#', '#').replace('\=', '=').replace('\\\\', '\\')
- for c in split(r'(?<=[^\\])=', x, 1)
- ],
- fs
- )
- )
-
- return arg_script, arg_param, arg_value, fields
-
-
-def debug(*args):
- """Send debug messages to the Maltego console."""
- for i in args:
- stderr.write('D:%s\n' % str(i))
-
-
-def progress(i):
- """Send a progress report to the Maltego console."""
- stderr.write('%%%d\n' % min(max(i, 0), 100))
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-from utils.stack import modulecallee
-
-from imghdr import what
-from pkg_resources import resource_filename, resource_listdir, resource_isdir
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.3'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-etc = 'canari.resources.etc'
-
-
-def imageicon(pkg, name):
- name = resource_filename(pkg, name)
- if name[0] != '/':
- return 'file:///%s' % name
- return 'file://%s' % name
-
-
-def imagepath(pkg, name):
- return '%s' % resource_filename(pkg, name)
-
-
-def external_resource(name, pkg=None):
- if pkg is None:
- pkg = '%s.resources.external' % modulecallee().__name__.split('.')[0]
- return resource_filename(pkg, name)
-
-
-def image_resource(name, pkg=None):
- if pkg is None:
- pkg = '%s.resources.images' % modulecallee().__name__.split('.')[0]
- return imagepath(pkg, name)
-
-
-def icon_resource(name, pkg=None):
- if pkg is None:
- pkg = '%s.resources.images' % modulecallee().__name__.split('.')[0]
- return imageicon(pkg, name)
-
-
-def image_resources(pkg=None, dir='resources'):
- if pkg is None:
- pkg = modulecallee().__name__.split('.')[0]
- pkg_dir = '%s.%s' % (pkg, dir)
- images = []
- for i in resource_listdir(pkg, dir):
- fname = resource_filename(pkg_dir, i)
- if resource_isdir(pkg_dir, i):
- images.extend(image_resources(pkg_dir, i))
- elif what(fname) is not None:
- images.append(fname)
- return images
-
-# etc
-conf = resource_filename(etc, 'canari.conf')
+++ /dev/null
-#!/usr/bin/env python
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-__all__ = [
- 'images',
- 'etc',
- 'tds',
- 'template'
-]
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
\ No newline at end of file
+++ /dev/null
-[default]
-# Additional config files that should be read to merge with the current config
-configs =
-
-# Additional exec paths (comma separated)
-path = ${PATH},/usr/local/bin,/opt/local/bin
-
-[remote]
-# Specify any transforms that your WSGI container will host. This is for Plume ONLY.
-modules =
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-# Builtin imports
-from xml.etree.cElementTree import fromstring
-from ConfigParser import NoSectionError
-from cStringIO import StringIO
-from urlparse import urljoin
-import importlib
-import hashlib
-import sys
-import os
-import re
-
-# Third-party imports
-from flask import Flask, Response, request
-
-# Canari imports
-import canari.config as _config
-from canari.commands.common import get_transform_version
-from canari.maltego.message import (Message, MaltegoMessage, MaltegoTransformRequestMessage,
- MaltegoTransformResponseMessage, MaltegoTransformExceptionMessage, MaltegoException)
-from canari.resource import image_resources
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-class Canari(Flask):
- def __init__(self, import_name):
- super(Canari, self).__init__(import_name)
- self.transforms = {}
- self._initialize()
-
- def _copy_images(self, pkg):
- if pkg.endswith('.transforms'):
- pkg = pkg.replace('.transforms', '')
- for i in image_resources(pkg):
- dname = 'static/%s' % hashlib.md5(i).hexdigest()
- if not os.path.exists(dname):
- with file(i, mode='rb') as src:
- with open(dname, mode="wb") as dst:
- dst.write(src.read())
-
- def _initialize(self):
- # Flask application container reload hack.
- reload(_config)
-
- packages = None
-
- # Read modules that are to be loaded at runtime
- try:
- packages = _config.config['remote/modules']
- except NoSectionError:
- sys.stderr.write('Exiting... You did not specify a [remote] section and a "modules" option in your canari.conf file!')
- exit(-1)
-
- # Is packages not blank
- if not packages:
- sys.stderr.write('Exiting... You did not specify any transform modules to load in your canari.conf file!')
- exit(-1)
- elif isinstance(packages, basestring):
- packages = [packages]
-
- # Create the static directory for static file loading
- if not os.path.exists('static'):
- os.mkdir('static', 0755)
-
- # Iterate through the list of packages to load
- for p in packages:
- # Copy all the image resource files in case they are used as entity icons
- self._copy_images(p)
-
- if not p.endswith('.transforms'):
- p = ('%s.transforms' % p)
-
- sys.stderr.write('Loading transform package %s\n' % repr(p))
-
- # Load our first transform package
- m = importlib.import_module(p)
-
- for t in m.__all__:
- t = ('%s.%s' % (p, t))
-
- # Let's import our transforms one by one
- m2 = importlib.import_module(t)
- if not hasattr(m2, 'dotransform'):
- continue
-
- # Should the transform be publicly available?
- if hasattr(m2.dotransform, 'remote') and m2.dotransform.remote:
- sys.stderr.write('Loading transform %s at /%s...\n' % (repr(t), t))
- # Does it conform to V2 of the Canari transform signature standard?
- if get_transform_version(m2.dotransform) == 2:
- sys.stderr.write('Plume does not support V2 Canari transforms (%s). Please update to V3. '
- 'See http://www.canariproject.com/plume for details.\n' % repr(t))
- exit(-1)
- # Does the transform need to be executed as root? If so, is this running in mod_wsgi? Yes = Bad!
- elif os.name == 'posix' and hasattr(m2.dotransform, 'privileged') and\
- os.geteuid() and __name__.startswith('_mod_wsgi_'):
- sys.stderr.write('Warning, mod_wsgi does not allow applications to run with root privileges. '
- 'Transform %s ignored...\n' % repr(t))
- continue
- # So everything is good, let's register our transform with the global transform registry.
- if hasattr(m2.dotransform, 'inputs'):
- inputs = [e[1]('').type for e in m2.dotransform.inputs]
- inputs = inputs + [i.split('.')[-1] for i in inputs]
- self.transforms[t] = (m2.dotransform, inputs)
- else:
- self.transforms[t] = (m2.dotransform, [])
-
-
-# Create our Flask app.
-app = Canari(__name__)
-
-def croak(error_msg):
- """Throw an exception in the Maltego GUI containing error_msg."""
- s = StringIO()
- Message(
- MaltegoMessage(
- MaltegoTransformExceptionMessage(exceptions=MaltegoException(error_msg)
- )
- )
- ).write(file=s)
- return s.getvalue()
-
-
-def message(m):
- """Write a MaltegoMessage to stdout and exit successfully"""
- v = None
- if isinstance(m, basestring):
- # Let's make sure that we're not spewing out local file system information ;)
- for url in re.findall("<iconurl>\s*(file://[^\s<]+)\s*</iconurl>(?im)", m):
- path = 'static/%s' % hashlib.md5(url[7:]).hexdigest()
- new_url = urljoin(request.host_url, path)
- m.replace(url, new_url, 1)
- v = m
- else:
- sio = StringIO()
- # Let's make sure that we're not spewing out local file system information ;)
- for e in m.entities:
- if e.iconurl is not None:
- e.iconurl = e.iconurl.strip()
- if e.iconurl.startswith('file://'):
- path = 'static/%s' % hashlib.md5(e.iconurl[7:]).hexdigest()
- new_url = urljoin(request.host_url, path)
- e.iconurl = new_url
-
- Message(MaltegoMessage(m)).write(sio)
- v = sio.getvalue()
- # Get rid of those nasty unicode 32 characters
- return Response(re.sub(r'(&#\d{5};){2}', r'', v), status=200, mimetype='text/html')
-
-
-def dotransform(t):
- try:
- # Get the body of the request
- request_str = request.data
-
- # Let's get an XML object tree
- xml = fromstring(request_str).find('MaltegoTransformRequestMessage')
-
- # Get the entity being passed in.
- e = xml.find('Entities/Entity')
- etype = e.get('Type', '')
-
- if t[1] and etype not in t[1]:
- return Response(status=404)
-
- # Initialize Maltego Request values to pass into transform
- value = e.find('Value').text or ''
- fields = dict([(f.get('Name', ''), f.text) for f in xml.findall('Entities/Entity/AdditionalFields/Field')])
- params = dict([(f.get('Name', ''), f.text) for f in xml.findall('TransformFields/Field')])
- limits = xml.find('Limits').attrib
-
- # Initialize a private copy of the config to pass into the transform
- config = _config.CanariConfigParser()
- for k, i in params.items():
- if '.' in k:
- config[k.replace('.', '/', 1)] = i
- else:
- config['default/%s' % k] = i
- # The private config variables CANNOT override the server's settings. This is for security?
- config._sections.update(_config.config._sections)
-
- # Execute it!
- msg = t[0](
- MaltegoTransformRequestMessage(value, fields, params, limits),
- request_str if hasattr(t[0], 'cmd') and callable(t[0].cmd) else MaltegoTransformResponseMessage(),
- config
- )
-
- # Let's serialize the return response and clean up whatever mess was left behind
- if isinstance(msg, MaltegoTransformResponseMessage) or isinstance(msg, basestring):
- return message(msg)
- else:
- raise MaltegoException('Could not resolve message type returned by transform.')
-
- # Unless we croaked somewhere, then we need to fix things up here...
- except MaltegoException, me:
- return croak(str(me))
- except Exception, e:
- return croak(str(e))
-
-
-# This is where the TDS will ask: "Are you a transform?" and we say "200 - Yes I am!" or "404 - PFO"
-@app.route('/<transform>', methods=['GET'])
-def transform_checker(transform):
- if transform not in app.transforms:
- return Response(status=404)
- return Response(status=200)
-
-
-# This is where we process a transform request.
-@app.route('/<transform>', methods=['POST'])
-def transform_runner(transform):
- if transform not in app.transforms:
- return Response(status=400)
- return dotransform(app.transforms[transform])
-
-
-# Finally, if you want to run Flask standalone for debugging, just type python plume.py and you're off to the races!
-if __name__ == '__main__':
- app.run(debug=True)
+++ /dev/null
-#!/usr/bin/python
-
-import tempfile
-import sys
-import os
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-# Import modules relative to where this script is if necessary
-my_location = os.path.dirname(__file__)
-os.chdir(my_location)
-sys.path.append(my_location)
-
-# Use temporary directory as Python Egg Cache
-os.environ['PYTHON_EGG_CACHE'] = tempfile.gettempdir()
-
-# Import our Flask app
-from plume import app as application
+++ /dev/null
-include *.md
-recursive-include src *.py *.conf *.gif *.png *.mtz *.machine
-recursive-include maltego *.mtz
+++ /dev/null
-# README - ${project}
-
-Welcome to Canari. You might be wondering what all these files are about. Before you can use the power of
-`canari install-package` you needed to create a transform package and that's exactly what you did here! I've given you a
-directory structure to use in the following manner:
-
-* `src/${package}` directory is where all your stuff goes in terms of auxiliary modules that you may need for your
- modules
-* `src/${package}/transforms` directory is where all your transform modules should be placed. An example
- `helloworld` transform is there for your viewing pleasure.
-* `src/${package}/transforms/common` directory is where you can put some common code for your transforms like result
- parsing, entities, etc.
-* `src/${package}/transforms/common/entities.py` is where you define your custom entities. Take a look at the
- examples provided if you want to play around with custom entities.
-* `maltego/` is where you can store your Maltego entity exports.
-* `src/${package}/resources/maltego` directory is where your `entities.mtz` and `*.machine` files can be stored for auto
- install and uninstall.
-* `src/${package}/resources/external` directory is where you can place non-Python transforms written in other languages.
-
-If you're going to add a new transform in the transforms directory, remember to update the `__all__` variable in
-`src/${package}/transforms/__init__.py`. Otherwise, `canari install-package` won't attempt to install the transform.
-Alternatively, `canari create-transform <transform name>` can be used within the `src/${package}/transforms` directory
-to generate a transform module and have it automatically added to the `__init__.py` file, like so:
-
-To test your transform, simply `cd` into the src directory and run `canari debug-transform`, like so:
-
-```bash
-$$ canari debug-transform ${project}.transforms.helloworld Phil
-%50
-D:This was pointless!
-%100
-`- MaltegoTransformResponseMessage:
- `- Entities:
- `- Entity: {'Type': 'test.MyTestEntity'}
- `- Value: Hello Phil!
- `- Weight: 1
- `- AdditionalFields:
- `- Field: 2 {'DisplayName': 'Field 1', 'Name': 'test.field1', 'MatchingRule': 'strict'}
- `- Field: test {'DisplayName': 'Field N', 'Name': 'test.fieldN', 'MatchingRule': 'strict'}
-```
-
-Cool right? If you have any further questions don't hesitate to drop us a line;)
-
-Have fun!
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-__author__ = '${author}'
-__copyright__ = 'Copyright ${year}, ${project} Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = '${author}'
-__email__ = '${email}'
-__status__ = 'Development'
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
\ No newline at end of file
+++ /dev/null
-[metadata]
-
-author = ${author}
-project = ${project}
-maintainer = ${maintainer}
-email = ${email}
+++ /dev/null
-# This was generated by running: $command
-# If you'd like to override any of the default settings for this package just go ahead and change em below!
-
-[default]
-# Additional config files that should be read to merge with the current config
-configs = $config
-
-path = $path
\ No newline at end of file
+++ /dev/null
-[section1]
-
-option1 = this, is, a, list
-
-option2 = this\, is\, a\, comma-separated string
-
-
-[section2]
-
-etc = etc
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-from canari.maltego.message import Entity, EntityField, EntityFieldType, MatchingRule
-
-__author__ = '${author}'
-__copyright__ = 'Copyright ${year}, ${project} Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = '${author}'
-__email__ = '${email}'
-__status__ = 'Development'
-
-__all__ = [
- '${base_entity}',
- '${entity}'
-]
-
-"""
-DO NOT EDIT:
-The following entity is the base entity type from which all your entities will inherit from. This provides you with the
-default namespace that all your entities will use for their unique entity type in Maltego. For example, ${entity} will
-have an entity type name of ${namespace}.${entity}. When adding a new entity in Maltego, you will have to specify this
-name (${namespace}.${entity}) in the 'Unique entity type' field.
-"""
-class ${base_entity}(Entity):
- namespace = '${namespace}'
-
-
-"""
-You can specify as many entity fields as you want by just adding an extra @EntityField() decorator to your entities. The
-@EntityField() decorator takes the following parameters:
- - name: the name of the field without spaces or special characters except for dots ('.') (required)
- - propname: the name of the object's property used to get and set the value of the field (required, if name contains dots)
- - displayname: the name of the entity as it appears in Maltego (optional)
- - type: the data type of the field (optional, default: EntityFieldType.String)
- - required: whether or not the field's value must be set before sending back the message (optional, default: False)
- - choices: a list of acceptable field values for this field (optional)
- - matchingrule: whether or not the field should be loosely or strictly matched (optional, default: MatchingRule.Strict)
- - decorator: a function that is invoked each and everytime the field's value is set or changed.
-TODO: define as many custom fields and entity types as you wish:)
-"""
-@EntityField(name='${package}.fieldN', propname='fieldN', displayname='Field N', matchingrule=MatchingRule.Loose)
-@EntityField(name='${package}.field1', propname='field1', displayname='Field 1', type=EntityFieldType.Integer)
-class ${entity}(${base_entity}):
- """
- Uncomment the line below and comment out the pass if you wish to define a ridiculous entity type name like
- 'my.fancy.EntityType'
- """
- # name = my.fancy.EntityType
- pass
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-from canari.maltego.utils import debug, progress
-from canari.framework import configure #, superuser
-
-__author__ = '${author}'
-__copyright__ = 'Copyright ${year}, ${project} Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = '${maintainer}'
-__email__ = '${email}'
-__status__ = 'Development'
-
-__all__ = [
- 'dotransform',
- 'onterminate'
-]
-
-
-"""
-TODO: set the appropriate configuration parameters for your transform.
-TODO: Uncomment the line below if the transform needs to run as super-user
-"""
-#@superuser
-@configure(
- label='TODO: To Something [Hello World]',
- description='TODO: Returns a Something entity with the phrase "Hello Word!"',
- uuids=[ 'TODO something.v2.SomethingToPhrase_HelloWorld' ],
- inputs=[ ( 'TODO: Some Set', SomethingEntity ) ],
- debug=True
-)
-def dotransform(request, response):
- """
- TODO: write your data mining logic below.
- """
- return response
-
-
-def onterminate():
- """
- TODO: Write your cleanup logic below or delete the onterminate function and remove it from the __all__ variable
- """
- pass
\ No newline at end of file
+++ /dev/null
-from setuptools import setup, find_packages
-
-setup(
- name='${package}',
- author='${author}',
- version='1.0',
- author_email='${email}',
- description='${description}',
- license='GPL',
- packages=find_packages('src'),
- package_dir={ '' : 'src' },
- zip_safe=False,
- package_data={
- '' : [ '*.gif', '*.png', '*.conf', '*.mtz', '*.machine' ] # list of resources
- },
- install_requires=[
- 'canari'
- ],
- dependency_links=[
- # custom links for the install_requires
- ]
-)
+++ /dev/null
-#!/usr/bin/env python
-
-from canari.maltego.entities import Person
-from canari.maltego.utils import debug, progress
-from canari.framework import configure #, superuser
-from common.entities import ${entity}
-
-__author__ = '${author}'
-__copyright__ = 'Copyright ${year}, ${project} Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = '${author}'
-__email__ = '${email}'
-__status__ = 'Development'
-
-__all__ = [
- 'dotransform',
- 'onterminate'
-]
-
-# Uncomment the line below if the transform needs to run as super-user
-#@superuser
-"""
-The @configure decorator tells mtginstall how to install the transform in Maltego. It takes the following parameters:
- - label: the name of the transform as it appears in the Maltego UI transform selection menu
- - description: a short description of the transform
- - uuids: a list of unique transform IDs, one per input type. The order of this list must match that of the
- inputs parameter. Make sure you account for entity type inheritance in Maltego. For example, if you
- choose a DNSName entity type as your input type you do not need to specify it again for MXRecord,
- NSRecord, etc.
- - inputs: a list of tuples where the first item is the name of the transform set the transform should be part
- of, and the second item is the input entity type.
- - debug: Whether or not the debugging window should appear in Maltego's UI when running the transform.
-TODO: set the appropriate configuration parameters for your transform.
-"""
-@configure(
- label='To ${entity} [Hello World]',
- description='Returns a ${entity} entity with the phrase "Hello Word!"',
- uuids=[ '${namespace}.v2.${entity}ToPhrase_HelloWorld' ],
- inputs=[ ( '${project}', Person ) ],
- debug=True
-)
-def dotransform(request, response):
- """
- The dotransform function is our transform's entry point. The request object has the following properties:
- - value: a string containing the value of the input entity.
- - fields: a dictionary of entity field names and their respective values of the input entity.
- - params: any additional command-line arguments to be passed to the transform.
- TODO: write your data mining logic below.
- """
-
- # Report transform progress
- progress(50)
- # Send a debugging message to the Maltego UI console
- debug('This was pointless!')
-
- # Create ${entity} entity with value set to 'Hello <request.value>!'
- e = ${entity}('Hello %s!' % request.value)
- # Setting field values on the entity
- e.field1 = 2
- e.fieldN = 'test'
- # Update progress
- progress(100)
-
- # Add entity to response object
- response += e
-
- # Return response for visualization
- return response
-
-
-"""
-Called if transform interrupted. It's presence is optional; you can remove this function if you don't need to do any
-resource clean up.
-
-TODO: Write your cleanup logic below or delete the onterminate function and remove it from the __all__ variable
-"""
-def onterminate():
- debug('Caught signal... exiting.')
- exit(0)
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-__all__ = [
- 'fs',
- 'wordlist'
-]
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-import os
-
-from tempfile import gettempdir
-from sys import maxint
-from time import time
-
-if os.name == 'nt':
- import msvcrt
- from ctypes import *
- from ctypes.wintypes import BOOL, DWORD, HANDLE
-
- LOCK_SH = 0x0 # the default
- LOCK_NB = 0x1 # LOCKFILE_FAIL_IMMEDIATELY
- LOCK_EX = 0x2 # LOCKFILE_EXCLUSIVE_LOCK
- LOCK_UN = 0x4 # Unlock file. Not in NT API, just needs to be there.
-
- # --- the code is taken from pyserial project ---
- #
- # detect size of ULONG_PTR
- def is_64bit():
- return sizeof(c_ulong) != sizeof(c_void_p)
- if is_64bit():
- ULONG_PTR = c_int64
- else:
- ULONG_PTR = c_ulong
- PVOID = c_void_p
-
- # --- Union inside Structure by stackoverflow:3480240 ---
- class _OFFSET(Structure):
- _fields_ = [
- ('Offset', DWORD),
- ('OffsetHigh', DWORD)]
-
- class _OFFSET_UNION(Union):
- _anonymous_ = ['_offset']
- _fields_ = [
- ('_offset', _OFFSET),
- ('Pointer', PVOID)]
-
- class OVERLAPPED(Structure):
- _anonymous_ = ['_offset_union']
- _fields_ = [
- ('Internal', ULONG_PTR),
- ('InternalHigh', ULONG_PTR),
- ('_offset_union', _OFFSET_UNION),
- ('hEvent', HANDLE)]
-
- LPOVERLAPPED = POINTER(OVERLAPPED)
-
- # --- Define function prototypes for extra safety ---
- LockFileEx = windll.kernel32.LockFileEx
- LockFileEx.restype = BOOL
- LockFileEx.argtypes = [HANDLE, DWORD, DWORD, DWORD, DWORD, LPOVERLAPPED]
- UnlockFileEx = windll.kernel32.UnlockFileEx
- UnlockFileEx.restype = BOOL
- UnlockFileEx.argtypes = [HANDLE, DWORD, DWORD, DWORD, LPOVERLAPPED]
-else:
- from fcntl import flock, LOCK_EX, LOCK_NB, LOCK_SH, LOCK_UN
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = [ 'Jonathan Feinberg' ]
-
-__license__ = 'GPL'
-__version__ = '0.2'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-__all__ = [
- 'cookie',
- 'flock',
- 'fsemaphore',
- 'fmutex',
- 'ufile',
- 'age'
-]
-
-
-if os.name == 'nt':
- def flock(file, flags):
- hfile = msvcrt.get_osfhandle(file.fileno())
- overlapped = OVERLAPPED()
- if flags & LOCK_UN and UnlockFileEx(hfile, 0, 0, 0xFFFF0000, byref(overlapped)):
- return
- elif (not flags or flags & (LOCK_EX | LOCK_NB | LOCK_SH)) and \
- LockFileEx(hfile, flags, 0, 0, 0xFFFF0000, byref(overlapped)):
- return
- raise IOError(GetLastError())
-
-
-def cookie(name):
- return os.path.join(gettempdir(), name)
-
-
-class fsemaphore(file):
-
- def __init__(self, name, mode='rb', buffering=-1):
- super(fsemaphore, self).__init__(name, mode, buffering)
-
- def lockex(self, nb=False):
- flags = LOCK_EX
- if nb:
- flags |= LOCK_NB
- flock(self, flags)
-
- def locksh(self, nb=False):
- flags = LOCK_SH
- if nb:
- flags |= LOCK_NB
- flock(self, flags)
-
- def unlock(self, nb=False):
- flags = LOCK_UN
- if nb:
- flags |= LOCK_NB
- flock(self, flags)
-
-
-class fmutex(fsemaphore):
-
- def __init__(self, name):
- super(fmutex, self).__init__(cookie(name), 'wb')
- self.lockex()
-
- def __del__(self):
- self.unlock()
-
-
-class ufile(file):
-
- def __init__(self, name):
- if os.path.exists(name):
- p, n = os.path.split(name)
- n, e = os.path.splitext(n)
-
- for i in xrange(2, maxint):
- name = os.path.join(p, '%s(%d)%s') % (n, i, e)
- if not os.path.exists(name):
- break
- super(ufile, self).__init__(name, mode='wb')
-
-
-def age(path):
- return time() - os.stat(path).st_mtime
+++ /dev/null
-#!/usr/bin/env python
-
-from inspect import stack, getmodule
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-__all__ = [
- 'modulecallee'
-]
-
-def modulecallee(atframe=2):
- frame = stack()[atframe]
- return getmodule(frame[0])
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-from zlib import decompress, MAX_WBITS
-from re import findall, search, sub
-from urllib import urlopen
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.2'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-__all__ = [
- 'wordlist'
-]
-
-
-def wordlist(uri, match='(.*?)\n+', ignore='^#.*', strip=None):
- if isinstance(uri, basestring):
- l = []
- if not uri:
- return l
- data = urlopen(uri).read()
- if search('\.gz(ip)?$', uri) is not None:
- data = decompress(data, 16 + MAX_WBITS)
- if data:
- l = findall(match, data)
- if ignore is not None:
- l = filter(lambda x: search(ignore, x) is None, l)
- if strip is not None:
- l = map(lambda x: sub(strip, '', x), l)
- return l
- return uri
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-__all__ = [
- 'objectify',
- 'oxml'
-]
\ No newline at end of file
+++ /dev/null
-#
-# ElementTree
-# $Id: ElementPath.py 3375 2008-02-13 08:05:08Z fredrik $
-#
-# limited xpath support for element trees
-#
-# history:
-# 2003-05-23 fl created
-# 2003-05-28 fl added support for // etc
-# 2003-08-27 fl fixed parsing of periods in element names
-# 2007-09-10 fl new selection engine
-# 2007-09-12 fl fixed parent selector
-# 2007-09-13 fl added iterfind; changed findall to return a list
-# 2007-11-30 fl added namespaces support
-# 2009-10-30 fl added child element value filter
-#
-# Copyright (c) 2003-2009 by Fredrik Lundh. All rights reserved.
-#
-# fredrik@pythonware.com
-# http://www.pythonware.com
-#
-# --------------------------------------------------------------------
-# The ElementTree toolkit is
-#
-# Copyright (c) 1999-2009 by Fredrik Lundh
-#
-# 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, 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 used in advertising or publicity
-# pertaining to distribution of the software without specific, written
-# prior permission.
-#
-# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
-# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
-# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
-# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
-# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
-# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
-# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
-# OF THIS SOFTWARE.
-# --------------------------------------------------------------------
-
-# Licensed to PSF under a Contributor Agreement.
-# See http://www.python.org/psf/license for licensing details.
-
-##
-# Implementation module for XPath support. There's usually no reason
-# to import this module directly; the <b>ElementTree</b> does this for
-# you, if needed.
-##
-import xml.etree.ElementPath as EP
-import re
-
-EP.xpath_tokenizer_re = xpath_tokenizer_re = re.compile(
- "("
- "'[^']*'|\"[^\"]*\"|"
- "::|"
- "//?|"
- "\.\.|"
- "\(\)|"
- "[/.*:\[\]\(\)@=])|"
- "((?:\{[^}]+\})?[^/\[\]\(\)@=\s]+)|"
- "\s+"
- )
-
-def xpath_tokenizer(pattern, namespaces=None):
- for token in xpath_tokenizer_re.findall(pattern):
- tag = token[1]
- if tag and tag[0] != "{" and ":" in tag:
- try:
- prefix, uri = tag.split(":", 1)
- if not namespaces:
- raise KeyError
- yield token[0], "{%s}%s" % (namespaces[prefix], uri)
- except KeyError:
- raise SyntaxError("prefix %r not found in prefix map" % prefix)
- else:
- yield token
-
-EP.xpath_tokenizer = xpath_tokenizer
-
-def get_parent_map(context):
- parent_map = context.parent_map
- if parent_map is None:
- context.parent_map = parent_map = {}
- for p in context.root.iter():
- for e in p:
- parent_map[e] = p
- return parent_map
-
-EP.get_parent_map = get_parent_map
-
-def prepare_child(next, token):
- tag = token[1]
- def select(context, result):
- for elem in result:
- for e in elem:
- if e.tag == tag:
- yield e
- return select
-
-EP.prepare_child = prepare_child
-
-def prepare_star(next, token):
- def select(context, result):
- for elem in result:
- for e in elem:
- yield e
- return select
-
-EP.prepare_star = prepare_star
-
-def prepare_self(next, token):
- def select(context, result):
- for elem in result:
- yield elem
- return select
-
-EP.prepare_self = prepare_self
-
-def prepare_descendant(next, token):
- token = next()
- if token[0] == "*":
- tag = "*"
- elif not token[0]:
- tag = token[1]
- else:
- raise SyntaxError("invalid descendant")
- def select(context, result):
- for elem in result:
- for e in elem.iter(tag):
- if e is not elem:
- yield e
- return select
-
-EP.prepare_descendant = prepare_descendant
-
-def prepare_parent(next, token):
- def select(context, result):
- # FIXME: raise error if .. is applied at toplevel?
- parent_map = get_parent_map(context)
- result_map = {}
- for elem in result:
- if elem in parent_map:
- parent = parent_map[elem]
- if parent not in result_map:
- result_map[parent] = None
- yield parent
- return select
-
-EP.prepare_parent = prepare_parent
-
-def prepare_predicate(next, token):
- # FIXME: replace with real parser!!! refs:
- # http://effbot.org/zone/simple-iterator-parser.htm
- # http://javascript.crockford.com/tdop/tdop.html
- signature = []
- predicate = []
- while 1:
- token = next()
- if token[0] == "]":
- break
- if token[0] and token[0][:1] in "'\"":
- token = "'", token[0][1:-1]
- signature.append(token[0] or "-")
- predicate.append(token[1])
- signature = "".join(signature)
- # use signature to determine predicate type
- if signature == "@-":
- # [@attribute] predicate
- key = predicate[1]
- def select(context, result):
- for elem in result:
- if elem.get(key) is not None:
- yield elem
- return select
- if signature == "@-='":
- # [@attribute='value']
- key = predicate[1]
- value = predicate[-1]
- def select(context, result):
- for elem in result:
- if elem.get(key) == value:
- yield elem
- return select
- if signature == "-" and not re.match("\d+$", predicate[0]):
- # [tag]
- tag = predicate[0]
- def select(context, result):
- for elem in result:
- if elem.find(tag) is not None:
- yield elem
- return select
- if signature == "-='" and not re.match("\d+$", predicate[0]):
- # [tag='value']
- tag = predicate[0]
- value = predicate[-1]
- def select(context, result):
- for elem in result:
- for e in elem.findall(tag):
- if "".join(e.itertext()) == value:
- yield elem
- break
- return select
- if signature == "-" or signature == "-()" or signature == "-()-":
- # [index] or [last()] or [last()-index]
- if signature == "-":
- index = int(predicate[0]) - 1
- else:
- if predicate[0] != "last":
- raise SyntaxError("unsupported function")
- if signature == "-()-":
- try:
- index = int(predicate[2]) - 1
- except ValueError:
- raise SyntaxError("unsupported expression")
- else:
- index = -1
- def select(context, result):
- parent_map = get_parent_map(context)
- for elem in result:
- try:
- parent = parent_map[elem]
- # FIXME: what if the selector is "*" ?
- elems = list(parent.findall(elem.tag))
- if elems[index] is elem:
- yield elem
- except (IndexError, KeyError):
- pass
- return select
- raise SyntaxError("invalid predicate")
-
-EP.prepare_predicate = prepare_predicate
-
-EP.ops = ops = {
- "": prepare_child,
- "*": prepare_star,
- ".": prepare_self,
- "..": prepare_parent,
- "//": prepare_descendant,
- "[": prepare_predicate,
- }
-
-EP._cache = _cache = {}
-
-class _SelectorContext:
- parent_map = None
- def __init__(self, root):
- self.root = root
-
-EP._SelectorContext = _SelectorContext
-# --------------------------------------------------------------------
-
-##
-# Generate all matching objects.
-
-def iterfind(elem, path, namespaces=None):
- # compile selector pattern
- if path[-1:] == "/":
- path = path + "*" # implicit all (FIXME: keep this?)
- try:
- selector = _cache[path]
- except KeyError:
- if len(_cache) > 100:
- _cache.clear()
- if path[:1] == "/":
- raise SyntaxError("cannot use absolute path on element")
- next = iter(xpath_tokenizer(path, namespaces)).next
- token = next()
- selector = []
- while 1:
- try:
- selector.append(ops[token[0]](next, token))
- except StopIteration:
- raise SyntaxError("invalid path")
- try:
- token = next()
- if token[0] == "/":
- token = next()
- except StopIteration:
- break
- _cache[path] = selector
- # execute selector pattern
- result = [elem]
- context = _SelectorContext(elem)
- for select in selector:
- result = select(context, result)
- return result
-
-EP.iterfind = iterfind
-
-##
-# Find first matching object.
-def find(elem, path, namespaces=None):
- try:
- return iterfind(elem, path, namespaces).next()
- except StopIteration:
- return None
-
-EP.find = find
-##
-def findall(elem, path, namespaces=None):
- return list(iterfind(elem, path, namespaces))
-
-EP.findall = findall
-##
-# Find text for first matching object.
-
-def findtext(elem, path, default=None, namespaces=None):
- try:
- elem = iterfind(elem, path, namespaces).next()
- return elem.text or ""
- except StopIteration:
- return default
-EP.findtext = findtext
+++ /dev/null
-#!/usr/bin/env python
-
-import xml.etree.ElementTree as ET
-from numbers import Number
-from copy import deepcopy
-from pickle import dumps
-from sys import stdout
-from re import sub
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-__all__ = [
- 'XSStringAttribute',
- 'XSEnumAttribute',
- 'XSIntegerAttribute',
- 'XSBooleanAttribute',
- 'XSFloatAttribute',
- 'XSLongAttribute',
- 'XSAttributeType',
- 'XMLAttribute',
- 'XSStringSubElement',
- 'XSCDataSubElement',
- 'XSEnumSubElement',
- 'XSIntegerSubElement',
- 'XSBooleanSubElement',
- 'XSFloatSubElement',
- 'XSLongSubElement',
- 'XSListSubElement',
- 'XSSubElementType',
- 'XMLSubElement',
- 'ElementTree',
- 'Element'
-]
-
-
-_e = ET.Element
-_se = ET.SubElement
-_eto = ET.ElementTree
-
-
-class XSStringAttribute(object):
-
- def __init__(self, name, default=None, required=False):
- self.name = name
- self.required = required
- if default is not None and not isinstance(default, basestring):
- default = str(default)
- self.default = default
-
- def __get__(self, obj, objtype):
- if self.default is not None:
- return obj.attrib.setdefault(self.name, self.default)
- return obj.attrib.get(self.name, None)
-
- def __set__(self, obj, val):
- if val is None:
- if self.default is None:
- if self.name in obj.attrib:
- del obj.attrib[self.name]
- else:
- obj.attrib[self.name] = self.default
- return
- elif not isinstance(val, basestring):
- val = str(val)
- obj.attrib[self.name] = val
-
-
-class XSEnumAttribute(XSStringAttribute):
-
- def __init__(self, name, choices, default=None, required=False):
- self.choices = [ str(c) if not isinstance(c, basestring) else c for c in choices ]
- super(XSEnumAttribute, self).__init__(name, default, required)
-
- def __set__(self, obj, val):
- if not isinstance(val, basestring):
- val = str(val)
- if val not in self.choices:
- raise ValueError('Expected one of %s (got %s instead)' % (self.choices, val))
- super(XSEnumAttribute, self).__set__(obj, val)
-
-
-class XSIntegerAttribute(XSStringAttribute):
-
- def __get__(self, obj, objtype):
- return int(super(XSIntegerAttribute, self).__get__(obj, objtype) or 0)
-
- def __set__(self, obj, val):
- if not isinstance(val, Number):
- raise TypeError('Expected an instance of int (got %s instance instead)' % type(val).__name__)
- super(XSIntegerAttribute, self).__set__(obj, val)
-
-
-class XSBooleanAttribute(XSStringAttribute):
-
- def __init__(self, name, default=False, required=False):
- super(XSBooleanAttribute, self).__init__(name, str(default).lower(), required)
-
- def __get__(self, obj, objtype):
- return super(XSBooleanAttribute, self).__get__(obj, objtype) == 'true'
-
- def __set__(self, obj, val):
- if not isinstance(val, bool):
- raise TypeError('Expected an instance of bool (got %s instance instead)' % type(val).__name__)
- super(XSBooleanAttribute, self).__set__(obj, str(val).lower())
-
-
-class XSFloatAttribute(XSStringAttribute):
-
- def __get__(self, obj, objtype):
- return float(super(XSFloatAttribute, self).__get__(obj, objtype) or 0)
-
- def __set__(self, obj, val):
- if not isinstance(val, Number):
- raise TypeError('Expected an instance of float (got %s instance instead)' % type(val).__name__)
- super(XSFloatAttribute, self).__set__(obj, val)
-
-
-class XSLongAttribute(XSStringAttribute):
-
- def __get__(self, obj, objtype):
- return long(super(XSLongAttribute, self).__get__(obj, objtype) or 0)
-
- def __set__(self, obj, val):
- if not isinstance(val, Number):
- raise TypeError('Expected an instance of float (got %s instance instead)' % type(val).__name__)
- super(XSLongAttribute, self).__set__(obj, val)
-
-
-class XSAttributeType(object):
- String = XSStringAttribute
- Float = XSFloatAttribute
- Integer = XSIntegerAttribute
- Enum = XSEnumAttribute
- Bool = XSBooleanAttribute
- Long = XSLongAttribute
-
-
-class XMLAttribute(object):
-
- def __init__(self, **kwargs):
- self.name = kwargs.get('name')
- if self.name is None:
- raise ValueError("Keyword argument 'name' is required.")
- self.property = kwargs.get('propname', sub('[^\w]+', '_', self.name))
- self.type = kwargs.get('type', XSAttributeType.String)
- self.default = kwargs.get('default', None)
- self.required = kwargs.get('required', False)
- self.choices = kwargs.get('choices')
-
- def __call__(self, cls):
- if self.type is XSAttributeType.Enum:
- setattr(cls, self.property, self.type(self.name, self.choices, self.default))
- else:
- setattr(cls, self.property, self.type(self.name, self.default))
- return cls
-
-
-class XSStringSubElement(object):
-
- def __init__(self, name, default=None):
- self.name = name
- if default is not None and not isinstance(default, basestring):
- default = str(default)
- self.default = default
-
- def __get__(self, obj, objtype):
- e = obj.find(self.name)
- if e is None:
- if self.default is None:
- return None
- e = obj.findelement(self.name)
- e.text = self.default
- return e.text
- if e.text is None and self.default is not None:
- e.text = self.default
- return e.text
-
- def __set__(self, obj, val):
- if val is None:
- e = obj.find(self.name)
- if e is not None:
- if self.default is None:
- obj.remove(e)
- else:
- e.text = self.default
- return
- if not isinstance(val, basestring):
- val = str(val)
- obj.findelement(self.name).text = val
-
-
-class XSCDataSubElement(XSStringSubElement):
-
- def __init__(self, name, default=None):
- super(XSCDataSubElement, self).__init__('%s/CDATA' % name, default)
-
-
-class XSEnumSubElement(XSStringSubElement):
-
- def __init__(self, name, choices, default=None):
- self.choices = [ str(c) if not isinstance(c, basestring) else c for c in choices ]
- super(XSEnumSubElement, self).__init__(name, default)
-
- def __set__(self, obj, val):
- if not isinstance(val, basestring):
- val = str(val)
- if val not in self.choices:
- raise ValueError('Expected one of %s (got %s instead)' % (self.choices, val))
- super(XSEnumSubElement, self).__set__(obj, val)
-
-
-class XSIntegerSubElement(XSStringSubElement):
-
- def __get__(self, obj, objtype):
- return int(super(XSIntegerSubElement, self).__get__(obj, objtype) or 0)
-
- def __set__(self, obj, val):
- if not isinstance(val, Number):
- raise TypeError('Expected an instance of int (got %s instance instead)' % type(val))
- super(XSIntegerSubElement, self).__set__(obj, val)
-
-
-class XSBooleanSubElement(XSStringSubElement):
-
- def __init__(self, name, default=False):
- super(XSBooleanSubElement, self).__init__(name, str(default).lower())
-
- def __get__(self, obj, objtype):
- return super(XSBooleanSubElement, self).__get__(obj, objtype) == 'true'
-
- def __set__(self, obj, val):
- if not isinstance(val, bool):
- raise TypeError('Expected an instance of bool (got %s instance instead)' % type(val))
- super(XSBooleanSubElement, self).__set__(obj, str(val).lower())
-
-
-class XSFloatSubElement(XSStringSubElement):
-
- def __get__(self, obj, objtype):
- return float(super(XSFloatSubElement, self).__get__(obj, objtype) or 0)
-
- def __set__(self, obj, val):
- if not isinstance(val, Number):
- raise TypeError('Expected an instance of float (got %s instance instead)' % type(val))
- super(XSFloatSubElement, self).__set__(obj, val)
-
-
-class XSLongSubElement(XSStringSubElement):
-
- def __get__(self, obj, objtype):
- return long(super(XSLongSubElement, self).__get__(obj, objtype) or 0)
-
- def __set__(self, obj, val):
- if not isinstance(val, Number):
- raise TypeError('Expected an instance of float (got %s instance instead)' % type(val))
- super(XSLongSubElement, self).__set__(obj, val)
-
-
-class XSListSubElement(object):
-
- def __init__(self, name):
- self.name = name
-
- def __get__(self, obj, objtype):
- return obj.findelement(self.name)
-
-
-class XSSubElementType(object):
- String = XSStringSubElement
- Float = XSFloatSubElement
- Integer = XSIntegerSubElement
- Enum = XSEnumSubElement
- Bool = XSBooleanSubElement
- Long = XSLongSubElement
- List = XSListSubElement
- CData = XSCDataSubElement
-
-
-class XMLSubElement(object):
-
- def __init__(self, **kwargs):
- self.name = kwargs.get('name')
- if self.name is None:
- raise ValueError("Keyword argument 'name' is required.")
- self.property = kwargs.get('propname', sub('[^\w]+', '_', self.name))
- self.type = kwargs.get('type', XSSubElementType.String)
- self.default = kwargs.get('default', None)
- self.required = kwargs.get('required', False)
- self.choices = kwargs.get('choices')
-
- def __call__(self, cls):
- if self.type is XSSubElementType.Enum:
- setattr(cls, self.property, self.type(self.name, self.choices, self.default))
- elif self.type is XSSubElementType.List:
- setattr(cls, self.property, self.type(self.name))
- else:
- setattr(cls, self.property, self.type(self.name, self.default))
- return cls
-
-
-class ElementTree(ET.ElementTree):
- if hasattr(ET.ElementTree, '_write'):
- def _write(self, file, node, encoding, namespaces):
- if node.tag is 'CDATA':
- if node.text is not None:
- text = node.text.encode(encoding)
- file.write('<![CDATA[%s]]>' % text)
- else:
- _eto._write(self, file, node, encoding, namespaces)
-
- def write(self, file=stdout, encoding='us-ascii'):
- _eto.write(self, file, encoding)
-
-if hasattr(ET, '_serialize_xml'):
- _orig_serialize_xml = ET._serialize_xml
-
- def _serialize_xml(write, elem, encoding, qnames, namespaces):
- if elem.tag == 'CDATA':
- elem.tag = None
- _orig_serialize_xml(write, elem, encoding, qnames, namespaces)
-
- ET._serialize_xml = _serialize_xml
-
-
-class Element(ET._ElementInterface, object):
-
- def __init__(self, tag='Element', attrib={}, **kwargs):
- attrib = attrib.copy()
- attrib.update(kwargs)
- super(Element, self).__init__(tag, attrib)
-
- def __add__(self, other):
- newobj = deepcopy(self)
- newobj += other
- return newobj
-
- def __iadd__(self, other):
- if isinstance(other, list):
- for o in other:
- self.appendelement(o)
- else:
- self.appendelement(other)
- return self
-
- appendelements = __iadd__
-
- def __sub__(self, other):
- newobj = deepcopy(self)
- newobj -= other
- return newobj
-
- def __isub__(self, other):
- if isinstance(other, list):
- for o in other:
- self.removeelement(o)
- else:
- self.removeelement(other)
- return self
-
- removeelements = __isub__
-
- def appendelement(self, other):
- self.append(other)
-
- def removeelement(self, other):
- self.remove(other)
-
- def findelement(self, name):
- e = self.find(name)
- if e is None:
- if '/' in name:
- path = name.split('/')
- e = self
- for p in path:
- ce = e.find(p)
- if ce is None:
- e = _se(e, p)
- else:
- e = _se(self, name)
- return e
-
- def makeelement(self, tag, attrib):
- return Element(tag, attrib)
-
- def __eq__(self, other):
- return dumps(self) == dumps(other)
+++ /dev/null
-#!/usr/bin/env python
-
-from canari.commands.common import get_commands
-from argparse import ArgumentParser
-
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-
-cmds = get_commands()
-
-def parse_args():
- parser = ArgumentParser(
- description='Centralized Canari Management System',
- add_help=False
- )
- parser.add_argument(
- 'command',
- metavar='<command>',
- choices=cmds,
- default='help',
- nargs='?',
- help='The name of the command you wish to run (%s).' % ', '.join(cmds),
- )
- args = parser.parse_known_args()
- return args
-
-
-def main():
- args = parse_args()
- cmds[args[0].command].run(args[1])
-
-
-if __name__ == '__main__':
- try:
- main()
- except KeyboardInterrupt:
- print('exiting...')
- pass
\ No newline at end of file
+++ /dev/null
-@python %~dp0\canari %*
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-from canari.commands.run_transform import run
-
-from sys import argv
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.1'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-if __name__ == '__main__':
- run(argv[1:])
\ No newline at end of file
+++ /dev/null
-@python %~dp0\dispatcher %*
\ No newline at end of file
+++ /dev/null
-#!/usr/bin/env python
-
-import sys
-import subprocess
-import getpass
-
-from canari.utils.fs import fmutex
-from canari.easygui import passwordbox
-
-__author__ = 'Nadeem Douba'
-__copyright__ = 'Copyright 2012, Canari Project'
-__credits__ = []
-
-__license__ = 'GPL'
-__version__ = '0.5'
-__maintainer__ = 'Nadeem Douba'
-__email__ = 'ndouba@gmail.com'
-__status__ = 'Development'
-
-
-def main():
-
- if not sys.argv[1:]:
- print 'usage: %s <command>' % sys.argv[0]
- exit(-1)
-
- # Let's try and run it right away and see what happens
- p = subprocess.Popen(['sudo', '-S'] + sys.argv[1:], stdin=subprocess.PIPE, stderr=subprocess.PIPE)
- p.communicate()
-
- # It ran!
- if not p.returncode:
- exit(0)
-
- # It didn't :( - let's lock this region now to avoid having multiple password boxes pop-up
- l = fmutex('pysudo.%s.lock' % getpass.getuser())
-
- # Try running it again (maybe another process authenticated... why ask for a password again?)
- p = subprocess.Popen(['sudo', '-S'] + sys.argv[1:], stdin=subprocess.PIPE, stderr=subprocess.PIPE)
- p.communicate()
-
- if not p.returncode:
- l.unlock()
- exit(0)
-
- # No we really need to ask for a password :(
- for i in range(0, 3):
- password = passwordbox('Please enter your password.', 'sudo', '')
- if password is None:
- exit(1)
-
- # Try it out with a password now!
- p = subprocess.Popen(['sudo', '-S', 'true'], stdin=subprocess.PIPE, stderr=subprocess.PIPE)
- p.communicate(input='%s\n' % password)
-
- # Did it work? Yes: let's do it!
- if not p.returncode:
- l.unlock()
- p = subprocess.Popen(['sudo', '-S'] + sys.argv[1:], stdin=subprocess.PIPE)
- p.communicate(input='%s\n' % password)
- exit(p.returncode)
-
- exit(2)
-
-if __name__ == '__main__':
- main()
+++ /dev/null
-@python %~dp0\pysudo %*
\ No newline at end of file