-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdetectRemoteCommand.py
More file actions
executable file
·168 lines (147 loc) · 5.91 KB
/
detectRemoteCommand.py
File metadata and controls
executable file
·168 lines (147 loc) · 5.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#!/usr/bin/python
#
#SMS test via Google Voice
#
#Jonathan Huff
#zarcos@gmail.com
#
#
from googlevoice import Voice
import sys
import BeautifulSoup
from time import sleep
import datetime
import random
import subprocess
smsCommands = {'on':'''Power on''', 'off':'''Shutdown''', 'off_force':'''Force shutdown'''}
adminNumber = '8018306325'
executibles = {'on':'''on_power.py''', 'off':'''on_power.py''', 'off_force':'''off_power_force.py'''}
confirmedText = "I will now execute command "
executibleLocation = "/home/jkh777/"
def isSMScommand(msg):
try:
text = msg['text']
except TypeError as e:
return False
for i,key in enumerate(smsCommands):
if text == smsCommands[key]:
return True
return False
def isConfirmPin(msg, pin):
text = msg['text']
if text == pin:
return True
else:
return False
def sendVerifyText(msg):
input = msg['text']
key = getSmsCommandKey(input)
pin = str(random.randint(0,99999)).zfill(5)
verifyText = "Do you want to \n --> " + input + " <-- \nyour computer? Reply with \n--> " + pin + " <--\nwithin 5 minutes."
sendSMS(adminNumber,verifyText)
return pin
def verifyReceivedPin(waitTime,pin,msg):
#Login so we can see if we got what we wanted
voice.login()
voice.sms()
#Extract the SMS so we can look at it in a dictionary
msgs = extractsms(voice.sms.html)
#find the last message we received (not perfect. Based on order on the page. Multiple conversations messes this up. Thanks Google Voice!)
myLastSms = findLastMsgISent(msgs)
#retrive the command being sent and find the proper key for our dictionary, so we can execute the right command in our command dictionary
commandKey = getSmsCommandKey(msg['text'])
#Set up the loop we will use to poll for the text. Eventually I'll make it so this can be a script that runs in response to a script, but polling will do for now
timeElapsed = 0
while timeElapsed < waitTime:
#log in to get all the most recent SMS messages.
voice.login()
voice.sms()
msgs = extractsms(voice.sms.html)
# Find the key and the number of the text message to make sure it matches the PIN we want.
#If it's not a text that is newer than the one we just sent, then it's not valid.
#This is important, because we might otherwise find the PIN we sent out and think we got a reply, even though we didn't!
#Self fulfilling prophecies are not allowed
for i,key in enumerate(msgs):
if isConfirmPin(msgs[i],pin) & (i > myLastSms):
executeCommand(commandKey)
return
#Rather than poll constantly, we'll wait at least 30 seconds. Don't want Google to think we're trying to hack them!
sleep(30)
timeElapsed += 30
#-------------------------------------
def executeCommand(key):
try:
#Use the subprocess library to call the executible we'll be running in order to complete the SMS command we received.
subprocess.check_call(executibleLocation + executibles[key])
#Tell our user that we got their command and just finished doing it for them!
sendSMS(adminNumber,confirmedText+executibles[key])
print datetime.datetime.now().strftime("%A, %d. %B %Y %I:%M%p") + "I will now execute command " + executibles[key] + ".\n"
#We're finished! Lets clean up our inbox so things will work consistently next time!
deleteReadSMS()
except subprocess.CalledProcessError:
sendSMS(adminNumber, "Power operation >" + executibles[key] + "< failed.")
print datetime.datetime.now().strftime("%A, %d. %B %Y %I:%M%p") + "Power operation>" + executibles[key] + "< failed due to CalledProcessError.\n"
except OSError:
sendSMS(adminNumber, "Power operation >" + executibles[key] + "< failed.")
print datetime.datetime.now().strftime("%A, %d. %B %Y %I:%M%p") + "Power operation>" + executibles[key] + "< failed due to OS error.\n"
def deleteReadSMS():
#Delete the read SMS messages. Just what it says on the tin.
for message in voice.sms().messages:
if message.isRead:
message.delete()
def sendSMS(number,message):
#send a message to the NUMBER specified with the MESSAGE specified
voice.send_sms(number, message)
def getSmsCommandKey(text):
text
for i,key in enumerate(smsCommands):
if text == smsCommands[key]:
return key
def findLastMsgISent(msgs):
result = -1
for msgNumber,message in enumerate(msgs):
if message['from'] == 'Me:':
result = msgNumber
return result
def findLastMsgIReceived(msgs):
result = -1
for msgNumber,message in enumerate(msgs):
if message['from'] != 'Me:':
result = msgNumber
return result
def extractsms(htmlsms) :
"""
extractsms -- extract SMS messages from BeautifulSoup tree of Google Voice SMS HTML.
Output is a list of dictionaries, one per message.
"""
msgitems = [] # accum message items here
# Extract all conversations by searching for a DIV with an ID at top level.
tree = BeautifulSoup.BeautifulSoup(htmlsms) # parse HTML into tree
conversations = tree.findAll("div",attrs={"id" : True},recursive=False)
for conversation in conversations :
# For each conversation, extract each row, which is one SMS message.
rows = conversation.findAll(attrs={"class" : "gc-message-sms-row"})
for row in rows : # for all rows
# For each row, which is one message, extract all the fields.
msgitem = {"id" : conversation["id"]} # tag this message with conversation ID
spans = row.findAll("span",attrs={"class" : True}, recursive=False)
for span in spans : # for all spans in row
cl = span["class"].replace('gc-message-sms-', '')
msgitem[cl] = (" ".join(span.findAll(text=True))).strip() # put text in dict
msgitems.append(msgitem) # add msg dictionary to list
return msgitems
#Main Event Loop
voice = Voice()
voice.login()
voice.sms()
msgs = extractsms(voice.sms.html)
try:
msg = msgs[len(msgs)-1]
except IndexError as e:
print "no messages to check right now."
msg = []
key = ""
if isSMScommand(msg):
key = getSmsCommandKey(msg)
pin = sendVerifyText(msg)
verifyReceivedPin(5*60,pin,msg)