Commit 66bcb6d0 authored by nextime's avatar nextime

first commit to github

parent 4032007f
##########################################################################
# Copyright (c) 2011-2013 Unixmedia S.r.l. <info@unixmedia.it>
# Copyright (c) 2011-2013 Franco (nextime) Lanza <franco@unixmedia.it>
#
# Domotika System Controller Daemon "domotikad" [http://trac.unixmedia.it]
#
# This file is part of domotikad.
#
# domotikad 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
###########################################################################
# Copyright=c) 2011-2013 Unixmedia S.r.l. <info@unixmedia.it>
# Copyright=c) 2011-2013 Franco=nextime) Lanza <franco@unixmedia.it>
#
# Domotika System Controller Daemon "domotikad" [http://trac.unixmedia.it]
#
# This file is part of domotikad.
#
# domotikad 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
UDP_IKA_PORT=12080
UDP_IKA_VERSION=1
IKAP_STARTBYTE=0xa5
IKAP_BROADCAST="\0\0\0\0"
# Encoding types
IKAP_ENC_CLEAR=0x00
IKAP_ENC_XTEA=0x01
IKAP_ENC_XTEA_CBC=0x02
IKAP_ENC_XXTEA=0x03
IKAP_ENC_ARCFOUR=0x04
IKAP_ENC_AES128=0x05
IKAP_ENC_AES256=0x06
# Message Type
IKAP_MSG_NULL=0x00
IKAP_MSG_REQUEST=0x01
IKAP_MSG_ACTION=0x02
IKAP_MSG_ACK=0x03
IKAP_MSG_NOTIFY=0x04
IKAP_MSG_NOTIFYCONF=0x05
IKAP_MSG_REQUESTCONF=0x06
IKAP_MSG_SETCONF=0x07
IKAP_MSG_DEBUG=0xff
# Context
IKAP_CTX_NULL=0x0000
IKAP_CTX_LIGHT=0x0001
IKAP_CTX_SOCKET=0x0002
IKAP_CTX_BLIND=0x0003
IKAP_CTX_SENSOR=0x0004
IKAP_CTX_DOOR=0x0005
IKAP_CTX_WINDOW=0x0006
IKAP_CTX_VALVE=0x0007
IKAP_CTX_STATUS=0x0008
IKAP_CTX_SCENARY=0x0009
IKAP_CTX_ALARM=0x000a
IKAP_CTX_CITOPHONE=0x000b
IKAP_CTX_GENERIC_SWITCH=0x000c
IKAP_CTX_TERMOSTAT=0x000d
IKAP_CTX_GATE=0x000e
IKAP_CTX_AUDIO=0x000f
IKAP_CTX_VIDEO=0x0010
IKAP_CTX_PHONE=0x0011
IKAP_CTX_TV=0x0012
IKAP_CTX_IRRIGATION=0x0013
IKAP_CTX_TIMER=0x0014
IKAP_CTX_INTERNET=0x0015
IKAP_CTX_MESSAGE=0x0016
IKAP_CTX_RFID=0x0017
IKAP_CTX_PUMP=0x0018
IKAP_CTX_MOTOR=0x0019
IKAP_CTX_TENT=0x01a
IKAP_CTX_RTC=0x0020
IKAP_CTX_SEQUENCE=0x0021
IKAP_CTX_SYSTEM=0xfffe
IKAP_CTX_USER=0xffff
SECTIONS={
IKAP_CTX_NULL: "none",
IKAP_CTX_LIGHT: "light",
IKAP_CTX_SOCKET: "socket",
IKAP_CTX_BLIND: "blind",
IKAP_CTX_SENSOR: "sensor",
IKAP_CTX_DOOR: "door",
IKAP_CTX_WINDOW: "finestra",
IKAP_CTX_VALVE: "valvle",
IKAP_CTX_STATUS: "stato",
IKAP_CTX_SCENARY: "scenario",
IKAP_CTX_ALARM: "allarme",
IKAP_CTX_CITOPHONE: "citofono",
IKAP_CTX_GENERIC_SWITCH: "accensione",
IKAP_CTX_TERMOSTAT: "clima",
IKAP_CTX_GATE: "cancello",
IKAP_CTX_AUDIO: "audio",
IKAP_CTX_VIDEO: "video",
IKAP_CTX_PHONE: "telefonia",
IKAP_CTX_TV: "tv",
IKAP_CTX_IRRIGATION: "irrigazione",
IKAP_CTX_TIMER: "timer",
IKAP_CTX_INTERNET: "network",
IKAP_CTX_MESSAGE: "messaggio",
IKAP_CTX_RFID: "rfid",
IKAP_CTX_PUMP: "pompa",
IKAP_CTX_MOTOR: "motore",
IKAP_CTX_TENT: "tenda",
IKAP_CTX_RTC: "dataora",
IKAP_CTX_SEQUENCE: "sequenza",
IKAP_CTX_SYSTEM: "sistema",
IKAP_CTX_USER: "user"
}
#Actions
IKAP_ACT_NULL=0x00
IKAP_ACT_ON=0x01
IKAP_ACT_OFF=0x02
IKAP_ACT_CHANGE=0x03
IKAP_ACT_OPEN=0x04
IKAP_ACT_CLOSE=0x05
IKAP_ACT_UP=0x06
IKAP_ACT_DOWN=0x07
IKAP_ACT_STOP=0x08
IKAP_ACT_START=0x09
IKAP_ACT_STOPTIMERED=0x0a
IKAP_ACT_STARTTIMERED=0x0b
IKAP_ACT_BLOCKUNBLOCK=0x0c
IKAP_ACT_BLOCK=0x0d
IKAP_ACT_UNBLOCK=0x0e
IKAP_ACT_HI=0x0f
IKAP_ACT_LOW=0x10
IKAP_ACT_EQUAL=0x11
IKAP_ACT_EXPIRED=0x12
IKAP_ACT_TIMEDOUT=0x13
IKAP_ACT_CHANGED=0x14
IKAP_ACT_SWITCHEDON=0x15
IKAP_ACT_SWITCHEDOFF=0x16
IKAP_ACT_CALL=0x17
IKAP_ACT_ANSWER=0x18
IKAP_ACT_RING=0x19
IKAP_ACT_PLAY=0x1a
IKAP_ACT_PAUSE=0x1b
IKAP_ACT_PAUSE_CLOSING=0x1c
IKAP_ACT_PAUSE_OPENING=0x1d
IKAP_ACT_NEXT=0x1e
IKAP_ACT_CLOSING=0x1f
IKAP_ACT_OPENING=0x20
IKAP_ACT_ASK=0x21
IKAP_ACT_BOARD=0xfd
IKAP_ACT_DEBUG=0xff
DM_OUTPUT_TYPE_NULL=0x00
DM_OUTPUT_TYPE_ONOFF=0x01
DM_OUTPUT_TYPE_IMPULSO=0x02
DM_OUTPUT_TYPE_TEMPORIZZATA=0x03
DM_OUTPUT_TYPE_INTERMITTENTE=0x04
DM_OUTPUT_TYPE_INTERMITTENTE_TEMPORIZZATA=0x05
DM_OUTPUT_TYPE_SIGNALING=0x06
DM_OUTPUT_TYPE_PWM=0x07
DM_OUTPUT_TYPE_DIMMER=0x08
DM_OUTPUT_TYPE_2_RELAY_EXCLUSIVE=0xf0
DM_OUTPUT_TYPE_2_RELAY_INCLUSIVE_ON=0xf1
DM_OUTPUT_TYPE_2_RELAY_INCLUSIVE_OFF=0xf2
DM_OUTPUT_TYPE_2_RELAY_ALTERNATE_SEQ=0xf3
DM_OUTPUT_TYPE_OPEN_CLOSE_2_RELAYS=0xf4
DM_OUTPUT_TYPE_RGB=0xfa
DM_OUTPUT_TYPE_SEQUENZA=0xff
RELAY_ACT={
0: "OPEN",
1: "CLOSE",
2: "CHANGE"
}
SEQUENCE_TYPE_NULL=0x00
SEQUENCE_TYPE_CONTINUE=0x01
SEQUENCE_TYPE_RANDOM=0x02
SEQUENCE_TYPE_CYCLE=0x03
SEQUENCE_TYPE_CONTINUE_RANDOM=0x04
SEQUENCE_TYPE_CYCLE_RANDOM=0x05
VIDEO_TYPE_NULL=0x00
VIDEO_TYPE_IPCAM=0x01
# BYTE ORDER!
MOTION_STATUS_START=0x01
MOTION_STATUS_UPDATE=0x02
MOTION_STATUS_STOP=0x04
MOTION_STATUS_ALL=0xff
MOTION_TYPE_MOTION=0x01
DM_INPUT_TYPE_DIGITAL=0xff
DM_INPUT_TYPE_ANALOG=0x00
DM_ARGTYPE_NULL=0x00
DM_ARGTYPE_RGB_TRANSITION=0x01
DM_ARGTYPE_PRESET=0x02
DM_ARGTYPE_DIMMER=0x03
DM_DIGITAL_INPUT_TYPE_NULL=0x00
DM_DIGITAL_INPUT_TYPE_SINGLECLICK=0x01
DM_DIGITAL_INPUT_TYPE_LONG=0x02
DM_DIGITAL_INPUT_TYPE_CHANGE=0x03
DM_DIGITAL_INPUT_TYPE_CONTINUOS_OPEN=0x04
DM_DIGITAL_INPUT_TYPE_CONTINUOS_CLOSE=0x05
DM_DIGITAL_INPUT_TYPE_PULSE_OPEN=0x90
DM_DIGITAL_INPUT_TYPE_PULSE_OPEN_COUNT=0x91
DM_DIGITAL_INPUT_TYPE_PULSE_CLOSE=0x92
DM_DIGITAL_INPUT_TYPE_PULSE_CLOSE_COUNT=0x93
DM_DIGITAL_INPUT_TYPE_PULSE_CHANGE=0x94
DM_DIGITAL_INPUT_TYPE_PULSE_CHANGE_COUNT=0x95
DM_DIGITAL_INPUT_TYPE_DOUBLECLICK=0xa0
DM_DIGITAL_INPUT_TYPE_SINGLE_AND_LONG=0xa1
DM_DIGITAL_INPUT_TYPE_CLICK_AND_CONTINUOS_CLOSE=0xa2
DM_DIGITAL_INPUT_TYPE_OPENCLOSE=0xa3
DM_DIGITAL_INPUT_TYPE_CONTINUOS_OPENCLOSE=0xa4
DM_DIGITAL_INPUT_TYPE_SEQUENCE2=0xb0
DM_DIGITAL_INPUT_TYPE_SEQUENCE2STEP=0xb1
DM_DIGITAL_INPUT_TYPE_PULSE_OPEN_DOUBLE=0xc0
DM_DIGITAL_INPUT_TYPE_PULSE_CLOSE_DOUBLE=0xc1
DM_DIGITAL_INPUT_TYPE_PULSE_CHANGE_DOUBLE=0xc2
DM_DIGITAL_INPUT_TYPE_TRIPLE=0xd0
DM_DIGITAL_INPUT_TYPE_SEQUENCE3=0xe0
DM_ANALOG_INPUT_TYPE_NULL=0x00
DM_ANALOG_INPUT_TYPE_GENERIC=0x01
DM_ANALOG_INPUT_TYPE_TEMPERATURE=0x02
DM_ANALOG_INPUT_TYPE_HUMIDITY=0x03
DM_ANALOG_INPUT_TYPE_CURRENT=0x04
DM_ANALOG_INPUT_TYPE_WIND=0x05
DM_ANALOG_INPUT_TYPE_SPEED=0x06
DM_ANALOG_INPUT_TYPE_PRESSURE=0x07
DM_ANALOG_INPUT_TYPE_FLUX=0x08
DM_ANALOG_INPUT_TYPE_LIGHT=0x09
DM_ANALOG_INPUT_TYPE_LEVEL=0x0a
BOARD_MODULE_NONE=0x00
BOARD_MODULE_97j60=0x01
BOARD_MODULE_67j60M=0x02
BOARD_MODULE_67j60S=0x03
BOARD_MODULE_67j60_Wifi=0x04
BOARD_MODULE_97j60_Wifi=0x05
BOARD_MODULE_2620=0x06
BOARD_MODULE_2685=0x07
BOARD_WORKER_12R12I_v1=0x0001
BOARD_WORKER_12R12I_v3=0x0002
BOARD_WORKER_RFID=0x0003
BOARD_WORKER_DIMMER=0x0004
BOARD_WORKER_SENSORS=0x0005
BOARD_WORKER_GW=0x0006
BOARD_WORKER_RGBLED=0x0007
BOARD_WORKER_DMSNT84=0x0008
BOARD_WORKER_RGBLED4=0x0009
FWTYPE_IRRIGAZIONE=0x01
FWTYPE_RELAYMASTER=0x02
FWTYPE_CANCELLI=0x03
FWTYPE_1TO1=0x04
FWTYPE_ALARM=0x05
FWTYPE_LIGHT=0x06
FWTYPE_TAPPARELLE=0x07
FWTYPE_DMLED=0x08
FWTYPE_DMLED4=0x09
FWTYPE_TESTDMR3=0xff
#############################################################################
#
# $Id: daemonizer.py,v 1.3 2005/01/22 01:05:44 irmen Exp $
# Run Pyro servers as daemon processes on Unix/Linux.
# This won't work on other operating systems such as Windows.
# Author: Jeff Bauer (jbauer@rubic.com)
# This software is released under the MIT software license.
# Based on an earlier daemonize module by Jeffery Kunce
# Updated by Luis Camaano to double-fork-detach.
#
# This is part of "Pyro" - Python Remote Objects
# which is (c) Irmen de Jong - irmen@users.sourceforge.net
#
#############################################################################
import sys, os, time
from signal import SIGINT, SIGHUP
import logging
import pwd, grp
import getopt
log = logging.getLogger( 'DaemonStarter' )
class DaemonizerException:
def __init__(self, msg):
self.msg = msg
def __str__(self):
return self.msg
class Daemonizer:
"""
Daemonizer is a class wrapper to run a Pyro server program
in the background as daemon process. The only requirement
is for the derived class to implement a main_loop() method.
See Test class below for an example.
The following command line operations are provided to support
typical /etc/init.d startup/shutdown on Unix systems:
start | stop | restart
In addition, a daemonized program can be called with arguments:
status - check if process is still running
debug - run the program in non-daemon mode for testing
Note: Since Daemonizer uses fork(), it will not work on non-Unix
systems.
"""
def __init__(self, pidfile=None):
log.debug("Calling Daemonizer orig. init")
if not pidfile:
self.pidfile = "/tmp/%s.pid" % self.__class__.__name__.lower()
else:
self.pidfile = pidfile
self.chuid=False
self.chuid_actions=False
def become_daemon(self, root_dir='/'):
log.debug("Become Daemon")
if os.fork() != 0: # launch child and ...
os._exit(0) # kill off parent
log.debug("Calling setsid")
os.setsid()
log.debug("Calling chdir")
os.chdir(root_dir)
log.debug("Calling umask")
os.umask(0)
log.debug("Calling fork")
if os.fork() != 0: # fork again so we are not a session leader
os._exit(0)
log.debug("Wrapping stdin")
sys.stdin.close()
sys.__stdin__ = sys.stdin
log.debug("Wrapping stdout")
sys.stdout.close()
sys.stdout = sys.__stdout__ = _NullDevice()
log.debug("Wrapping stderr")
sys.stderr.close()
sys.stderr = sys.__stderr__ = _NullDevice()
#sys.stderr = sys.__stderr__ = log.debug
log.debug("Daemonized")
#for fd in range(1024):
# try:
# os.close(fd)
# except OSError:
# pass
def daemon_start(self, start_as_daemon=1, root_dir='/'):
log.debug("Daemon Start")
if start_as_daemon:
self.become_daemon(root_dir)
log.debug("Checking if the process is already running")
if self.is_process_running():
msg = "Unable to start server. Process is already running."
raise DaemonizerException(msg)
log.debug("Writing pid file")
f = open(self.pidfile, 'w')
f.write("%s" % os.getpid())
f.close()
log.debug("Calling main_loop")
if self.chuid:
log.debug("Change running privileges to "+str(self.chuid))
print 'Change running privileges to', str(self.chuid)
self.change_uid(self.chuid)
self.main_loop()
def daemon_stop(self):
pid = self.get_pid()
try:
os.kill(pid, SIGINT) # SIGTERM is too harsh...
time.sleep(1)
try:
os.unlink(self.pidfile)
except OSError:
pass
except IOError:
pass
def daemon_reload(self):
pid = self.get_pid()
try:
os.kill(pid, SIGHUP)
except:
pass
def get_pid(self):
try:
f = open(self.pidfile)
pid = int(f.readline().strip())
f.close()
except IOError:
pid = None
return pid
def is_process_running(self):
pid = self.get_pid()
if pid:
try:
os.kill(pid, 0)
return 1
except OSError:
pass
return 0
def main_loop(self):
"""NOTE: This method must be implemented in the derived class."""
msg = "main_loop method not implemented in derived class: %s" % \
self.__class__.__name__
raise DaemonizerException(msg)
def change_uid(self, uid):
c_user = uid
c_group = None
print os.getuid
if os.getuid() == 0:
if ':' in c_user:
c_user, c_group = c_user.split(":", 1)
cpw = pwd.getpwnam(c_user)
c_uid = cpw.pw_uid
if c_group:
cgr = grp.getgrnam(c_group)
c_gid = cgr.gr_gid
else:
c_gid = cpw.pw_gid
c_group = grp.getgrgid(cpw.pw_gid).gr_name
c_groups = []
for item in grp.getgrall():
if c_user in item.gr_mem:
c_groups.append(item.gr_gid)
if c_gid not in c_groups:
c_groups.append(c_gid)
if callable(self.chuid_actions):
self.chuid_actions(c_uid, c_gid)
os.setgid(c_gid)
os.setgroups(c_groups)
os.setuid(c_uid)
def process_command_line(self, argv, verbose=1, usagestr=None, chuid_actions=False):
usage = "usage: %s [options] start | stop | reload | restart | status | debug " \
"(run as non-daemon)\n\n" \
% os.path.basename(argv[0])
usage += "OPTIONS:\n"
usage += "\t--chuid=<username[:group]>\tchange username and group of the running process\n"
try:
optlist, args = getopt.getopt(argv[1:], "", ['chuid='])
for opt in optlist:
if opt[0] == '--chuid':
self.chuid=opt[1]
self.chuid_actions=chuid_actions
except:
pass
if usagestr:
usage += usagestr
if len(argv) < 2:
print usage
raise SystemExit
else:
operation = argv[len(argv)-1]
pid = self.get_pid()
if operation == 'status':
if self.is_process_running():
print "Server process %s is running." % pid
else:
print "Server is not running."
elif operation == 'start':
if self.is_process_running():
print "Server process %s is already running." % pid
raise SystemExit
else:
if verbose:
print "Starting server process."
self.daemon_start(1, os.path.abspath(os.path.dirname(argv[0])))
elif operation == 'stop':
if self.is_process_running():
self.daemon_stop()
if verbose:
print "Server process %s stopped." % pid
else:
print "Server process %s is not running." % pid
raise SystemExit
elif operation == 'reload':
if self.is_process_running():
if verbose:
print "Reloading server process."
self.daemon_reload()
else:
if verbose:
print "Server isn't running. Starting it."
self.daemon_start(1, os.path.abspath(os.path.dirname(argv[0])))
elif operation == 'restart':
self.daemon_stop()
if verbose:
print "Restarting server process."
self.daemon_start(1, os.path.abspath(os.path.dirname(argv[0])))
elif operation == 'debug':
self.daemon_start(0, os.path.abspath(os.path.dirname(argv[0])))
else:
print "Unknown operation:", operation
raise SystemExit
class _NullDevice:
"""A substitute for stdout/stderr that writes to nowhere."""
def isatty(self, *a, **kw):
return False
def write(self, s):
pass
def flush(self, s):
pass
class Test(Daemonizer):
def __init__(self):
Daemonizer.__init__(self)
def main_loop(self):
while 1:
time.sleep(1)
if __name__ == "__main__":
test = Test()
test.process_command_line(sys.argv)
###########################################################################
# Copyright (c) 2011-2013 Unixmedia S.r.l. <info@unixmedia.it>
# Copyright (c) 2011-2013 Franco (nextime) Lanza <franco@unixmedia.it>
#
# Domotika System Controller Daemon "domotikad" [http://trac.unixmedia.it]
#
# This file is part of domotikad.
#
# domotikad 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
import struct
import base64
from Crypto.Cipher import AES
try:
import hashlib
md5 = hashlib
md5.new = hashlib.md5
sha1 = hashlib.sha1
except:
import md5
import sha1
DMHASH=[
0x18a677e4,
0x11de784a,
0x51ae08b6,
0x22679cb0
]
def DMHash128(data):
import copy
reshash=copy.deepcopy(DMHASH)
i=0
while(len(data)<16):
data+=struct.pack('B', struct.unpack('B', data[i])[0]^struct.unpack('B', data[len(data)-1])[0])
i+=1
data=struct.unpack('<4I', data[:16])
i=0
while(i<4):
reshash[i]=reshash[i]^data[i]
i+=1
return struct.pack('<4I', *reshash)
def DMHash256(data):
import copy
reshash=copy.deepcopy(DMHASH)
reshash+=reshash
i=0
while(len(data)<32):
data+=struct.pack('B', struct.unpack('B', data[i])[0]^struct.unpack('B', data[len(data)-1])[0])
i+=1
data=struct.unpack('<8I', data[:32])
i=0
while(i<8):
reshash[i]=reshash[i]^data[i]
i+=1
i=0
while(i<4):
reshash[i]=reshash[i]^reshash[i+4]
i+=1
return struct.pack('<8I', *reshash)
class ARCFOUR(object):
def __init__(self,key,drop_n_bytes=768):
self.ksa = self.make_key(key,drop_n_bytes)
def encrypt_byte(self, i,j,S):
i = (i+1) % 256
j = (j+S[i]) % 256
S[i], S[j] = S[j],S[i]
K = S[(S[i] + S[j])%256]
return (i,j,K)
def make_key(self, key, drop_n_bytes):
#The key-scheduling algorithm (KSA)
S = [i for i in range(256)]
j = 0
for i in range(256):
j = (j + S[i] + ord(key[i % len(key)])) % 256
S[i], S[j] = S[j],S[i]
self.i = 0
self.j = 0
#Do the RC4-drop[(nbytes)]
if drop_n_bytes:
#i = j = 0
for dropped in range(drop_n_bytes):
self.i,self.j,K = self.encrypt_byte(self.i,self.j,S)
return S
def __crypt(self, message):
#The pseudo-random generation algorithm (PRGA)
S = list(self.ksa) #make a deep copy of you KSA array, gets modified
combined = []
counter = 0
i,j = self.i, self.j
for c in message:
i,j,K = self.encrypt_byte(i,j,S)
combined.append(struct.pack('B', (K ^ ord(c))))
crypted = (''.join(combined))
return crypted
def encode(self,message,encodeBase64=True):
crypted = self.__crypt(message)
if encodeBase64:
crypted = base64.urlsafe_b64encode(crypted)
return crypted
def decode(self,message,encodedBase64=True):
if encodedBase64:
message = base64.urlsafe_b64decode(message.encode())
return self.__crypt(message)
class XTEABlock(object):
cleandata=""
encdata=""
key=""
delta = 0x9e3779b9L
mask = 0xffffffffL
rounds=32
def __init__(self, key):
self.key=(int(key[0:][:8], 16), int(key[8:][:8], 16), int(key[16:][:8], 16), int(key[24:][:8], 16))
def setCleanData(self, data):
self.cleandata=data
self._encrypt(data)
def setEncryptData(self, data):
self.encdata=data
self._decrypt(data)
def _encrypt(self, data):
block=struct.unpack("<2L",data)
v0,v1=block[0], block[1]
sum=0L
for round in range(self.rounds):
v0 = (v0 + (((v1<<4 ^ v1>>5) + v1) ^ (sum + self.key[sum & 3]))) & self.mask
sum = (sum + self.delta) & self.mask
v1 = (v1 + (((v0<<4 ^ v0>>5) + v0) ^ (sum + self.key[sum>>11 & 3]))) & self.mask
self.encdata=struct.pack("<2L",v0,v1)
def _decrypt(self, data):
block=struct.unpack("<2L",data)
v0,v1=block[0], block[1]
sum = self.delta*self.rounds
for round in range(self.rounds):
v1 = (v1 - (((v0<<4 ^ v0>>5) + v0) ^ (sum + self.key[sum>>11 & 3]))) & self.mask
sum = (sum-self.delta) & self.mask;
v0 = (v0 - (((v1<<4 ^ v1>>5) + v1) ^ (sum + self.key[sum & 3]))) & self.mask
self.cleandata=struct.pack("<2L",v0,v1)
def raw_xxtea(v, n, k):
assert type(v) == type([])
assert type(k) == type([]) or type(k) == type(())
assert type(n) == type(1)
def MX():
return ((z>>5)^(y<<2)) + ((y>>3)^(z<<4))^(sum^y) + (k[(p & 3)^e]^z)
def u32(x):
return x & 0xffffffffL
y = v[0]
sum = 0
DELTA = 0x9e3779b9
if n > 1: # Encoding
z = v[n-1]
q = 6 + 52 / n
while q > 0:
q -= 1
sum = u32(sum + DELTA)
e = u32(sum >> 2) & 3
p = 0
while p < n - 1:
y = v[p+1]
z = v[p] = u32(v[p] + MX())
p += 1
y = v[0]
z = v[n-1] = u32(v[n-1] + MX())
return 0
elif n < -1: # Decoding
n = -n
q = 6 + 52 / n
sum = u32(q * DELTA)
while sum != 0:
e = u32(sum >> 2) & 3
p = n - 1
while p > 0:
z = v[p-1]
y = v[p] = u32(v[p] - MX())
p -= 1
z = v[n-1]
y = v[0] = u32(v[0] - MX())
sum = u32(sum - DELTA)
return 0
return 1
class BTEABlock(object):
cleandata=""
encdata=""
key=""
def __init__(self, key):
self.key=(int(key[0:][:8], 16), int(key[8:][:8], 16), int(key[16:][:8], 16), int(key[24:][:8], 16))
def setCleanData(self, data):
self.cleandata=data
self._encrypt(data)
def setEncryptData(self, data):
#print len(data)
self.encdata=data
self._decrypt(data)
def _encrypt(self, data):
ldata = len(data) / 4
block=list(struct.unpack("<%dL" % ldata ,data))
if raw_xxtea(block, ldata, self.key) == 0:
self.encdata=struct.pack("<%dL" % ldata, *block)
def _decrypt(self, data):
ldata = len(data) / 4
#print ldata, len(data)
block=list(struct.unpack("<%dL" % ldata ,data))
#print 'AAA', block
#print block
if raw_xxtea(block, -ldata, self.key) == 0:
#print 'AAA', block
self.cleandata=struct.pack("<%dL" % ldata ,*block)
class AES256(object):
cleandata=""
encdata=""
key=""
iv=""
def __init__(self, key, iv):
self.key=key
self.iv=iv
def setCleanData(self, data):
self.cleandata=data
self._encrypt(data)
def setEncryptData(self, data):
#print len(data)
self.encdata=data
self._decrypt(data)
def _encrypt(self, data):
ldata = len(data) / 4
key=struct.pack("<8L", *self.key)
iv=struct.pack("<4L", *self.iv)
obj=AES.new(key, AES.MODE_CBC, iv)
#block=list(struct.unpack("<%dL" % ldata ,data))
#enc=obj.encrypt(block)
#self.encdata=struct.pack("<%dL" % ldata, *enc)
self.encdata=obj.encrypt(data)
def _decrypt(self, data):
ldata = len(data) / 4
key=struct.pack("<8L", *self.key)
iv=struct.pack("<4L", *self.iv)
obj=AES.new(key, AES.MODE_CBC, iv)
#block=list(struct.unpack("<%dL" % ldata ,data))
#dec=obj.decrypt(block)
#self.cleandata=struct.pack("<%dL" % ldata ,*dec)
self.cleandata=obj.decrypt(data)
BLOCK_SIZE = 32
INTERRUPT = u'\u0001'
PAD = u'\u0000'
def AddPadding(data, interrupt, pad, block_size):
new_data = ''.join([data, interrupt])
new_data_len = len(new_data)
remaining_len = block_size - new_data_len
to_pad_len = remaining_len % block_size
pad_string = pad * to_pad_len
return ''.join([new_data, pad_string])
def StripPadding(data, interrupt, pad):
return data.rstrip(pad).rstrip(interrupt)
def B64AESEncrypt(key, iv, data):
c = md5.new()
c.update(key)
i = md5.new()
i.update(iv)
cipher = AES.new(c.hexdigest(), AES.MODE_CBC, i.hexdigest()[:16])
padded = AddPadding(data, INTERRUPT, PAD, BLOCK_SIZE)
encrypted = cipher.encrypt(padded)
return base64.b64encode(encrypted)
def B64AESDecrypt(key, iv, data):
c = md5.new()
c.update(key)
i = md5.new()
i.update(iv)
cipher = AES.new(c.hexdigest(), AES.MODE_CBC, i.hexdigest()[:16])
decoded = base64.b64decode(data)
try:
decrypted = cipher.decrypt(decoded)
except:
decrypted = ""
return StripPadding(decrypted, INTERRUPT, PAD)
###########################################################################
# Copyright (c) 2011-2013 Unixmedia S.r.l. <info@unixmedia.it>
# Copyright (c) 2011-2013 Franco (nextime) Lanza <franco@unixmedia.it>
#
# Domotika System Controller Daemon "domotikad" [http://trac.unixmedia.it]
#
# This file is part of domotikad.
#
# domotikad 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
import logging
import DMDomain as dmd
log = logging.getLogger( 'DMDomain' )
def isMatch(s):
specials=['[',']','!','*','|']
if len(s) > 32:
return False
for i in specials:
if i in s:
return False
return True
#return dmd.ValidateDomainString(s, dmd.DOMAIN_TYPE_MATCH, len(s))==s
# il primo e' passato dalla query
# il secondo arriva dal db
def match(dmstr, dmchk):
if ' ' in dmstr:
dmstr=dmstr.split()
if(len(dmstr)>1) and dmstr[1].lower() in ['rev', 'reversed']:
log.debug("DMDOMAIN REVERSED")
ret=dmd.DMDomainMatch(dmchk, dmstr[0], len(dmchk))
else:
log.debug("DMDOMAIN NOT REVERSED")
ret=dmd.DMDomainMatch(dmstr[0], dmchk, len(dmstr[0]))
else:
ret=dmd.DMDomainMatch(dmstr, dmchk, len(dmstr))
log.debug("DMDOMAIN check for %s, %s: %s" % (dmstr, dmchk, str(ret)))
return ret
#!/usr/bin/env python
###########################################################################
# Copyright (c) 2011-2013 Unixmedia S.r.l. <info@unixmedia.it>
# Copyright (c) 2011-2013 Franco (nextime) Lanza <franco@unixmedia.it>
#
# Domotika System Controller Daemon "domotikad" [http://trac.unixmedia.it]
#
# This file is part of domotikad.
#
# domotikad 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
import time
import sys, random
import struct
from dmcrypt import AES256
import constants as C
import logging
from utils import pwgen
import copy
import socket
log = logging.getLogger( 'IKAProtocol' )
IKAP_ARGDICT={
'ip': None,
'io_type': None,
'io_subtype': None,
'act_ret': None,
'arg_data': None,
'unused': None,
'OPT_TYPE': None,
'OPT_DATA': None,
'raw': None
}
def getDefaultDict():
return copy.deepcopy(IKAP_ARGDICT)
def dictToIkapArg(rd, localip=False):
d=getDefaultDict()
d.update(rd)
try:
data=False
if d['OPT_DATA']:
data=["\x00"]*(20-(9-len(d['OPT_DATA'])))
data[11:len(data)]=list(struct.pack('<'+str(len(d['OPT_DATA']))+'B', *d['OPT_DATA']))
if d['OPT_TYPE']:
if not data: data=["\x00"]*11
data[10]=struct.pack('<B', d['OPT_TYPE'])
if d['arg_data']:
if not data: data=["\x00"]*9
data[7:9]=list(struct.pack('<H', d['arg_data']))
if d['act_ret']:
if not data: data=["\x00"]*7
data[6]=struct.pack('<B', d['arg_ret'])
if d['io_subtype']:
if not data: data=["\x00"]*6
data[5]=struct.pack('<B', d['io_subtype'])
if d['io_type']:
if not data: data=["\x00"]*5
data[4]=struct.pack('<B', d['io_type'])
if localip:
d['ip']=localip
if d['ip']:
if not data: data=["\x00"]*4
data[0:4]=list(socket.inet_aton(d['ip']))
except:
return ''
return "".join(data).ljust(20, "\x00")
def ikapArgtoDict(data):
d=getDefaultDict()
if len(data)>=4:
d['ip']=socket.inet_ntoa(data[0:4])
if len(data)>=5:
d['io_type']=struct.unpack("<B", data[4])[0]
if len(data)>=6:
d['io_subtype']=struct.unpack("<B", data[5])[0]
if len(data)>=7:
d['act_ret']=struct.unpack("<B", data[6])[0]
if len(data)>=9:
d['arg_data']=struct.unpack("<H", data[7:9])[0]
#if len(data)>=10:
# pass
if len(data)>=20:
d['OPT_TYPE']=struct.unpack("<B", data[10])[0]
opt_data=".".join([socket.inet_ntoa(data[11:15]),
socket.inet_ntoa(data[15:19]),
str(struct.unpack("<B", data[19])[0])]).split(".")
d['OPT_DATA']=map(int, opt_data)
d['raw']=data
return d
def calcIPCheckSum(data):
s = 0
for i in range(0, len(data)):
c = s+data[i]
s = (c & 0xffff) + (c >> 16)
return ~s & 0xffff
#DEFKEY=(0xdeadbeef, 0xcafebabe, 0xdefec8ed, 0xbaadf00d)
#DEFKEY="deadbeefcafebabedefec8edbaadf00dca8b49745393d660b7b55dbb29523971"
DEFKEY="\xde\xad\xbe\xef\xca\xfe\xba\xbe\xde\xfe\xc8\xed\xba\xad\xf0\x0d\xca\x8b\x49\x74\x53\x93\xd6\x60\xb7\xb5\x5d\xbb\x29\x52\x39\x71"
DEFIV=pwgen.generateIV128(DEFKEY)
CONST={}
CONST_MSG={}
CONST_ACT={}
CONST_CTX={}
CONST_ENC={}
for co in dir(C):
if type(eval('C.'+co)).__name__=='int':
if co.startswith('IKAP_MSG'):
CONST_MSG[eval('C.'+co)]=co
elif co.startswith('IKAP_ACT'):
CONST_ACT[eval('C.'+co)]=co
elif co.startswith('IKAP_CTX'):
CONST_CTX[eval('C.'+co)]=co
elif co.startswith('IKAP_ENC'):
CONST_ENC[eval('C.'+co)]=co
else:
CONST[eval('C.'+co)]=co
class IkaPacketHeader(struct.Struct):
epoch=0
msgtype=C.IKAP_MSG_ACTION
ctx=C.IKAP_CTX_USER
act=C.IKAP_ACT_DEBUG
srclen=0
dstlen=0
arglen=0
version=0
enctype=0
cfg=0
chksum=0
key=[0,0,0,0]
def __init__(self, hdr=None):
struct.Struct.__init__(self, '<LBHBBBBBBBHLLLL')
self.unpacked=None
def setHdr(self):
self.data=self.tobytes()
self.unpacked=self.unpack(self.data)
self.hdr=list(self.unpacked)
def formatHeader(self, data):
self.unpacked=self.unpack(data)
self.hdr=list(self.unpacked)
self.data=data
self.epoch, self.msgtype, self.ctx, self.act, self.srclen, self.dstlen, \
self.arglen, self.version, self.enctype, self.cfg, self.chksum, self.key[0], self.key[1], \
self.key[2], self.key[3] = self.hdr
def tobytes(self):
return struct.pack('<LBHBBBBBBBHLLLL', self.epoch, self.msgtype, self.ctx, self.act, self.srclen, self.dstlen, \
self.arglen, self.version, self.enctype, self.cfg, self.chksum, self.key[0], self.key[1], \
self.key[2], self.key[3])
def calculateCheckSum(self):
#print "%r" % self.data
cleanchk=struct.pack('<LBHBBBBBBBHLLLL', self.epoch, self.msgtype, self.ctx, self.act, self.srclen, self.dstlen, \
self.arglen, self.version, self.enctype, self.cfg, 0x0000, self.key[0], self.key[1], \
self.key[2], self.key[3])
d=list(struct.unpack('<16H', cleanchk))
#print d
return calcIPCheckSum(d)
def __repr__(self):
return str({'original': str(self.hdr),
'epoch:': self.epoch,
'msgtype': CONST_MSG[self.msgtype],
'ctx': CONST_CTX[self.ctx],
'act': CONST_ACT[self.act],
#'act': self.act,
'srclen':self.srclen,
'dstlen':self.dstlen,
'arglen':self.arglen,
'version':self.version,
'enctype':CONST_ENC[self.enctype],
'cfg': bin(self.cfg),
'chksum': hex(self.chksum),
'key': [hex(self.key[0])[:-1], hex(self.key[1])[:-1], hex(self.key[2])[:-1], hex(self.key[3])[:-1]]
})
#return str(self.hdr)
class IkaPacket(object):
hdr=None
src="Q.USER"
dst="*"
arg=""
epoch=None
enctype=C.IKAP_ENC_AES256
memkey=DEFKEY
def __init__(self, hdr=None):
if not hdr:
self.hdr=IkaPacketHeader()
self.hdr.enctype=C.IKAP_ENC_AES256
self.hdr.epoch=int(time.time())
self.calculateChecksum()
self.setDst(self.dst)
self.setSrc(self.src)
self.setArg(self.arg)
self.setEncType(self.enctype)
self.epoch=self.hdr.epoch
def __repr__(self):
self.hdr.setHdr()
hdr=self.hdr.__repr__()
return 'HEADER: '+hdr+"\nSOURCE: "+self.src+"\nDST: "+self.dst+"\nEPOCH :"+str(self.epoch)
def calculateChecksum(self):
self.hdr.chksum=self.hdr.calculateCheckSum()
def setDst(self, dst):
self.dst=dst
self.hdr.dstlen=len(dst)
self.calculateChecksum()
def setSrc(self, src):
self.src=src
self.hdr.srclen=len(src)
self.calculateChecksum()
def setArg(self, arg):
self.arg=arg
self.hdr.arglen=len(arg)
self.calculateChecksum()
def updateTime(self):
self.hdr.epoch=int(time.time())
self.epoch=self.hdr.epoch
self.calculateChecksum()
def setMsgType(self, msgType):
self.hdr.msgtype=msgType
def setCtx(self, ctx):
self.hdr.ctx=ctx
self.calculateChecksum()
def setAct(self, act):
self.hdr.act=act
self.calculateChecksum()
def setEncType(self, enc):
self.hdr.enctype=enc
self.calculateChecksum()
def setMemkey(self, memkey):
self.memkey=memkey
def generateKey(self):
self.hdr.key = struct.unpack('<4L', pwgen.GenerateHexKey(16))
self.calculateChecksum()
def _aes(self):
# XXX Gestire differenti encryption
aeshdr=AES256(struct.unpack('<8L', DEFKEY), struct.unpack('<4L', DEFIV))
aesdata=AES256(struct.unpack('<8L', DEFKEY), struct.unpack('<4L', DEFIV))
aesdata.iv=self.hdr.key
aeshdr.setCleanData(self.hdr.tobytes())
totdatalen=self.hdr.srclen+self.hdr.dstlen+self.hdr.arglen
totdata=self.src+self.dst+self.arg
totdata=list(ord(c) for c in totdata)
totdata=struct.pack('<%dB' % totdatalen, *totdata)+struct.pack('<L', self.epoch)
totdatalen=len(totdata)
if(len(totdata)%16):
totdatalen=len(totdata)+16-(len(totdata)%16)
totdata=totdata.ljust(totdatalen, "\0") # XXX Magari qui usare dei random bytes!
aesdata.setCleanData(totdata)
return aeshdr, aesdata
def cleanpacket(self):
aeshdr, aesdata = self._aes()
return aeshdr.cleandata+aesdata.cleandata
def encryptPacket(self):
aeshdr, aesdata = self._aes()
return aeshdr.encdata+aesdata.encdata
def prepare(self):
self.generateKey()
self.updateTime()
def toSend(self):
self.prepare()
return struct.pack("<B", C.IKAP_STARTBYTE)+self.encryptPacket()
This diff is collapsed.
"""
__version__ = "$Revision: 1.2 $"
__date__ = "$Date: 2004/04/16 14:55:00 $"
"""
"""
A Python Singleton mixin class that makes use of some of the ideas
found at http://c2.com/cgi/wiki?PythonSingleton. Just inherit
from it and you have a singleton. No code is required in
subclasses to create singleton behavior -- inheritance from
Singleton is all that is needed.
Assume S is a class that inherits from Singleton. Useful behaviors
are:
1) Getting the singleton:
S.getInstance()
returns the instance of S. If none exists, it is created.
2) The usual idiom to construct an instance by calling the class, i.e.
S()
is disabled for the sake of clarity. If it were allowed, a programmer
who didn't happen notice the inheritance from Singleton might think he
was creating a new instance. So it is felt that it is better to
make that clearer by requiring the call of a class method that is defined in
Singleton. An attempt to instantiate via S() will restult in an SingletonException
being raised.
3) If S.__init__(.) requires parameters, include them in the
first call to S.getInstance(.). If subsequent calls have parameters,
a SingletonException is raised.
4) As an implementation detail, classes that inherit
from Singleton may not have their own __new__
methods. To make sure this requirement is followed,
an exception is raised if a Singleton subclass includ
es __new__. This happens at subclass instantiation
time (by means of the MetaSingleton metaclass.
By Gary Robinson, grobinson@transpose.com. No rights reserved --
placed in the public domain -- which is only reasonable considering
how much it owes to other people's version which are in the
public domain. The idea of using a metaclass came from
a comment on Gary's blog (see
http://www.garyrobinson.net/2004/03/python_singleto.html#comments).
Not guaranteed to be fit for any particular purpose.
RDS - 2004-04-16
To make a class a Singleton, inhert from singleton.Singleton.
Call <Class>.getInstance() to get the single instance of <Class>.
Any arguments passed to <Class>.getInstance() will be passed on
to your <Class>.__init__.
"""
class SingletonException(Exception):
pass
class MetaSingleton(type):
def __new__(metaclass, strName, tupBases, dict):
if dict.has_key('__new__'):
raise SingletonException, 'Can not override __new__ in a Singleton'
return super(MetaSingleton,metaclass).__new__(metaclass, strName, tupBases, dict)
def __call__(cls, *lstArgs, **dictArgs):
raise SingletonException, 'Singletons may only be instantiated through getInstance()'
class Singleton(object):
__metaclass__ = MetaSingleton
def getInstance(cls, *lstArgs):
"""
Call this to instantiate an instance or retrieve the existing instance.
If the singleton requires args to be instantiated, include them the first
time you call getInstance.
"""
if cls._isInstantiated():
if len(lstArgs) != 0:
raise SingletonException, 'If no supplied args, singleton must already be instantiated, or __init__ must require no args'
else:
if len(lstArgs) != cls._getConstructionArgCountNotCountingSelf():
raise SingletonException, 'If the singleton requires __init__ args, supply them on first instantiation'
instance = cls.__new__(cls)
instance.__init__(*lstArgs)
cls.cInstance = instance
return cls.cInstance
getInstance = classmethod(getInstance)
def _isInstantiated(cls):
return hasattr(cls, 'cInstance')
_isInstantiated = classmethod(_isInstantiated)
def _getConstructionArgCountNotCountingSelf(cls):
return cls.__init__.im_func.func_code.co_argcount - 1
_getConstructionArgCountNotCountingSelf = classmethod(_getConstructionArgCountNotCountingSelf)
def _forgetClassInstanceReferenceForTesting(cls):
"""
This is designed for convenience in testing -- sometimes you
want to get rid of a singleton during test code to see what
happens when you call getInstance() under a new situation.
To really delete the object, all external references to it
also need to be deleted.
"""
delattr(cls,'cInstance')
_forgetClassInstanceReferenceForTesting = classmethod(_forgetClassInstanceReferenceForTesting)
if __name__ == '__main__':
import unittest
class PublicInterfaceTest(unittest.TestCase):
def testReturnsSameObject(self):
"""
Demonstrates normal use -- just call getInstance and it returns a singleton instance
"""
class A(Singleton):
def __init__(self):
super(A, self).__init__()
a1 = A.getInstance()
a2 = A.getInstance()
self.assertEquals(id(a1), id(a2))
def testInstantiateWithMultiArgConstructor(self):
"""
If the singleton needs args to construct, include them in the first
call to get instances.
"""
class B(Singleton):
def __init__(self, arg1, arg2):
super(B, self).__init__()
self.arg1 = arg1
self.arg2 = arg2
b1 = B.getInstance('arg1 value', 'arg2 value')
b2 = B.getInstance()
self.assertEquals(b1.arg1, 'arg1 value')
self.assertEquals(b1.arg2, 'arg2 value')
self.assertEquals(id(b1), id(b2))
def testTryToInstantiateWithoutNeededArgs(self):
class B(Singleton):
def __init__(self, arg1, arg2):
super(B, self).__init__()
self.arg1 = arg1
self.arg2 = arg2
self.assertRaises(SingletonException, B.getInstance)
def testTryToInstantiateWithoutGetInstance(self):
"""
Demonstrates that singletons can ONLY be instantiated through
getInstance, as long as they call Singleton.__init__ during construction.
If this check is not required, you don't need to call Singleton.__init__().
"""
class A(Singleton):
def __init__(self):
super(A, self).__init__()
self.assertRaises(SingletonException, A)
def testDontAllowNew(self):
def instantiatedAnIllegalClass():
class A(Singleton):
def __init__(self):
super(A, self).__init__()
def __new__(metaclass, strName, tupBases, dict):
return super(MetaSingleton,metaclass).__new__(metaclass, strName, tupBases, dict)
self.assertRaises(SingletonException, instantiatedAnIllegalClass)
def testDontAllowArgsAfterConstruction(self):
class B(Singleton):
def __init__(self, arg1, arg2):
super(B, self).__init__()
self.arg1 = arg1
self.arg2 = arg2
b1 = B.getInstance('arg1 value', 'arg2 value')
self.assertRaises(SingletonException, B, 'arg1 value', 'arg2 value')
unittest.main()
\ No newline at end of file
###########################################################################
# Copyright (c) 2011-2013 Unixmedia S.r.l. <info@unixmedia.it>
# Copyright (c) 2011-2013 Franco (nextime) Lanza <franco@unixmedia.it>
#
# Domotika System Controller Daemon "domotikad" [http://trac.unixmedia.it]
#
# This file is part of domotikad.
#
# domotikad 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
###########################################################################
# Copyright (c) 2011-2013 Unixmedia S.r.l. <info@unixmedia.it>
# Copyright (c) 2011-2013 Franco (nextime) Lanza <franco@unixmedia.it>
#
# Domotika System Controller Daemon "domotikad" [http://trac.unixmedia.it]
#
# This file is part of domotikad.
#
# domotikad 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
from twisted.internet import defer, reactor, threads
import time
class BlockingDefer(object):
result = None
errors = None
done = None
timeout = False
def run(self, d, timeout=10):
start = time.time()
d.addCallbacks(self.callbackDone, self.callbackError)
while not self.done:
if int(time.time()-start) > timeout:
self.timeout = True
self.done = True
reactor.iterate(0.05)
time.sleep(.05)
if self.timeout:
raise "Timeout Error"
else:
if not self.errors:
return self.result
else:
raise self.errors
def callbackError(self, err=True):
self.errors = err
self.done = True
def callbackDone(self, result):
self.result = result
self.done = True
def blockingDeferred(d, timeout=5):
bd=BlockingDefer()
ret=bd.run(d, timeout)
del bd
return ret
###########################################################################
# Copyright (c) 2011-2013 Unixmedia S.r.l. <info@unixmedia.it>
# Copyright (c) 2011-2013 Franco (nextime) Lanza <franco@unixmedia.it>
#
# Domotika System Controller Daemon "domotikad" [http://trac.unixmedia.it]
#
# This file is part of domotikad.
#
# domotikad 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
try:
import hashlib
md5 = hashlib
md5.new = hashlib.md5
sha1 = hashlib.sha1
except:
import md5
import sha1
from ConfigParser import SafeConfigParser
def revlist(l): l.reverse(); return l
class FakeObject(object):
pass
class configFile(SafeConfigParser):
def __init__(self, config):
self.configfile = config
SafeConfigParser.__init__(self)
def readConfig(self):
return self.read(self.configfile)
def writeConfig(self):
fd = open(self.configfile, "w")
self.write(fd)
fd.close()
return True
def getOptions(self, section):
res = {}
for opt in self.items(section):
try:
res[opt[0]] = opt[1]
except:
pass
return res
class CircularList(list):
"""
A list that wraps around instead of throwing an index error.
Works like a regular list:
>>> cl = CircularList([1,2,3])
>>> cl
[1, 2, 3]
>>> cl[0]
1
>>> cl[-1]
3
>>> cl[2]
3
Except wraps around:
>>> cl[3]
1
>>> cl[-4]
3
Slices work
>>> cl[0:2]
[1, 2]
but only in range.
"""
def __getitem__(self, key):
# try normal list behavior
try:
return super(CircularList, self).__getitem__(key)
except IndexError:
pass
# key can be either integer or slice object,
# only implementing int now.
try:
index = int(key)
index = index % self.__len__()
return super(CircularList, self).__getitem__(index)
except ValueError:
raise TypeError
class CircularList2(list):
def __init__(self, sequence):
list.__init__(self, sequence)
self.i = 0
def set_index(self, i):
if i not in range(len(self)):
raise IndexError, 'Can\'t set index out of range'
else:
self.i = i
def next(self, n=1):
if self == []:
return None
if n < 0:
return self.prev(abs(n))
if self.i not in range(len(self)):
self.i = len(self) - 1
if self.i + n >= len(self):
i = self.i
self.set_index(0)
return self.next(n - len(self) + i)
else:
self.set_index(self.i + n)
return self[self.i]
def prev(self, n=1):
if self == []:
return None
if n < 0:
return self.next(abs(n))
if self.i not in range(len(self)):
self.i = len(self) - 1
if self.i - n < 0:
i = self.i
self.set_index(len(self) - 1)
return self.prev(n - i - 1)
else:
self.i -= n
return self[self.i]
class SliceCircular(CircularList2):
def getdata(self, howmany=1):
if(howmany > len(self)):
howmany=len(self)
i=self.i
distance=int((howmany-1)/2)
ret=[]
self.prev(distance+1)
while howmany > 0:
ret.append(self.next())
howmany-=1
self.i=i
return ret
def invertWord(word):
import struct
return struct.pack('<2B', struct.unpack('<2B', str(word[:2]))[1],
struct.unpack('<2B', str(word[:2]))[0])
def isIp(addr):
ip=addr.split(".")
if len(ip)==4:
for n in ip:
if not unicode(n).isnumeric() or int(n) <0 or int(n) > 255:
return False
return True
return False
def is_number(s):
try:
float(s) # for int, long and float
except ValueError:
try:
complex(s) # for complex
except ValueError:
return False
except:
return False
return True
def isTrue(d):
if str(d).lower() in ["1", "true", "yes", "si", "y"]:
return True
return False
def board_syspwd(cfgpwd):
if len(cfgpwd)>4:
return cfgpwd
return 'domotika'
def devs_adminpwd(cfgpwd):
if len(cfgpwd)>4:
return cfgpwd
return 'domotika'
def ip_match(mask, ip):
if mask=='255.255.255.255' or mask=='0.0.0.0':
return True
else:
return mask==ip
def hashPwd(pwd):
if pwd and len(pwd)>3:
s=sha1()
s.update(pwd)
return s.hexdigest()
return False
###########################################################################
# Copyright (c) 2011-2013 Unixmedia S.r.l. <info@unixmedia.it>
# Copyright (c) 2011-2013 Franco (nextime) Lanza <franco@unixmedia.it>
#
# Domotika System Controller Daemon "domotikad" [http://trac.unixmedia.it]
#
# This file is part of domotikad.
#
# domotikad 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
import smtplib
from email import MIMEText, MIMEMultipart
from OpenSSL.SSL import SSLv3_METHOD
from twisted.internet import reactor
from twisted.mail.smtp import ESMTPSenderFactory
from twisted.internet.ssl import ClientContextFactory
from twisted.internet.defer import Deferred
import logging
from cStringIO import StringIO
log = logging.getLogger( 'SkylivedCore' )
# XXX: ATTENZIONE: la libreria email e' molto cambiata in python 2.5, verifica
# e rendi il tutto compatibile!
def sendmail(
authenticationUsername, authenticationSecret,
fromAddress, toAddress,
messageFile,
smtpHost, smtpPort=25, requiredAuth=False
):
"""
@param authenticationUsername: The username with which to authenticate.
@param authenticationSecret: The password with which to authenticate.
@param fromAddress: The SMTP reverse path (ie, MAIL FROM)
@param toAddress: The SMTP forward path (ie, RCPT TO)
@param messageFile: A file-like object containing the headers and body of
the message to send.
@param smtpHost: The MX host to which to connect.
@param smtpPort: The port number to which to connect.
@return: A Deferred which will be called back when the message has been
sent or which will errback if it cannot be sent.
"""
# Create a context factory which only allows SSLv3 and does not verify
# the peer's certificate.
contextFactory = ClientContextFactory()
contextFactory.method = SSLv3_METHOD
resultDeferred = Deferred()
senderFactory = ESMTPSenderFactory(
authenticationUsername,
authenticationSecret,
fromAddress,
toAddress,
messageFile,
resultDeferred,
contextFactory=contextFactory,
requireAuthentication=requiredAuth)
reactor.connectTCP(smtpHost, smtpPort, senderFactory)
return resultDeferred
def cbSentMessage(result):
"""
Called when the message has been sent.
Report success to the user and then stop the reactor.
"""
log.info("Message sent "+str(result))
def ebSentMessage(err):
"""
Called if the message cannot be sent.
Report the failure to the user and then stop the reactor.
"""
log.info("Error sending message "+str(err))
class GenericEmail:
def __init__(self, server="127.0.0.1"):
self.Subject = "This is a default subject"
self.From = "me"
self.To = "you"
self.Reply = "you"
self.Cc = False
self.server = server
self.serverport = 25
self.username = 'skyliverobot@astronomix.org'
self.password = 'antanissimo'
self.msg=MIMEText.MIMEText("Default message")
def SetTo(self, to):
self.To=to
#self.Reply=to
def SetCc(self, cc):
self.Cc=cc
def SetSubject(self, subject):
self.Subject=subject
def SetFrom(self, From):
self.From=From
self.Reply=From
def SetReply(self, reply):
self.Reply=reply
def Send(self):
msg=self.msg
msg['Subject'] = self.Subject
msg['From'] = self.From
self._from = self.From
if "<" in self.From:
self._from = ""
start=False
for c in self.From:
if start and c=='>':
start=False
if start:
self._from += c
if c == '<':
start=True
msg['To'] = self.To
msg['Reply-To'] = self.Reply
if self.Cc:
msg['Cc'] = self.Cc
#s=smtplib.SMTP(self.server)
#s.connect()
#s.sendmail(self.From, [self.To], msg.as_string())
#s.close()
toAddress = self.To
if self.Cc:
try:
toAddress.append(self.Cc)
except:
toAddress = [self.To, self.Cc]
result = sendmail(
self.username,
self.password,
self._from,
toAddress,
StringIO(msg.as_string()),
self.server,
self.serverport)
result.addCallbacks(cbSentMessage, ebSentMessage)
class TextEmail(GenericEmail):
def SetMsg(self, msg):
self.msg=MIMEText.MIMEText(msg)
class HTMLEmail(GenericEmail):
def __init__(self, *args, **kwargs):
GenericEmail.__init__(self, *args, **kwargs)
self.msg=MIMEMultipart.MIMEMultipart('alternative')
self._txtmsg = MIMEText.MIMEText('default txt', 'plain')
self._htmlmsg = MIMEText.MIMEText('<html><body>default html</body></html>', 'html')
def SetTextMsg(self, msg):
self._txtmsg = MIMEText.MIMEText(msg, 'plain')
def SetHtmlMsg(self, msg):
self._htmlmsg = MIMEText.MIMEText(msg, 'html')
def Send(self):
self.msg.attach(self._htmlmsg)
self.msg.attach(self._txtmsg)
return GenericEmail.Send(self)
###########################################################################
# Copyright (c) 2011-2013 Unixmedia S.r.l. <info@unixmedia.it>
# Copyright (c) 2011-2013 Franco (nextime) Lanza <franco@unixmedia.it>
#
# Domotika System Controller Daemon "domotikad" [http://trac.unixmedia.it]
#
# This file is part of domotikad.
#
# domotikad 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
from random import Random
lefthand="789yuiophjklbnmYUIOPHJKLBNM"
righthand="123456qwertyasdfgzxcvQWERTYASDFGZXCV"
allchars=lefthand+righthand
def GeneratePwd(leng=8, alt=False):
rng = Random()
pwd=""
for i in range(leng):
if not alt:
pwd+=rng.choice(allchars)
else:
if i%2:
pwd+=rng.choice(lefthand)
else:
pwd+=rng.choice(righthand)
return pwd
def GenerateHexKey(leng=8):
import struct
rng = Random()
pwd=[]
for i in range(leng):
pwd.append(rng.randint(0, 255))
return struct.pack('<%dB' % leng, *pwd)
def generateIV128(pwdhash):
from genutils import invertWord
import struct
res=""
i=0
while(i<16):
a=struct.unpack('<H',invertWord(pwdhash[i:i+2]))[0]
b=struct.unpack('<H',pwdhash[i+16:i+16+2])[0]
res+=struct.pack('<H', a^b)
i+=2
return res
###########################################################################
# Copyright (c) 2011-2013 Unixmedia S.r.l. <info@unixmedia.it>
# Copyright (c) 2011-2013 Franco (nextime) Lanza <franco@unixmedia.it>
#
# Domotika System Controller Daemon "domotikad" [http://trac.unixmedia.it]
#
# This file is part of domotikad.
#
# domotikad 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
from zope.interface import implements
from twisted.internet import defer
import formal
from formal import iformal
REGEX_IP_ADDRESS=('b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).)'
'{3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)b')
REGEX_EMAIL="^[a-zA-Z0-9]+([\._\-a-zA-Z0-9]+)*@[a-zA-Z0-9]+([._\-a-zA-Z0-9]+[\.][a-zA-Z]{2,5})+$"
REGEX_URI=("(http|https|mail|telnet|ftp|imap|irc|file):\/\/[a-z0-9]+"
"([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}((:[0-9]{1,5})?\/.*)?$")
class GenericValidator(object):
def __init__(self, errmsg=u'Cannot validate'):
self.errmsg = errmsg
def check(self, value):
return False
def validate(self, field, value):
if not self.check(value):
raise formal.FieldValidationError(self.errmsg)
class GenericWordListValidator(GenericValidator):
def __init__(self, wordlist=[], errmsg=u'Word not in list'):
self.wordlist = wordlist
GenericValidator.__init__(self, errmsg)
def check(self, value):
if value in self.wordlist:
return True
else:
return False
class YesNoValidator(GenericWordListValidator):
def __init__(self, errmsg=u'Only yes or not are valid values'):
GenericWordListValidator.__init__(self, ['yes', 'no'], errmsg)
class AcceptPolicy(GenericWordListValidator):
def __init__(self, errmsg=u'You must accept our terms of usage!'):
GenericWordListValidator.__init__(self, ['yes'], errmsg)
This diff is collapsed.
#!/usr/bin/env python
from distutils.core import setup
setup(name='dmlib',
version='0.1',
description='Python Domotika Libs',
author='Franco (nextime) Lanza',
author_email='franco@unixmedia.it',
url='http://www.unixmedia.it/',
packages=['dmlib', 'dmlib/utils'],
)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment