Skip to content

Commit

Permalink
Reworked these to get them where I needed them.
Browse files Browse the repository at this point in the history
These should now handle SFTP and use the latest
methods from pushover and twilio to send out an
uploaded file from a hosting service.
  • Loading branch information
hhocker committed Dec 7, 2021
1 parent 5c5cddf commit 0e574c5
Show file tree
Hide file tree
Showing 26 changed files with 261 additions and 157 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,6 @@ docs/_build/
target/
.DS_Store
.idea/

#safety
deshler*
Binary file added push_notifier/dist/libcrypto-1_1.dll
Binary file not shown.
Binary file added push_notifier/dist/libffi-7.dll
Binary file not shown.
Binary file added push_notifier/dist/libssl-1_1.dll
Binary file not shown.
Binary file modified push_notifier/dist/pushNotifier.exe
Binary file not shown.
Binary file added push_notifier/dist/python38.dll
Binary file not shown.
14 changes: 14 additions & 0 deletions push_notifier/example.push.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"APP_KEY": "<pushover application key>",
"GROUP_KEY": "<user group, easier than individual user keys, to broadcast to>",
"MESSAGE": "[department] paged ",
{"MESSAGE-COMMENT":"//Shows up as the start of the message like 'Department paged @ <Timestamp>' "},
"TITLE": "[Dept] Page Alert",
{"TITLE-COMMENT":"//Shows up as the title of the push in bold "},
"SOUND": "siren",
{"SOUND-COMMENT":"//Send the message with the given alert tone. Find list on Pushover site "},
"PRIORITY": 1,
{"PRIORITY-COMMENT":"//Sets the message priority. 1 = high. There is a critical alert but that can be set per user if they choose in the app preferences. Best to leave as high and let them upgrade them as they want. "},
"TIMESTAMP": "[Dept]_%Y_%m_%d_%H_%M_%S.mp3"
{"TIMESTAMP-COMMENT":"//Date format of the mp3 file to parse out the time. Uses parsed time to set the sent time in the API call"},
}
8 changes: 0 additions & 8 deletions push_notifier/example_push_config.json

This file was deleted.

67 changes: 41 additions & 26 deletions push_notifier/pushNotifier.py
Original file line number Diff line number Diff line change
@@ -1,43 +1,58 @@
import argparse
from urllib import request, parse
from os.path import basename
import time, json, datetime

#uses pushover.net to send a push notification to users. usually called like [pushNotifier.exe "<quoted path to json config>" -u ] the URL will be appended by uploadFile
parser = argparse.ArgumentParser(description='Uploaded file to FTP server and send out link via Pushover')
parser.add_argument("pushconfig", help='path to the pushover config file (wrap with quotes if path contains spaces)')
parser.add_argument("--timestamp", "-ts", dest='ts', default=False, action='store_true',
help='include a timestamp on the message')
parser.add_argument("--url", "-u", help='url to include in the message.', dest='url', default='')
args = parser.parse_args()

pushconfig = args.pushconfig
url = args.url
tmst = args.ts
pushconfig = args.pushconfig #config file that setups the notifications quickly
url = args.url #URL to a media file or link to push out

import httplib, urllib, json
import time
import datetime
jfile = open(pushconfig) #open the config file that was passed in
push_json = json.load(jfile) #read as jason into an array
jfile.close() #close the file as we have already loaded in the array

ct = time.time()
dt = datetime.datetime.fromtimestamp(ct).strftime('%Y-%m-%d %H:%M:%S')
message = push_json["MESSAGE"] #parameter for the message header
timestamp = '' #set timestamp format to blank to signal no further processing
if 'TIMESTAMP' in push_json: #if a timestamp field is in the config
timestamp = str(push_json["TIMESTAMP"]) #parse the value into a string to use

jfile = open(pushconfig)
push_json = json.load(jfile)
jfile.close()
timestring = '' #set the message timestamp to be empty

