commit 89b7caaacc9bf8740d38131853abd766e3def564 Author: Julien Cabillot Date: Tue Aug 6 11:24:49 2019 -0400 Import diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..d2c12d0 --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +PB_APIKEY=xxxxxxxxx +PIN=0000 +GW_API=192.168.1.1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..91da32d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +launch.sh +app/__pycache__ +data/* diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7a8a9bc --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM "python:3.7-alpine" +LABEL maintainer="Cabillot Julien " + +COPY app /app + +WORKDIR "/app" + +RUN pip install -r requirements.txt + +USER "nobody" + +ENTRYPOINT [ "/app/entrypoint" ] diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..09ad2b6 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,38 @@ +pipeline { + environment { + registry = 'https://registry.hub.docker.com' + registryCredential = 'dockerhub_jcabillot' + dockerImage = 'jcabillot/huawei-3g-sms-api' + } + + agent any + + triggers { + cron('@midnight') + } + + stages { + stage('Clone repository') { + steps{ + checkout scm + } + } + + stage('Build image') { + steps{ + sh 'docker build -t ${dockerImage} .' + } + } + + stage('Deploy Image') { + steps{ + script { + withCredentials([usernamePassword(credentialsId: 'dockerhub_jcabillot', usernameVariable: 'DOCKER_USER', passwordVariable: 'DOCKER_PASS')]) { + sh 'docker login --username ${DOCKER_USER} --password ${DOCKER_PASS}' + sh 'docker push ${dockerImage}' + } + } + } + } + } +} diff --git a/app/README.md b/app/README.md new file mode 100644 index 0000000..27a7f88 --- /dev/null +++ b/app/README.md @@ -0,0 +1,11 @@ +# huawei-3G-SMS-API + +Program to check for SMS messages, archive and send via email + +In future it will also include sending SMS + + +Thanks to: +https://github.com/juslop/3G-tunnel/blob/master/pi_sms.py +https://github.com/trick77/huawei-hilink-status/blob/master/hstatus.py +https://trick77.com/query-status-information-huaweis-hilink-3g-lte-modems/ diff --git a/app/entrypoint.sh b/app/entrypoint.sh new file mode 100644 index 0000000..4326b7d --- /dev/null +++ b/app/entrypoint.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +if [[ -z "${PB_APIKEY}" ]] +then + echo 'Please define the env var PB_APIKEY, exit' >&2 + exit 1 +fi + +if [[ -z "${PIN}" ]] +then + echo 'Please define the env var PIN, exit' >&2 + exit 2 +fi + +if [[ -z "${GW_API}" ]] +then + echo 'Please define the env var GW_API, exit' >&2 + exit 3 +fi + +python3 "/app/sms.py" diff --git a/app/requirements.txt b/app/requirements.txt new file mode 100644 index 0000000..12f3ce4 --- /dev/null +++ b/app/requirements.txt @@ -0,0 +1,2 @@ +pushbullet.py==0.11.0 +xmltodict==0.12.0 diff --git a/app/sendEmail.py b/app/sendEmail.py new file mode 100644 index 0000000..0d63202 --- /dev/null +++ b/app/sendEmail.py @@ -0,0 +1,14 @@ +import smtplib + +def sendmail(subject, message, to): + fromaddr = 'EMAIL-ADDRESS' + toaddrs = to + msg = "Subject: %s\n\n%s" % (subject, message) + username = 'EMAIL-ADDRESS' + password = 'PASSWORD' + server = smtplib.SMTP('smtp.gmail.com:587') #default server for gmail, change if not using gmail + server.ehlo() + server.starttls() + server.login(username,password) + server.sendmail(fromaddr, toaddrs, msg) + server.quit() diff --git a/app/sms.py b/app/sms.py new file mode 100644 index 0000000..82324bd --- /dev/null +++ b/app/sms.py @@ -0,0 +1,180 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import sys, os +import xmltodict +import requests +import json +import time +from pushbullet import Pushbullet + +pb = Pushbullet(os.environ['PB_APIKEY']) + +pin = os.environ['PIN'] + +PIN_ENTER_TEMPLATE = ''' + 0 + ''' + PIN + ''' + + + ''' + +SMS_LIST_TEMPLATE = ''' + 1 + 20 + 1 + 0 + 0 + 0 + ''' + +SMS_DEL_TEMPLATE = '{index}' + +"""SMS_SEND_TEMPLATE = ''' + -1 + {phone} + + {content} + {length} + 1 + {timestamp} + ''' + """ + +__location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__))) + +def isHilink(device_ip): + try: + r = requests.get(url='http://' + device_ip + '/api/device/information', timeout=(2.0,2.0)) + except requests.exceptions.RequestException as e: + return False; + + if r.status_code != 200: + return False + return True + +def getHeaders(device_ip): + token = None + sessionID = None + try: + r = requests.get(url='http://' + device_ip + '/api/webserver/SesTokInfo') + except requests.exceptions.RequestException as e: + return (token, sessionID) + try: + d = xmltodict.parse(r.text, xml_attribs=True) + if 'response' in d and 'TokInfo' in d['response']: + token = d['response']['TokInfo'] + d = xmltodict.parse(r.text, xml_attribs=True) + if 'response' in d and 'SesInfo' in d['response']: + sessionID = d['response']['SesInfo'] + headers = {'__RequestVerificationToken': token, 'Cookie': sessionID} + except: + pass + return headers + + +def getSMS(device_ip, headers): + r = requests.post(url = 'http://' + device_ip + '/api/sms/sms-list', data = SMS_LIST_TEMPLATE, headers = headers) + d = xmltodict.parse(r.text, xml_attribs=True) + numMessages = int(d['response']['Count']) + messagesR = d['response']['Messages']['Message'] + if numMessages == 1: + temp = messagesR + messagesR = [temp] + messages = getContent(messagesR, numMessages) + return messages, messagesR + +def statusPin(device_ip, headers): + r = requests.get(url = 'http://' + device_ip + '/api/pin/status', headers = headers) + d = xmltodict.parse(r.text, xml_attribs=True) + state = int(d['response']['SimState']) + return state + +def enterPin(pin, device_ip, headers): + r = requests.post(url = 'http://' + device_ip + '/api/pin/operate', data = PIN_ENTER_TEMPLATE, headers = headers) + d = xmltodict.parse(r.text, xml_attribs=True) + print(d['response']) + +def getContent(data, numMessages): + messages = [] + for i in range(numMessages): + message = data[i] + number = message['Phone'] + content = message['Content'] + date = message['Date'] + messages.append('Message from ' + number + ' recieved ' + date + ' : ' + str(content)) + return messages + +def delMessage(device_ip, headers, ind): + r = requests.post(url = 'http://' + device_ip + '/api/sms/delete-sms', data = SMS_DEL_TEMPLATE.format(index=ind), headers = headers) + d = xmltodict.parse(r.text, xml_attribs=True) + print(d['response']) + +def getUnread(device_ip, headers): + r = requests.get(url = 'http://' + device_ip + '/api/monitoring/check-notifications', headers = headers) + d = xmltodict.parse(r.text, xml_attribs=True) + unread = int(d['response']['UnreadMessage']) + return unread + +if __name__ == "__main__": + while True: + device_ip = os.environ['GW_IP'] + if not isHilink(device_ip): + print("Can't find a Huawei HiLink device on " + device_ip + ", exit") + print('') + sys.exit(-1) + + headers = getHeaders(device_ip) + # Require to enter the PIN to unlock device + if statusPin(device_ip, headers) == 260: + print('# Configure PIN') + enterPin(os.environ['PIN'], device_ip, headers) + + unread = getUnread(device_ip, headers) + print('# Unread message(s) : %d' % unread) + if unread != 0: + messages, messagesR = getSMS(device_ip, headers) + + #Read + if not os.path.exists(os.path.join(__location__,'data',)): + os.makedirs(os.path.join(__location__,'data')) + try: + f1 = open(os.path.join(__location__,'data',"sms.json"), 'r') + data = json.load(f1) + f1.close() + except: + data = [] + + f3 = open(os.path.join(__location__,'data',"sms.txt"), 'a') + + # Ok, fonctionnel + for i in range(len(messages)): + # Json + print('# Log JSON') + data.append(messagesR[i]) + + # Text + f3.write(messages[i] + '\n') + # Pushbullet + print('# Notif pushbullet') + pb.push_note("SMS", "From: %s\nDate: %s\n%s" % (messagesR[i]['Phone'], messagesR[i]['Date'], messagesR[i]['Content'])) + + # Log HTTP + print('# Notif HTTP') + datam = {'sender' : messagesR[i]['Phone'], 'date': messagesR[i]['Date'], 'content': messagesR[i]['Content']} + r = requests.post(url="https://sms.cabillot.eu", headers={'Content-Type': 'application/json' }, json=datam) + #print(r.status_code) + + #Save + f2 = open(os.path.join(__location__,'data',"sms.json"), 'w') + json.dump(data, f2) + f2.close() + + f3.close() + + #delete from device + for i in range(len(messagesR)): + headers = getHeaders(device_ip) + delMessage(device_ip, headers, messagesR[i]['Index']) + + time.sleep(30) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d472ed1 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,20 @@ +version: '2.3' + +services: + offlineimap: + image: "jcabillot/huawei-3g-sms-api" + container_name: "huawei-3g-sms-api" + restart: "unless-stopped" + mem_limit: "256m" + cpus: 0.3 + cpu_shares: 1024 + pids_limit: 200 + volumes: + # To store plain text & json logs + - "./data:/app/data" + environment: + - "PB_APIKEY" + - "PIN" + - "GW_API" + security_opt: + - "no-new-privileges"