diff --git a/.github/workflows/github_release.yml b/.github/workflows/github_release.yml index 14b2ef8..1245da2 100644 --- a/.github/workflows/github_release.yml +++ b/.github/workflows/github_release.yml @@ -1,15 +1,15 @@ -name: Create Release +name: Create GitHub Release on: push: - branches: [ master ] + branches: [ main, master ] jobs: build: runs-on: ubuntu-latest strategy: matrix: - python-version: [ '3.10' ] + python-version: [ '3.12' ] steps: - name: Checkout uses: actions/checkout@v3 @@ -19,20 +19,17 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python -m pip install --upgrade pip - pip install flake8 - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + pip install flake8 poetry + poetry install - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - - name: Test setup & install + - name: Install run: | - pip install build twine - python3 -m build - twine check dist/*.whl + poetry build python3 -m pip install dist/*.whl - name: Extract release notes id: extract-release-notes diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 77d0e39..9cdac40 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -5,9 +5,9 @@ name: Python package on: push: - branches: [ develop ] + branches: [ develop, feature/**, release/** ] pull_request: - branches: [ develop ] + branches: [ develop, feature/**, release/** ] jobs: build-ubuntu: @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.10'] + python-version: ['3.12'] steps: - uses: actions/checkout@v2 @@ -25,9 +25,8 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python -m pip install --upgrade pip - pip install flake8 - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + pip install flake8 poetry + poetry install - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names @@ -36,11 +35,9 @@ jobs: flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - name: Test setup & install run: | - pip install build twine - python3 -m build - twine check dist/*.whl + poetry build python3 -m pip install dist/*.whl - name: Test run run: | slack-watchman --version - slack-watchman --help + slack-watchman --help \ No newline at end of file diff --git a/.github/workflows/pythonpublish.yml b/.github/workflows/pythonpublish.yml index 119e458..612e54d 100644 --- a/.github/workflows/pythonpublish.yml +++ b/.github/workflows/pythonpublish.yml @@ -1,11 +1,9 @@ -# This workflows will upload a Python Package using Twine when a release is created -# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries -name: Upload Python Package +name: Poetry Publish on: push: - branches: [ master ] + branches: [ main ] jobs: deploy: @@ -17,14 +15,11 @@ jobs: - name: Set up Python uses: actions/setup-python@v2 with: - python-version: '3.x' + python-version: '3.12' - name: Install dependencies run: | - python3 -m pip install --upgrade pip twine build - - name: Build and publish - env: - TWINE_USERNAME: ${{ '__token__' }} - TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} - run: | - python3 -m build - twine upload dist/* + pip install poetry + poetry install + poetry config pypi-token.pypi "${{ secrets.PYPI_TOKEN }}" + - name: Publish package + run: poetry publish --build \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 95faa02..96a3198 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ +## [4.1.0] - 2024-09-02 +### Changed +- Signatures are now downloaded, processes and stored in memory instead of writing to disk. This saves having to store them in files, and solves the issues when using Slack Watchman with read-only filesystems (raised in [#51](https://github.com/PaperMtn/watchman-signatures/issues/51)) +- Migrated to Poetry for dependency control and packaging + + ## [4.0.2] - 2023-06-14 ### Added -- Added notification for an invalid cookie being passed (Fixes #47) +- Added notification for an invalid cookie being passed (Fixes [#47](https://github.com/PaperMtn/watchman-signatures/issues/47)) ### Fixed - JSON output for User and Workspace information was malformed, this has now been fixed @@ -11,7 +17,7 @@ ## [4.0.0] - 2023-05-03 This major version release brings multiple updates to Slack Watchman in usability, functionality and behind the scenes improvements. -**Note**: While efforts have been made to make sure there is some backwards compatibility, this release may have some breaking changes on previous versions. Make sure to look at the removed secion +**Note**: While efforts have been made to make sure there is some backwards compatibility, this release may have some breaking changes on previous versions. Make sure to look at the removed section ### Added - Support for centralised signatures from the [Watchman Signatures repository](https://github.com/PaperMtn/watchman-signatures) diff --git a/Dockerfile b/Dockerfile index c1601ea..383733c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,40 @@ # syntax=docker/dockerfile:1 -FROM python:3.10 -COPY . /opt/slack-watchman +#FROM python:3.12-slim-bullseye +#WORKDIR /opt/slack-watchman +#COPY . /opt/slack-watchman +#RUN pip install poetry +#ENV PYTHONPATH=/opt/slack-watchman \ +# SLACK_WATCHMAN_TOKEN="" \ +# SLACK_WATCHMAN_COOKIE="" \ +# SLACK_WATCHMAN_URL="" +#RUN poetry config virtualenvs.create false && \ +# poetry install --no-dev && \ +# chmod -R 700 . && \ +# poetry build && \ +# pip install dist/*.whl +#STOPSIGNAL SIGINT +#WORKDIR /opt/slack-watchman +#ENTRYPOINT ["slack-watchman"] + +# syntax=docker/dockerfile:1 +FROM python:3.12-slim-bullseye AS builder WORKDIR /opt/slack-watchman -ENV PYTHONPATH=/opt/slack-watchman SLACK_WATCHMAN_TOKEN="" SLACK_WATCHMAN_COOKIE="" SLACK_WATCHMAN_URL="" -RUN pip3 install -r requirements.txt build && \ - chmod -R 700 . && \ - python3 -m build && \ - python3 -m pip install dist/*.whl -STOPSIGNAL SIGINT +COPY . . +RUN pip install poetry +RUN poetry config virtualenvs.create false && \ + poetry install --no-dev && \ + poetry build + +FROM python:3.12-slim-bullseye WORKDIR /opt/slack-watchman +COPY --from=builder /opt/slack-watchman/dist/*.whl /opt/slack-watchman/dist/ +COPY --from=builder /opt/slack-watchman/pyproject.toml /opt/slack-watchman/poetry.lock /opt/slack-watchman/ +ENV PYTHONPATH=/opt/slack-watchman \ + SLACK_WATCHMAN_TOKEN="" \ + SLACK_WATCHMAN_COOKIE="" \ + SLACK_WATCHMAN_URL="" +RUN pip install dist/*.whl && \ + chmod -R 700 . +STOPSIGNAL SIGINT ENTRYPOINT ["slack-watchman"] \ No newline at end of file diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..2f53189 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,238 @@ +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. + +[[package]] +name = "certifi" +version = "2024.8.30" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "idna" +version = "3.8" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.6" +files = [ + {file = "idna-3.8-py3-none-any.whl", hash = "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac"}, + {file = "idna-3.8.tar.gz", hash = "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, +] + +[[package]] +name = "requests" +version = "2.32.3" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.8" +files = [ + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "urllib3" +version = "2.2.2" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, + {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[metadata] +lock-version = "2.0" +python-versions = ">=3.10" +content-hash = "e1ea022f613b62aab2d599e878268a445dd9e1b6bf8ae74caa03a88c5ed6bf97" diff --git a/pyproject.toml b/pyproject.toml index 374b58c..9398292 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,31 @@ -[build-system] -requires = [ - "setuptools>=42", - "wheel" +[tool.poetry] +name = "slack-watchman" +version = "4.1.0" +description = "Monitoring and enumerating Slack for exposed secrets" +authors = ["PaperMtn "] +license = "GPL-3.0" +readme = "README.md" +homepage = "https://github.com/PaperMtn/slack-watchman" +repository = "https://github.com/PaperMtn/slack-watchman" +keywords = [ "audit", "slack", "slack-watchman", "watchman", "blue-team", "red-team", "threat-hunting" ] +classifiers = [ + "Intended Audience :: Information Technology", + "Topic :: Cybersecurity", + "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", ] -build-backend = "setuptools.build_meta" + +[tool.poetry.urls] +"Blog" = "https://papermtn.co.uk/category/tools/slack-watchman/" + +[tool.poetry.dependencies] +python = ">=3.10" +colorama = "^0.4.6" +pyyaml = "^6.0.2" +requests = "^2.32.3" + +[tool.poetry.scripts] +slack-watchman = "slack_watchman:main" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 1193a43..0000000 --- a/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -requests -colorama -PyYAML \ No newline at end of file diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 6249596..0000000 --- a/setup.cfg +++ /dev/null @@ -1,35 +0,0 @@ -[metadata] -name = slack-watchman -version = attr: slack_watchman.__version__.__version__ -description = Monitoring and enumerating Slack for exposed secrets -long_description = file: README.md, CHANGELOG.md -long_description_content_type = text/markdown -license = GPL-3.0 -url = https://github.com/PaperMtn/slack-watchman -author = PaperMtn -author_email = papermtn@protonmail.com -keywords = audit, slack, slack-watchman, watchman, blue-team, red-team, threat-hunting -classifiers = - Intended Audience :: Information Technology - Topic :: Security - License :: OSI Approved :: GNU General Public License v3 (GPLv3) - Programming Language :: Python :: 3.10 - -[options] -zip_safe = False -package_dir = - = src -include_package_data = True -packages = find_namespace: -python_requires = >=3.10 -install_requires = - requests - PyYAML - colorama - -[options.entry_points] -console_scripts = - slack-watchman = slack_watchman:main - -[options.packages.find] -where = src \ No newline at end of file diff --git a/src/__init__.py b/src/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/slack_watchman/__init__.py b/src/slack_watchman/__init__.py index 3ff4b2c..03ea149 100644 --- a/src/slack_watchman/__init__.py +++ b/src/slack_watchman/__init__.py @@ -4,16 +4,17 @@ import sys import time import traceback +from importlib import metadata + import yaml -from pathlib import Path -from typing import List - -from . import sw_logger -from . import __version__ -from . import slack_wrapper as slack -from . import signature_updater -from . import exceptions -from .models import ( + +from slack_watchman import ( + sw_logger, + signature_downloader, + exceptions, + slack_wrapper +) +from slack_watchman.models import ( signature, user, workspace, @@ -21,31 +22,9 @@ conversation ) -SIGNATURES_PATH = (Path(__file__).parents[2] / 'watchman-signatures').resolve() OUTPUT_LOGGER: sw_logger.JSONLogger -def load_signatures() -> List[signature.Signature]: - """ Load signatures from YAML files - Returns: - List containing loaded definitions as Signatures objects - """ - - loaded_signatures = [] - try: - for root, dirs, files in os.walk(SIGNATURES_PATH): - for sig_file in files: - sig_path = (Path(root) / sig_file).resolve() - if sig_path.name.endswith('.yaml'): - loaded_def = signature.load_from_yaml(sig_path) - for sig in loaded_def: - if sig.status == 'enabled' and 'slack_std' in sig.watchman_apps: - loaded_signatures.append(sig) - return loaded_signatures - except Exception as e: - raise e - - def validate_conf(path: str, cookie: bool) -> bool: """ Check the file slack_watchman.conf exists @@ -106,7 +85,7 @@ def validate_conf(path: str, cookie: bool) -> bool: raise exceptions.MissingEnvVarError('SLACK_WATCHMAN_URL') -def search(slack_connection: slack.SlackAPI, +def search(slack_connection: slack_wrapper.SlackAPI, loaded_signature: signature.Signature, timeframe: int or str, scope: str, @@ -125,7 +104,7 @@ def search(slack_connection: slack.SlackAPI, if scope == 'messages': OUTPUT_LOGGER.log('INFO', f'Searching for posts containing {loaded_signature.name}') - messages = slack.find_messages( + messages = slack_wrapper.find_messages( slack_connection, OUTPUT_LOGGER, loaded_signature, @@ -142,7 +121,7 @@ def search(slack_connection: slack.SlackAPI, notify_type='result') if scope == 'files': OUTPUT_LOGGER.log('INFO', f'Searching for posts containing {loaded_signature.name}') - files = slack.find_files( + files = slack_wrapper.find_files( slack_connection, OUTPUT_LOGGER, loaded_signature, @@ -180,7 +159,8 @@ def main(): try: OUTPUT_LOGGER = '' start_time = time.time() - parser = argparse.ArgumentParser(description=__version__.__summary__) + project_metadata = metadata.metadata('slack-watchman') + parser = argparse.ArgumentParser(description="Monitoring and enumerating Slack for exposed secrets") required = parser.add_argument_group('required arguments') required.add_argument('--timeframe', '-t', choices=['d', 'w', 'm', 'a'], dest='time', @@ -189,7 +169,7 @@ def main(): parser.add_argument('--output', '-o', choices=['json', 'stdout'], dest='logging_type', help='Where to send results') parser.add_argument('--version', '-v', action='version', - version=f'Slack Watchman: {__version__.__version__}') + version=f'Slack Watchman: {project_metadata.get("version")}') parser.add_argument('--all', '-a', dest='everything', action='store_true', help='Find secrets and PII') parser.add_argument('--users', '-u', dest='users', action='store_true', @@ -246,7 +226,7 @@ def main(): conf_path = f'{os.path.expanduser("~")}/watchman.conf' validate_conf(conf_path, cookie) - slack_con = slack.initiate_slack_connection(cookie) + slack_con = slack_wrapper.initiate_slack_connection(cookie) auth_data = slack_con.get_auth_test() calling_user = user.create_from_dict( @@ -255,14 +235,12 @@ def main(): workspace_information = workspace.create_from_dict(slack_con.get_workspace_info().get('team')) OUTPUT_LOGGER.log('SUCCESS', 'Slack Watchman started execution') - OUTPUT_LOGGER.log('INFO', f'Version: {__version__.__version__}') - OUTPUT_LOGGER.log('INFO', f'Created by: {__version__.__author__} - {__version__.__email__}') + OUTPUT_LOGGER.log('INFO', f'Version: {project_metadata.get("version")}') + OUTPUT_LOGGER.log('INFO', f'Created by: PaperMtn ') OUTPUT_LOGGER.log('INFO', f'Searching workspace: {workspace_information.name}') OUTPUT_LOGGER.log('INFO', f'Workspace URL: {workspace_information.url}') - OUTPUT_LOGGER.log('INFO', 'Downloading signature file updates') - signature_updater.SignatureUpdater(OUTPUT_LOGGER).update_signatures() - OUTPUT_LOGGER.log('INFO', 'Importing signatures...') - signature_list = load_signatures() + OUTPUT_LOGGER.log('INFO', 'Downloading and importing signatures...') + signature_list = signature_downloader.SignatureDownloader(OUTPUT_LOGGER).download_signatures() OUTPUT_LOGGER.log('SUCCESS', f'{len(signature_list)} signatures loaded') if cookie: OUTPUT_LOGGER.log('SUCCESS', 'Successfully authenticated using cookie') @@ -275,7 +253,7 @@ def main(): if users: OUTPUT_LOGGER.log('INFO', 'Enumerating users...') - user_list = slack.get_users(slack_con, verbose) + user_list = slack_wrapper.get_users(slack_con, verbose) OUTPUT_LOGGER.log('SUCCESS', f'{len(user_list)} users discovered') OUTPUT_LOGGER.log('INFO', 'Writing to csv') sw_logger.export_csv('slack_users', user_list) @@ -285,7 +263,7 @@ def main(): if channels: OUTPUT_LOGGER.log('INFO', 'Enumerating channels...') - channel_list = slack.get_channels(slack_con, verbose) + channel_list = slack_wrapper.get_channels(slack_con, verbose) OUTPUT_LOGGER.log('SUCCESS', f'{len(channel_list)} channels discovered') OUTPUT_LOGGER.log('INFO', 'Writing to csv') sw_logger.export_csv('slack_channels', channel_list) diff --git a/src/slack_watchman/__version__.py b/src/slack_watchman/__version__.py deleted file mode 100644 index 5ed6c6f..0000000 --- a/src/slack_watchman/__version__.py +++ /dev/null @@ -1,35 +0,0 @@ -# Slack Watchman -# Copyright (C) 2023 PaperMtn -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -__all__ = [ - '__title__', - '__summary__', - '__uri__', - '__version__', - '__author__', - '__email__', - '__license__', -] - -__title__ = 'Slack Watchman' -__version__ = '4.0.2' -__summary__ = 'Monitoring and enumerating Slack for exposed secrets' -__author__ = 'PaperMtn' -__email__ = 'papermtn@protonmail.com' -__license__ = 'GPL-3.0' -__uri__ = 'https://github.com/PaperMtn/slack-watchman' -__copyright__ = f'2023 {__author__}' - diff --git a/src/slack_watchman/models/post.py b/src/slack_watchman/models/post.py index cc40cc4..5cf6653 100644 --- a/src/slack_watchman/models/post.py +++ b/src/slack_watchman/models/post.py @@ -2,8 +2,7 @@ from dataclasses import dataclass from typing import List, Dict -from . import conversation -from . import user +from slack_watchman.models import conversation, user def _convert_timestamp(timestamp: str or int) -> str or None: diff --git a/src/slack_watchman/models/signature.py b/src/slack_watchman/models/signature.py index f5d1425..c5164c3 100644 --- a/src/slack_watchman/models/signature.py +++ b/src/slack_watchman/models/signature.py @@ -1,16 +1,14 @@ -import pathlib -import yaml from dataclasses import dataclass from typing import List -@dataclass(slots=True) +@dataclass(frozen=True, slots=True) class TestCases: match_cases: List[str] fail_cases: List[str] -@dataclass(slots=True) +@dataclass(frozen=True, slots=True) class Signature: """ Class that handles loaded signature objects. Signatures define what to search for in Slack and where to search for it. @@ -30,40 +28,3 @@ class Signature: test_cases: TestCases search_strings: str patterns: List[str] - - -def load_from_yaml(sig_path: pathlib.PosixPath) -> List[Signature]: - """Load YAML file and return a Signature object - Args: - sig_path: Path of YAML file - Returns: - Signature object with fields populated from the YAML - signature file - """ - - with open(sig_path) as yaml_file: - yaml_import = yaml.safe_load(yaml_file) - - output = [] - for sig in yaml_import.get('signatures'): - if 'slack_std' in sig.get('watchman_apps'): - output.append(Signature( - name=sig.get('name'), - status=sig.get('status'), - author=sig.get('author'), - date=sig.get('date'), - version=sig.get('version'), - description=sig.get('description'), - severity=sig.get('severity'), - watchman_apps=sig.get('watchman_apps'), - category=sig.get('watchman_apps').get('slack_std').get('category'), - scope=sig.get('watchman_apps').get('slack_std').get('scope'), - file_types=sig.get('watchman_apps').get('slack_std').get('file_types'), - test_cases=TestCases( - match_cases=sig.get('test_cases').get('match_cases'), - fail_cases=sig.get('test_cases').get('fail_cases') - ), - search_strings=sig.get('watchman_apps').get('slack_std').get('search_strings'), - patterns=sig.get('patterns'))) - - return output diff --git a/src/slack_watchman/signature_downloader.py b/src/slack_watchman/signature_downloader.py new file mode 100644 index 0000000..e77f973 --- /dev/null +++ b/src/slack_watchman/signature_downloader.py @@ -0,0 +1,98 @@ +import io +import os +import sys +import traceback +import zipfile +from urllib.request import urlopen +from typing import List + +import yaml + +from slack_watchman.sw_logger import JSONLogger, StdoutLogger +from slack_watchman.models.signature import Signature, TestCases + +SIGNATURE_URL = 'https://github.com/PaperMtn/watchman-signatures/archive/main.zip' + + +class SignatureDownloader: + def __init__(self, logger: JSONLogger or StdoutLogger): + """ Initializes a SignatureDownloader object. + + Args: + logger (JSONLogger or StdoutLogger): The logger object to use for logging. + Returns: + None + """ + self.logger = logger + + def download_signatures(self) -> List[Signature]: + """ Download signatures from GitHub repository + + Returns: + List of downloaded Signature objects + """ + + try: + response = urlopen(SIGNATURE_URL) + signatures_zip_file = zipfile.ZipFile(io.BytesIO(response.read())) + signature_files = {} + signature_objects = [] + for file_path in signatures_zip_file.namelist(): + if file_path.endswith('/'): + continue + + signature_name = os.path.basename(file_path) + self.logger.log('DEBUG', f'Processing {file_path} ...') + + with signatures_zip_file.open(file_path) as source: + signature_files[signature_name] = source.read() + + if file_path.endswith('.yaml'): + signature_objects.append(self._process_signature(signature_files[signature_name])) + self.logger.log('SUCCESS', f'Downloaded signature file: {signature_name}') + else: + self.logger.log('DEBUG', f'Skipping unrecognized file: {file_path}') + + return [item for sublist in signature_objects for item in sublist] + + except Exception as e: + self.logger.log('CRITICAL', f'Error while processing the signature' + f' files from the download package: {e}') + self.logger.log('DEBUG', traceback.format_exc()) + sys.exit(1) + + def _process_signature(self, signature_data: bytes) -> List[Signature]: + """ Process a signature data bytes object into a list of Signature objects. + + This function takes a bytes object containing signature data, parses it into a dictionary, + and then creates a list of Signature objects based on the parsed data. + + Args: + signature_data (bytes): A bytes object containing signature data. + Returns: + List[Signature]: A list of Signature objects created from the parsed signature data. + """ + + signature_dict = yaml.safe_load(io.StringIO(signature_data.decode('utf-8'))) + output = [] + for sig in signature_dict.get('signatures'): + if 'slack_std' in sig.get('watchman_apps') and sig.get('status') == 'enabled': + output.append(Signature( + name=sig.get('name'), + status=sig.get('status'), + author=sig.get('author'), + date=sig.get('date'), + version=sig.get('version'), + description=sig.get('description'), + severity=sig.get('severity'), + watchman_apps=sig.get('watchman_apps'), + category=sig.get('watchman_apps').get('slack_std').get('category'), + scope=sig.get('watchman_apps').get('slack_std').get('scope'), + file_types=sig.get('watchman_apps').get('slack_std').get('file_types'), + test_cases=TestCases( + match_cases=sig.get('test_cases').get('match_cases'), + fail_cases=sig.get('test_cases').get('fail_cases') + ), + search_strings=sig.get('watchman_apps').get('slack_std').get('search_strings'), + patterns=sig.get('patterns'))) + return output diff --git a/src/slack_watchman/signature_updater.py b/src/slack_watchman/signature_updater.py deleted file mode 100644 index fdd6ddb..0000000 --- a/src/slack_watchman/signature_updater.py +++ /dev/null @@ -1,82 +0,0 @@ -import io -import os -import zipfile -import shutil -import sys -from datetime import datetime -from pathlib import Path -from urllib.request import urlopen - -from . import sw_logger - -SIGNATURE_URL = 'https://github.com/PaperMtn/watchman-signatures/archive/main.zip' - - -class SignatureUpdater(object): - def __init__(self, logger: sw_logger.JSONLogger): - self.application_path = str((Path(__file__).parents[2]).resolve()) - self.logger = logger - - def update_signatures(self): - - response = urlopen(SIGNATURE_URL) - - try: - sig_dir = os.path.join(self.application_path, 'watchman-signatures/') - for sub_directory in [ - '', - 'config_files', - 'competitive', - 'compliance', - 'tokens_and_credentials' - ]: - full_path = os.path.join(sig_dir, sub_directory) - if not os.path.exists(full_path): - os.makedirs(full_path) - except Exception as e: - self.logger.log('CRITICAL', 'Error while creating the signature-base directories') - sys.exit(1) - - try: - signatures_zip_file = zipfile.ZipFile(io.BytesIO(response.read())) - for file_path in signatures_zip_file.namelist(): - signature_name = os.path.basename(file_path) - if file_path.endswith('/'): - continue - - self.logger.log('DEBUG', f'Extracting {file_path} ...') - if '/competitive/' in file_path and file_path.endswith('.yaml'): - target_file = os.path.join(sig_dir, 'competitive', signature_name) - elif '/compliance/' in file_path and file_path.endswith('.yaml'): - target_file = os.path.join(sig_dir, 'compliance', signature_name) - elif '/config_files/' in file_path and file_path.endswith('.yaml'): - target_file = os.path.join(sig_dir, 'config_files', signature_name) - elif file_path.endswith('.yaml'): - target_file = os.path.join(sig_dir, 'tokens_and_credentials', signature_name) - elif file_path.endswith('.yaml'): - target_file = os.path.join(sig_dir, 'misc', signature_name) - else: - continue - - if os.path.exists(target_file): - existing_modified_date = datetime.utcfromtimestamp(os.path.getmtime(target_file)) - if datetime(*signatures_zip_file.getinfo(file_path).date_time) > existing_modified_date: - self.logger.log('SUCCESS', f'Signature updated to newest version: {signature_name}') - source = signatures_zip_file.open(file_path) - target = open(target_file, 'wb') - with source, target: - shutil.copyfileobj(source, target) - target.close() - source.close() - else: - self.logger.log('SUCCESS', f'New signature file: {signature_name}') - source = signatures_zip_file.open(file_path) - target = open(target_file, 'wb') - with source, target: - shutil.copyfileobj(source, target) - target.close() - source.close() - - except Exception as e: - self.logger.log('CRITICAL', f'Error while extracting the signature files from the download package {e}') - sys.exit(1) diff --git a/src/slack_watchman/slack_wrapper.py b/src/slack_watchman/slack_wrapper.py index 8df1ae6..aba564d 100644 --- a/src/slack_watchman/slack_wrapper.py +++ b/src/slack_watchman/slack_wrapper.py @@ -14,9 +14,8 @@ from urllib3.util import Retry from requests.adapters import HTTPAdapter -from . import sw_logger -from . import exceptions -from .models import ( +from slack_watchman import sw_logger, exceptions +from slack_watchman.models import ( signature, user, post,