message = push_json["MESSAGE"]
if tmst:
message += " @ " + dt
if url:
message += "\n" + url
attachment = '' #set the attachment file to blank to skip attaching a URL to the push
if args.url != '' : #if URL was passed in then
attachment += "\r\n" + args.url #put the URL on its own line after the given message
basenameurl = parse.urlparse(args.url) #get the file name from the URL
timestring = basename(basenameurl.path) #we will parse the time out of the filename (often <dept>_<timestamp>.mp3)

conn = httplib.HTTPSConnection("api.pushover.net:443")
conn.request("POST", "/1/messages.json",
urllib.urlencode({

if timestamp: #if a timestamp format was given
ct = time.time() #default to RIGHT NOW as a fallback usually will be a litte bit off of the upload/received time in the pageing file
try:
if (timestamp.lower() != "now") and timestring : #if we specify "now" we just skip parsing the time. and we have a good file name to parse
ct = time.mktime(time.strptime(timestring,timestamp)) #parse the time from the file format
except Exception as tpe:
print(tpe)
ct = time.time() #on execption go back to the current time
dt = datetime.datetime.fromtimestamp(ct).strftime('%Y-%m-%d %H:%M:%S') #format to a human readable 'ISO8601' format
message += " @ " + dt #then put it after the message
message += attachment #but before the url to upload.


data = parse.urlencode({ #encode the details we need from our json file
"token": push_json['APP_KEY'],
"user": push_json["GROUP_KEY"],
"message": message,
"message": message, #put our assembled message as the details to the upload
"title": push_json["TITLE"],
"sound": push_json["SOUND"],
"timestamp": ct,
"timestamp": time.time(), #i was putting the current time in the system likely by accident TODO: investigate why CT is not used if available.
"priority": push_json["PRIORITY"]
}), {"Content-type": "application/x-www-form-urlencoded"})

conn.getresponse()
}).encode('utf-8')
rqst = request.Request("https://api.pushover.net/1/messages.json", data=data) #call the pushover api.
rqst.add_header('Content-Type', 'application/x-www-form-urlencoded')
resp = request.urlopen(rqst) #we should probably log that we did something here. but here we just ensure the call is done.

1 change: 0 additions & 1 deletion push_notifier/setup.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from distutils.core import setup
import py2exe
import paramiko

setup(name = "PushNotifier",
version = '1.0',
Expand Down
Binary file modified twilio_mms/dist/twilioSMS.exe
Binary file not shown.
21 changes: 21 additions & 0 deletions twilio_mms/example.twilio.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"MESSAGE":"[name of department] paged",
{"MESSAGE-COMMENT":"//Shows up as the start of the message like 'Department paged @ <Timestamp>' "},
"TW_SID":"<Subscriber ID>",
{"TW_SID-COMMENT":"//Found in the account dashboard "},
"TW_TOKEN":"<token>",
{"TW_TOKEN-COMMENT":"//the secret token from the account "},
"TW_FROM":"<sending phone number, likely required with new regulations>",
{"TW_FROM-COMMENT":"//either a 10DLC, Toll Free, or other number from the Programable Messaging interface "},
"AS_MMS":false,
{"AS_MMS-COMMENT":"//determines if the URL given is attached to the email or just sent as a link. "},
"TIMESTAMP": "<MyDepartment>_%Y_%m_%d_%H_%M_%S.mp3",
{"TIMESTAMP-COMMENT":"//The format of the MP3 file to parse the time out so the sent time matches the paged time. "},
"RECIPIENTS":[
"commma separated list of recipients",
"+15553219876",
"+15555551234",
"for example.",
"NOTE: must use +1aaaLLLnnnn style number to make twilio happy"
]
}
7 changes: 0 additions & 7 deletions twilio_mms/example_mms_config.json

This file was deleted.

5 changes: 2 additions & 3 deletions twilio_mms/setup.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from distutils.core import setup
import py2exe
import paramiko

setup(name = "TwilioMMS",
setup(name = "twilioSMS",
version = '1.0',
description = "Send a message through the twilio SMS/MMS API",
author = "Hal Hockersmith",
console = [{'script': 'twilio_mms.py'}],
console = [{'script': 'twilioSMS.py'}],
zipfile = None,
data_files=[],
options = {
Expand Down
79 changes: 79 additions & 0 deletions twilio_mms/twilioSMS.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
from twilio.base.exceptions import TwilioRestException
from twilio.rest import Client as TwilioRestClient #uses twilio Python client. may need to load with pip
import argparse
import logging
import json
import time
import datetime
from urllib.parse import urlparse
from os.path import basename

parser = argparse.ArgumentParser(description='send out passed in url link via Twilio SMS/MMS')
parser.add_argument("smsconfig", help='path to the twilio config file (wrap with quotes if path contains spaces)')
parser.add_argument("--url", "-u", help='url to include in the message.', dest='url', default='')
args = parser.parse_args()
smsconfig = args.smsconfig

#setup logging to file to track issues with Twilio api
logging.basicConfig(filename='twiliosms.log', level=logging.DEBUG, format='%(levelname)s - %(message)s')
logging.info("=========================\r\nTwilio SMS using config %s", smsconfig)

jfile = open(smsconfig)
sms_json = json.load(jfile) #open the local json file and parse into memory
jfile.close()

alert = sms_json["MESSAGE"]
sendmms = sms_json["AS_MMS"] #get the details of the text from the JSON. SendMMS will define if we use MMS attachements or just send out a html link
timestamp = str(sms_json["TIMESTAMP"])

timestring = '' #set the timestamp format to blank to skip formatting in the future

attachment = '' #set the attachment link to null to skip if not set in the future
if args.url != '' : #if we do have URL passed in on the command line
if sendmms != True: #if we are not going to send as an attachment
attachment += "\r\n" + args.url #we add the link to the end of the text message string
basenameurl = urlparse(args.url); #get the filename out of the path
timestring = basename(basenameurl.path) #then set the name to be parsed for the timestamp

if timestamp and timestring : #if we have a format designator and a string to parse
ct = time.time() #safety default to now
try:
if (timestamp.lower() != "now"): #then assuming the format is not "NOW" which skips this step
ct = time.mktime(time.strptime(timestring,timestamp)) #parse the mp3 for the time
except Exception as tpe:
print(tpe)
ct = time.time()
dt = datetime.datetime.fromtimestamp(ct).strftime('%Y-%m-%d %H:%M:%S') #then make it a human readable format
alert += " @ " + dt #and add to the alerted text. This is semi important for held messaging that could flush through to the phone causing panic much later after the call is resolved.
alert += attachment

account_sid = sms_json["TW_SID"] # Your Account SID from www.twilio.com/console
auth_token = sms_json["TW_TOKEN"] # Your Auth Token from www.twilio.com/console
twilio_from = sms_json["TW_FROM"] # Sms Number from
sms_recipients = sms_json["RECIPIENTS"] #array of numbers to send to

client = TwilioRestClient(account_sid, auth_token) #use the client from the library
client.http_client.logger.setLevel(logging.INFO) #give the client a logging framework link so it can add to our log file

#add a bit of logging to indicate we are about to send
print("Twilio send message: \r\n===\r\n" + alert + "\r\n===\r\nMMS: " + str(sendmms) )
logging.info("Twilio send message: \r\n===\r\n" + alert + "\r\n===\r\nMMS: " + str(sendmms) )

#then for every number in the array. Twilio to my knowledge does not allow bulk messaging so it is a bit of race to send a whole bunch of message.
#NOTE!!! Watch your speed here. 10DLC is limited to a few per second, Toll free or Shortcode can send faster.
#ALSO! you might need to do some work for your 10DLC (cheaper) to ensure your messages dont get put on a suspicious list and slowed or blocked. see 10DLC validation
for number in sms_recipients:
print("Twilio sending to " + number)
try:
if sendmms: #send as MMS (usually more expensive than a typical sms message)
ret = client.messages.create(body = alert,
to = number, # number to be alerted
from_ = twilio_from, # Replace with your Twilio number
media_url = args.url) #have twilio convert the given URL into an attachemnt
else: #send plain text
ret = client.messages.create(body = alert, #everything needed (including URL) should be in the alert
to = number, # number to be alerted
from_ = twilio_from)
except TwilioRestException as e:
print("Send message to " + number + " error: " + e)
logging.warning("Send message to %s error: ", number, e)
51 changes: 0 additions & 51 deletions twilio_mms/twilio_mms.py

This file was deleted.

Binary file added upload_file/dist/libcrypto-1_1.dll
Binary file not shown.
Binary file added upload_file/dist/libffi-7.dll
Binary file not shown.
Binary file added upload_file/dist/libssl-1_1.dll
Binary file not shown.
Binary file added upload_file/dist/python38.dll
Binary file not shown.
Binary file modified upload_file/dist/uploadfile.exe
Binary file not shown.
19 changes: 19 additions & 0 deletions upload_file/example.upload.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"FTP_HOST": "<url or ip of server/host>",
"FTP_USER": "<username to login, can be specific to FTP/SFTP uploads>",
"FTP_PASS": "<password, ensure the password doesnt have a double quote in it>",
"FTP_PATH": "",
{"FTP_PATH-COMMENT":"//if there is a subdirectory the FTP upload must switch into to place the files <url>/pages for example would be '/pages' with forward but not trailing slash"},
"FTP_PORT": 22,
{"FTP_PORT-COMMENT":"//port to upload with, may be different if using SFTP"},
"FILE_URL": "http://example.com/pages",
{"FTP_URL-COMMENT":"//the public webpage path for the files to be accessed at. Take sthe file name and turns it into a live link to the mp3 file"},
"USE_SFTP": true,
{"USE_SFTP-COMMENT":"//set false to use typical unsecuried FTP, set to 'true' for SFTP uploads. at this time FTPS is likely not supported unless the SFTP library will auto swith to it"},
"AUDIO_FILES_PATH": "",
{"AUDIO_FILES_PATH-COMMENT":"//Used if the MP3 file was not a full path (eg. 'pagertest-date.mp3' was give vs 'C:\pages\pagertest-todaysdate.mp3'. If just the file name is passed set this to 'C:\pages\' to ensure the file is found"},
"POST_UP_COMMANDS": ["<path to tool>/pushNotifier.exe <path to json>/<department>.push.json -u ",
"C:/TTD/tools/twilioSMS.exe C:/TTD/tools/<department>.twilio.json -u "]
{"POST_UP_COMMANDS-COMMENT":"//a list of commands to run if the upload was a success. Will be run in sequence. Also has the public URL passed as a parameter at the end automaticly. Use / not \ to make python happy",
"POST_UP_COMMANDS-example":"c:/TTD/twilioSMS.exe c:/TTD/example.json -u http://example.com/pages/pagertest-2021-06-20-18-34-22.mp3 << URL auto appended to above command and run"}
}
10 changes: 0 additions & 10 deletions upload_file/example_config.json

This file was deleted.

Binary file added upload_file/pagetest.7z
Binary file not shown.
6 changes: 3 additions & 3 deletions upload_file/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import paramiko

setup(name = "UploadFile",
version = '1.0',
version = '1.1',
description = "Upload file over SFTP or FTP then call further processors with link",
author = "Hal Hockersmith",
console = [{'script': 'uploadfile.py'}],
Expand All @@ -15,8 +15,8 @@
'bundle_files': 2,
'compressed': True,
'excludes':[],
'includes':['paramiko','packaging','cffi'],
'packages':['paramiko','packaging'],
'includes':['paramiko','packaging','appdirs','cffi','logging','sys','argparse', 'json', 'logging', 'sys', 'subprocess', 'pathlib', 'ftplib'],
'packages':['paramiko','packaging','logging','cffi'],
'dll_excludes':['w9xpopen.exe']
}
}
Expand Down
Loading

0 comments on commit 0e574c5

Please sign in to comment.