diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..f2cad6c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,85 @@ +name: goreleaser + +on: + pull_request: + push: + branches: + - 'main' + tags: + - 'v*' + +permissions: + contents: write + +jobs: + test: + name: Test + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: 'go.mod' + + # - name: Debug + # run: | + # printenv | sort + + - name: Test + run: go test -v ./... + + build: + name: Build Release + needs: [ test ] + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: 'go.mod' + + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v6 + with: + distribution: goreleaser + version: latest + args: release --clean --skip=validate --skip=publish + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + release: + name: Release and publish + needs: [ test ] + if: startsWith(github.ref, 'refs/tags/') + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: 'go.mod' + + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v6 + with: + distribution: goreleaser + version: latest + args: release --clean + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GORELEASER_CURRENT_TAG: ${{ github.ref_name }} diff --git a/.gitignore b/.gitignore index c6016a6..a443b90 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *~ +/dist/ /hemlock-sendmsg /hemlock-sendmsg.exe /secrets/* diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000..5b1789f --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,31 @@ +version: 2 + +env: + - GO111MODULE=on + +before: + hooks: + - go mod download + +builds: + - main: ./... + env: + - CGO_ENABLED=0 + goos: + - linux + goarch: + - amd64 + +archives: + - files: + - README.md + +release: + prerelease: auto + +changelog: + sort: asc + filters: + exclude: + - '^docs:' + - '^test:' diff --git a/Makefile b/Makefile index 43f93b3..d782a51 100644 --- a/Makefile +++ b/Makefile @@ -9,3 +9,7 @@ install: > /etc/systemd/system/hemlock-sendmsg.service systemctl daemon-reload systemctl enable hemlock-sendmsg + +.PHONY: snapshot +snapshot: + goreleaser release --snapshot --clean diff --git a/attic/messaging.py b/attic/messaging.py deleted file mode 100644 index 6967ebc..0000000 --- a/attic/messaging.py +++ /dev/null @@ -1,340 +0,0 @@ -"""Server Side FCM sample. - -Firebase Cloud Messaging (FCM) can be used to send messages to clients on iOS, -Android and Web. - -This sample uses FCM to send two types of messages to clients that are subscribed -to the `news` topic. One type of message is a simple notification message (display message). -The other is a notification message (display notification) with platform specific -customizations. For example, a badge is added to messages that are sent to iOS devices. - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2015 Google Inc - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - All code in any directories or sub-directories that end with *.html or - *.css is licensed under the Creative Commons Attribution International - 4.0 License, which full text can be found here: - https://creativecommons.org/licenses/by/4.0/legalcode. - - As an exception to this license, all html or css that is generated by - the software at the direction of the user is copyright the user. The - user has full ownership and control over such content, including - whether and how they wish to license it. -""" - -import argparse -import json -import requests - -from oauth2client.service_account import ServiceAccountCredentials -from pprint import pprint - -PROJECT_ID = 'test-fdfb4' -BASE_URL = 'https://fcm.googleapis.com' -FCM_ENDPOINT = 'v1/projects/' + PROJECT_ID + '/messages:send' -FCM_URL = BASE_URL + '/' + FCM_ENDPOINT -SCOPES = ['https://www.googleapis.com/auth/firebase.messaging'] - -# [START retrieve_access_token] -def _get_access_token(): - """Retrieve a valid access token that can be used to authorize requests. - - :return: Access token. - """ - credentials = ServiceAccountCredentials.from_json_keyfile_name( - 'service-account.json', SCOPES) - pprint(credentials) - access_token_info = credentials.get_access_token() - pprint(access_token_info) - return access_token_info.access_token -# [END retrieve_access_token] - -def _send_fcm_message(fcm_message): - """Send HTTP request to FCM with given message. - - Args: - fcm_message: JSON object that will make up the body of the request. - """ - # [START use_access_token] - headers = { - 'Authorization': 'Bearer ' + _get_access_token(), - 'Content-Type': 'application/json; UTF-8', - } - # [END use_access_token] - resp = requests.post(FCM_URL, data=json.dumps(fcm_message), headers=headers) - - if resp.status_code == 200: - print('Message sent to Firebase for delivery, response:') - print(resp.text) - else: - print('Unable to send message to Firebase') - print(resp.text) - -def _build_common_message(): - """Construct common notifiation message. - - Construct a JSON object that will be used to define the - common parts of a notification message that will be sent - to any app instance subscribed to the news topic. - """ - return { - 'message': { - 'topic': 'news', - 'notification': { - 'title': 'FCM Notification', - 'body': 'Notification from FCM' - } - } - } - -def _build_override_message(): - """Construct common notification message with overrides. - - Constructs a JSON object that will be used to customize - the messages that are sent to iOS and Android devices. - """ - fcm_message = _build_common_message() - - apns_override = { - 'payload': { - 'aps': { - 'badge': 1 - } - }, - 'headers': { - 'apns-priority': '5' - } - } - - android_override = { - 'notification': { - 'click_action': 'android.intent.action.MAIN' - } - } - - fcm_message['message']['android'] = android_override - fcm_message['message']['apns'] = apns_override - - return fcm_message - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument('--message') - args = parser.parse_args() - if args.message and args.message == 'common-message': - common_message = _build_common_message() - print('FCM request body for message using common notification object:') - print(json.dumps(common_message, indent=2)) - _send_fcm_message(common_message) - elif args.message and args.message == 'override-message': - override_message = _build_override_message() - print('FCM request body for override message:') - print(json.dumps(override_message, indent=2)) - _send_fcm_message(override_message) - else: - print('''Invalid command. Please use one of the following commands: -python messaging.py --message=common-message -python messaging.py --message=override-message''') - -if __name__ == '__main__': - main() diff --git a/attic/requirements.txt b/attic/requirements.txt deleted file mode 100644 index 286f197..0000000 --- a/attic/requirements.txt +++ /dev/null @@ -1,21 +0,0 @@ -cachetools==5.3.3 -certifi==2024.2.2 -charset-normalizer==3.3.2 -google-api-core==2.18.0 -google-api-python-client==2.125.0 -google-auth==2.29.0 -google-auth-httplib2==0.2.0 -googleapis-common-protos==1.63.0 -httplib2==0.22.0 -idna==3.6 -oauth2client==4.1.3 -proto-plus==1.23.0 -protobuf==4.25.3 -pyasn1==0.6.0 -pyasn1_modules==0.4.0 -pyparsing==3.1.2 -requests==2.31.0 -rsa==4.9 -six==1.16.0 -uritemplate==4.1.1 -urllib3==2.2.1 diff --git a/buildinfo.go b/buildinfo.go index b943414..b645c6b 100644 --- a/buildinfo.go +++ b/buildinfo.go @@ -7,6 +7,14 @@ import ( "runtime/debug" ) +// If built by goreleaser, these variables are set by goreleaser using -ldflags. +var ( + version = "dev" + commit = "unknown" + date = "" + builtBy = "" +) + func safeSubstr(str string, length int) string { if len(str) >= length { return str[:length] @@ -22,26 +30,27 @@ func readBuildInfo() (string, error) { } programName := filepath.Base(execPath) - info, ok := debug.ReadBuildInfo() - if !ok { - return "", fmt.Errorf("ReadBuildInfo failed") - } + if builtBy != "goreleaser" { + info, ok := debug.ReadBuildInfo() + if !ok { + return "", fmt.Errorf("ReadBuildInfo failed") + } - vcs_modified := "" - vcs_rev := "" - vcs_time := "" - for _, element := range info.Settings { - if element.Key == "vcs.revision" { - vcs_rev = safeSubstr(element.Value, 8) - } else if element.Key == "vcs.time" { - vcs_time = safeSubstr(element.Value, 10) - } else if element.Key == "vcs.modified" { - if element.Value == "true" { - vcs_modified = "(LOCALLY MODIFIED)" - } else { - vcs_modified = "" + vcsModified := false + for _, setting := range info.Settings { + switch setting.Key { + case "vcs.revision": + commit = safeSubstr(setting.Value, 8) + case "vcs.time": + date = safeSubstr(setting.Value, 10) + case "vcs.modified": + vcsModified = setting.Value == "true" } } + if vcsModified { + commit = "locally_modified" + } } - return fmt.Sprintf("%s date=%s commit=%s %s", programName, vcs_time, vcs_rev, vcs_modified), nil + + return fmt.Sprintf("%s version=%s date=%s commit=%s", programName, version, date, commit), nil } diff --git a/sendmsg.go b/sendmsg.go index 5784d57..ca86735 100644 --- a/sendmsg.go +++ b/sendmsg.go @@ -168,7 +168,7 @@ func (srv *ServiceData) sendHandler(w http.ResponseWriter, r *http.Request) { } func createServiceData(credentialsFile string) (*ServiceData, error) { - // sanity check that credentialsFile is present, else you get an unhelpful error + // check that credentialsFile is present, else you get an unhelpful error if _, err := os.Stat(credentialsFile); err != nil { return nil, err }