From 1b505f68574cb3ef62757806bd9d0ca0050eeb45 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 7 Sep 2015 16:32:59 +0200 Subject: [PATCH] removed Google contacts import feature --- bot.py | 59 ----------- cgi/auth.py | 73 -------------- cgi/index.html | 11 -- cgi/sipgate.py | 237 -------------------------------------------- cgi/sniff.py | 99 ------------------ conf/apache.cfg | 63 ------------ constants.py.sample | 8 +- googleclient.py | 69 ------------- utils.py | 13 --- 9 files changed, 1 insertion(+), 631 deletions(-) delete mode 100755 cgi/auth.py delete mode 100644 cgi/index.html delete mode 100644 cgi/sipgate.py delete mode 100755 cgi/sniff.py delete mode 100644 conf/apache.cfg delete mode 100644 googleclient.py diff --git a/bot.py b/bot.py index 8712d91..aa9bd35 100644 --- a/bot.py +++ b/bot.py @@ -31,7 +31,6 @@ import os import utils from constants import * -#from googleclient import GoogleClient from Yowsup.Contacts.contacts import WAContactsSyncRequest @@ -40,10 +39,7 @@ class Bot(): self.session = session self.name = name - # self.google = GoogleClient() - self.commands = { -# "import": self._import, "help": self._help, "prune": self._prune, "welcome": self._welcome, @@ -79,41 +75,6 @@ class Bot(): def send(self, message): self.session.backend.handleMessage(self.session.user, self.name, message) -# def __do_import(self, token): -# # Google -# google = self.google.getContacts(token) -# self.send("%d buddies imported from google" % len(google)) -# -# result = { } -# for number, name in google.iteritems(): -# number = re.sub("[^0-9]", "", number) -# number = number if number[0] == "0" else "+" + number -# -# result[number] = { 'nick': name, 'state': 0 } -# -# # WhatsApp -# user = self.session.legacyName -# password = self.session.password -# sync = WAContactsSyncRequest(user, password, result.keys()) -# whatsapp = sync.send()['c'] -# -# for w in whatsapp: -# result[w['p']]['state'] = w['w'] -# result[w['p']]['number'] = w['n'] -# -# self.send("%d buddies are using whatsapp" % len(filter(lambda w: w['w'], whatsapp))) -# -# for r in result.values(): -# if r['nick']: -# self.session.buddies.add( -# number = r['number'], -# nick = r['nick'], -# groups = [u'Google'], -# state = r['state'] -# ) -# -# self.send("%d buddies imported" % len(whatsapp)) - def __get_token(self, filename, timeout = 30): file = open(filename, 'r') file.seek(-1, 2) # look at the end @@ -135,25 +96,6 @@ class Bot(): file.close() # commands -# def _import(self, token = None): -# if not token: -# token_url = self.google.getTokenUrl("http://whatsapp.0l.de/auth.py") -# auth_url = "http://whatsapp.0l.de/auth.py?number=%s&auth_url=%s" % (self.session.legacyName, urllib.quote(token_url)) -# short_url = utils.shorten(auth_url) -# self.send("please visit this url to auth: %s" % short_url) -# -# self.send("waiting for authorization...") -# token = self.__get_token(TOKEN_FILE) -# if token: -# self.send("got token: %s" % token) -# self.__do_import(token) -# self.session.updateRoster() -# else: -# self.send("timeout! please use \"\\import [token]\"") -# else: -# self.__do_import(token) -# self.session.updateRoster() - def _sync(self): user = self.session.legacyName password = self.session.password @@ -170,7 +112,6 @@ class Bot(): self.send("""following bot commands are available: \\help show this message \\prune clear your buddylist -\\import [token] import buddies from Google \\sync sync your imported contacts with WhatsApp \\fortune [database] give me a quote diff --git a/cgi/auth.py b/cgi/auth.py deleted file mode 100755 index 5eeb3c0..0000000 --- a/cgi/auth.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/python - -__author__ = "Steffen Vogel" -__copyright__ = "Copyright 2013, Steffen Vogel" -__license__ = "GPLv3" -__maintainer__ = "Steffen Vogel" -__email__ = "post@steffenvogel.de" -__status__ = "Prototype" - -""" - This file is part of transWhat - - transWhat 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 - any later version. - - transwhat 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 transWhat. If not, see . -""" - -import os -import sys -import cgi -import cgitb -import time - -sys.path.insert(1, os.path.join(sys.path[0], '..')) - -from constants import * - -def cookies(str): - return dict(c.split('=') for c in str.split(";")) - -def save_token(timestamp, number, token, filename="tokens"): - file = open(filename, 'a') - file.write("%s\t%s\t%s\n" % (str(timestamp), number, token)) - file.close() - -def main(): - form = cgi.FieldStorage() - number = form.getfirst("number") - auth_url = form.getfirst("auth_url") - token = form.getfirst("code") - - if auth_url: - print "Status: 301 Moved" - print "Location: %s" % auth_url - print "Content-type: text/html" - print "Set-Cookie: number=%s" % number - print "\n\n"; - - elif token and os.environ.has_key('HTTP_COOKIE'): - print "Status: 301 Moved" - print "Content-type: text/html" - print "Location: http://whatsapp.0l.de" - print - - c = cookies(os.environ['HTTP_COOKIE']) - save_token(time.time(), c['number'], token, TOKEN_FILE) - - else: - print "Content-type: text/html" - print "\n" - print "something strange happened :(" - -if __name__ == "__main__": - main() diff --git a/cgi/index.html b/cgi/index.html deleted file mode 100644 index 99a9632..0000000 --- a/cgi/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - diff --git a/cgi/sipgate.py b/cgi/sipgate.py deleted file mode 100644 index a3ece4b..0000000 --- a/cgi/sipgate.py +++ /dev/null @@ -1,237 +0,0 @@ -#!/usr/bin/env python -# -*- encoding: UTF8 -*- - -# author: Philipp Klaus, philipp.klaus →AT→ gmail.com - -# This file is part of python-sipgate-xmlrpc. -# -# python-sipgate-xmlrpc 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. -# -# python-sipgate-xmlrpc 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 python-sipgate-xmlrpc. If not, see . - - -##################################################################### -###### This the most important file of the project: ####### -###### It contains the classe api, which ####### -###### implements the XML-RPC communication with the ####### -###### Sipgate API. ####### - -#from time import time -from sys import stderr -from xmlrpclib import ServerProxy, Fault, ProtocolError, ResponseError -from exceptions import TypeError -from socket import error as socket_error -import re - -VERSION = "0.9.2" -NAME = "%s - python-sipgate-xmlrpc/sipgate.py" -VENDOR = "https://github.com/pklaus/python-sipgate-xmlrpc" - -### ------- Here comes the most important piece of code: the api class with magic methods ----- - -class api (ServerProxy): - def __init__ (self, username=False, password=False, prog_name=False, verbose=False): - if not (username and password and prog_name): - raise SipgateAPIException('To use the class sipgate.api you must provide, username, password and a program name.') - address = SIPGATE_API_URL % {'username':username, 'password':password} - ### The super() call would be more modern but it doesn't work with the current Python version yet. - #super(api, self).__init__(address, verbose=debug) - ServerProxy.__init__(self, address,verbose=verbose) - ### It is considered good practice to Identify the client talking to the server: - self.ClientIdentify({ "ClientName" : NAME % prog_name, "ClientVersion" : VERSION, "ClientVendor" : VENDOR }) - - def __getattr__(self,name): - return _Method(self.__request, name) - - def __request (self, methodname, params): - if methodname.replace(API_PREFIX,'') not in VALID_METHODS: - stderr.write( UNKNOWN_METHOD_MESSAGE % { - 'method': methodname.replace(API_PREFIX,''), 'api_prefix': API_PREFIX, - 'api_version': SIPGATE_API_DOC_V, 'api_date': SIPGATE_API_DOC_D } ) - if len(params)>0 and not type(params[0]) is dict: - raise TypeError(DICT_AS_PARAM_MESSAGE % methodname.replace(API_PREFIX,'')) - method_function = ServerProxy.__getattr__(self,methodname) - try: - result = method_function(params[0] if len(params)>0 and type(params[0]) is dict else dict()) - # cast the result dictionary to a SipgateResponse (custom dictionary): - result = SipgateResponse(result) - except Fault, e: - raise SipgateAPIFault(e.faultCode, e.faultString) - except ProtocolError, e: - raise SipgateAPIProtocolError(e.url, e.errcode, e.errmsg, e.headers) - except socket_error, (value,message): - raise SipgateAPISocketError(value, message) - return result - -## -class SipgateResponse(dict): - def __init__(self, response_dict): - try: - self.StatusCode, self.StatusString = int(response_dict['StatusCode']), response_dict['StatusString'] - self.success = self.StatusCode == 200 - except: - raise TypeError(RESPONSE_NOT_A_DICTIONARY % response_dict) - dict.__init__(self, response_dict) - -class _Method: - # With the help of this class the api class does not - # need to state explicitly the possible XML-RPC calls. - def __init__(self, send, name): - self.__send = send - self.__name = API_PREFIX+name - def __call__(self, *args): - return self.__send(self.__name, args) - -### ------ now we define the exceptions that could occur ------ - -class SipgateAPIException(Exception): - pass - -class SipgateAPIFault(Fault, SipgateAPIException): - # As this inherits from xmlrpclib.Fault it also has the - # attributes faultCode and faultString. - pass - -class SipgateAPIProtocolError(ProtocolError, SipgateAPIException): - # As this inherits from xmlrpclib.ProtocolError it also has the - # attributes errcode and errmsg. - pass - -class SipgateAPISocketError(socket_error, SipgateAPIException): - # As this inherits from socket.error it also has the - # attributes . - pass - -### ------ This section contains message strings ------- - -UNKNOWN_METHOD_MESSAGE = "The method '%(method)s' for the API prefix '%(api_prefix)s' " + \ - "was called. This method, however, is currently not documented for the Sipgate API " + \ - "v%(api_version)s (%(api_date)s). Let's try but I've warned you.\n" -DICT_AS_PARAM_MESSAGE = 'Please specify a dictionary as function call parameter for api.%s().' -RESPONSE_NOT_A_DICTIONARY = 'The response "%s" does not seem to be a response from the ' + \ - 'Sipgate XML-RPC API.' - -### ------ This section contains constants of the Sipgate XML-RPC API ------- - -# This constant represents the version of the currently implemented Sipgate API -# ans is taken from the API description PDF: -SIPGATE_API_DOC_V = '1.06' -SIPGATE_API_DOC_D = 'August 21, 2007' - -# Sipgate basic and plus accounts must use this API URL: -SIPGATE_API_URL = "https://%(username)s:%(password)s@samurai.sipgate.net/RPC2" -# Sipgate one and team have a different URL: api.sipgate.net. -# see -API_PREFIX = 'samurai.' - -VALID_METHODS = [ - 'AccountStatementGet', - 'BalanceGet', - 'ClientIdentify', - 'HistoryGetByDate', - 'ItemizedEntriesGet', - 'OwnUriListGet', - 'PhonebookEntryGet', - 'PhonebookListGet', - 'RecommendedIntervalGet', - 'ServerdataGet', - 'SessionClose', - 'SessionInitiate', - 'SessionInitiateMulti', - 'SessionStatusGet', - 'TosListGet', - 'TosListGet', - 'UmSummaryGet', - 'UserdataGreetingGet', - 'UserdataSipGet', -] - -SERVER_STATUS_CODES = { - ### From Table A.1 and A.2 of the API docu: general server status codes - 200: 'Method success', - 400: 'Method not supported', - 401: 'Request denied (no reason specified)', - 402: 'Internal error', - 403: 'Invalid arguments', - 404: 'Resources exceeded (this MUST not be used to indicate parameters in error)', - 405: 'Invalid parameter name', - 406: 'Invalid parameter type', - 407: 'Invalid parameter value', - 408: 'Attempt to set a non-writable parameter', - 409: 'Notification request rejected.', - 410: 'Parameter exceeds maximum size.', - 411: 'Missing parameter.', - 412: 'Too many requests.', - 500: 'Date out of range.', - 501: 'Uri does not belong to user.', - 502: 'Unknown type of service.', - 503: 'Selected payment method failed.', - 504: 'Selected currency not supported.', - 505: 'Amount exceeds limit.', - 506: 'Malformed SIP URI.', - 507: 'URI not in list.', - 508: 'Format is not valid E.164.', - 509: 'Unknown status.', - 510: 'Unknown ID.', - 511: 'Invalid timevalue.', - 512: 'Referenced session not found.', - 513: 'Only single default per TOS allowed.', - 514: 'Malformed VCARD format.', - 515: 'Malformed PID format.', - 516: 'Presence information not available.', - 517: 'Invalid label name.', - 518: 'Label not assigned.', - 519: 'Label doesn’t exist.', - 520: 'Parameter includes invalid characters.', - 521: 'Bad password. (Rejected due to security concerns.)', - 522: 'Malformed timezone format.', - 523: 'Delay exceeds limit.', - 524: 'Requested VPN type not available.', - 525: 'Requested TOS not available.', - 526: 'Unified messaging not available.', - 527: 'URI not available for registration.', -} - -TYPE_OF_SERVICE = { - 'fax': 'pages', # fax transmission - 'text': 'characters', # text message (e.g. "SMS") - 'video': 'seconds', # video communication - 'voice': 'seconds', # voice communication -} - - -class helpers (object): - @staticmethod - def FQTN(phone_number, default_country_code): - """ - Assures phone numbers are in the form of a E164 Fully Qualified Telephone Number - without the leading + sign. - The alternative would be the Python port of Google's libphonenumber: - https://github.com/daviddrysdale/python-phonenumbers - """ - phone_number = phone_number.replace(' ','').replace('-','').replace('+','').replace('/','') - - ## number starting with 00 (so it's an international format) - if re.compile("^00[1-9][0-9]*$").match(phone_number): - return phone_number[2:] - - ## number starting with your country code (so it was already a FQTN): - if re.compile("^"+default_country_code+"[1-9][0-9]*$").match(phone_number): - return phone_number - - if re.compile("^0[1-9]*$").match(phone_number): - return default_country_code+phone_number[1:] - - if re.compile("^[1-9]*$").match(phone_number): - return phone_number - - raise TypeError("Couldn't parse this phone number: "+phone_number) diff --git a/cgi/sniff.py b/cgi/sniff.py deleted file mode 100755 index 1fdac92..0000000 --- a/cgi/sniff.py +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/python - -__author__ = "Steffen Vogel" -__copyright__ = "Copyright 2013, Steffen Vogel" -__license__ = "GPLv3" -__maintainer__ = "Steffen Vogel" -__email__ = "post@steffenvogel.de" -__status__ = "Prototype" - -""" - This file is part of transWhat - - transWhat 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 - any later version. - - transwhat 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 transWhat. If not, see . -""" - -import os -import sys -import cgi -import cgitb -import time -import pycurl -import StringIO -import json -import sipgate - -sys.path.insert(1, os.path.join(sys.path[0], '..')) - -from constants import * - -def send_sms(recipient, content): - sg = sipgate.api(SIPGATE_USERNAME, SIPGATE_PASSWORD, 'transwhat') - - default_uri = 'sip:NULL@sipgate.net' - for own_uri in sg.OwnUriListGet()['OwnUriList']: - if own_uri['DefaultUri']: - default_uri = own_uri['SipUri'] - - # SessionInitiate may return the following server status codes in case of errors: 501, 502, 506, 520, 525 - return sg.SessionInitiate({'LocalUri': default_uri, 'RemoteUri': 'sip:%s@sipgate.de' % recipient, 'TOS': 'text', 'Content': content }) - -def main(): - url = os.environ['SCRIPT_URI'] + '?' + os.environ['QUERY_STRING'] - - writer = StringIO.StringIO() - ch = pycurl.Curl() - - ch.setopt(pycurl.URL, url) - ch.setopt(pycurl.USERAGENT, os.environ['HTTP_USER_AGENT']) - - ch.setopt(pycurl.WRITEFUNCTION, writer.write) - ch.setopt(pycurl.SSL_VERIFYPEER, False) - ch.setopt(pycurl.HEADER, True) - - ch.perform() - - response = writer.getvalue() - headers, body = response.split("\r\n\r\n", 1) - headers = headers.split("\n") - preamble = headers.pop(0) - - code = preamble.split(" ", 2)[1] - status = preamble.split(" ", 2)[2] - - print "Status: %s %s" % (code, status) - for header in headers: - print header - - print - print body - - file = open(REQUESTS_FILE, "a") - file.write("\n--- Time: %s\n>>> Request: %s\n<<< Reponse Headers:\n%s\nResponse Body:\n%s\n" % (time.strftime("%a, %d %b %Y %H:%M:%S"), url, "\n".join(headers), body)) - file.close() - - # send password via sms to requester - if code == "200": - parsed = json.loads(body) - form = cgi.FieldStorage() - cc = form.getfirst("cc") - number = form.getfirst("in") - - if parsed.has_key('pw') and parsed.has_key('login'): - send_sms(parsed['login'], parsed['pw']) - - ch.close() - -if __name__ == "__main__": - main() diff --git a/conf/apache.cfg b/conf/apache.cfg deleted file mode 100644 index f5f1124..0000000 --- a/conf/apache.cfg +++ /dev/null @@ -1,63 +0,0 @@ - - ServerAdmin webmaster@0l.de - ServerName whatsapp.0l.de - - DocumentRoot /home/stv0g/files/whatsapp/transwhat/cgi - - Options FollowSymLinks - AllowOverride None - - - Options Indexes FollowSymLinks MultiViews +ExecCGI - AllowOverride All - Order allow,deny - allow from all - AddHandler cgi-script .py - - - ErrorLog /home/stv0g/files/whatsapp/htdocs/error.log - CustomLog /home/stv0g/files/whatsapp/htdocs/access.log combined - - - - - ServerAdmin webmaster@0l.de - ServerName whatsapp.0l.de - ServerAlias v.whatsapp.net - - DocumentRoot /home/stv0g/files/whatsapp/transwhat/cgi - - Options FollowSymLinks - AllowOverride None - - - Options Indexes FollowSymLinks MultiViews +ExecCGI - AllowOverride None - Order allow,deny - allow from all - AddHandler cgi-script .py - - - ErrorLog /home/stv0g/files/whatsapp/htdocs/error.log - CustomLog /home/stv0g/files/whatsapp/htdocs/access.log combined - - LogLevel info - # debug, info, notice, warn, error, crit, alert, emerg. - - # Rewrite - RewriteEngine on - - RewriteCond %{REQUEST_FILENAME} !-f - RewriteCond %{REQUEST_FILENAME} !-d - RewriteRule (.*) /sniff.py/$1 - - # SSL - SSLEngine on - SSLCertificateFile /home/stv0g/files/whatsapp/htdocs/whatsapp.crt - SSLCertificateKeyFile /home/stv0g/files/whatsapp/htdocs/whatsapp.key - - - SSLOptions +StdEnvVars - - - diff --git a/constants.py.sample b/constants.py.sample index 9856612..958c2e9 100644 --- a/constants.py.sample +++ b/constants.py.sample @@ -31,10 +31,4 @@ BASE_PATH = "/opt/transwhat" TOKEN_FILE = BASE_PATH + "/logs/tokens" MOTD_FILE = BASE_PATH + "/conf/motd" -REQUESTS_FILE = BASE_PATH + "/logs/requests" - -GOOGLE_CLIENT_ID = "" -GOOGLE_CLIENT_SECRET = "" - -SIPGATE_USERNAME="" -SIPGATE_PASSWORD="" +REQUESTS_FILE = BASE_PATH + "/logs/requests" \ No newline at end of file diff --git a/googleclient.py b/googleclient.py deleted file mode 100644 index 899bbd0..0000000 --- a/googleclient.py +++ /dev/null @@ -1,69 +0,0 @@ -__author__ = "Steffen Vogel" -__copyright__ = "Copyright 2013, Steffen Vogel" -__license__ = "GPLv3" -__maintainer__ = "Steffen Vogel" -__email__ = "post@steffenvogel.de" -__status__ = "Prototype" - -""" - This file is part of transWhat - - transWhat 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 - any later version. - - transwhat 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 transWhat. If not, see . -""" - -import sys - -import gdata.gauth -import gdata.contacts.client -import gdata.contacts.data -import atom.data - -from constants import * - -gdata.contacts.REL_MOBILE='http://schemas.google.com/g/2005#mobile' - -class GoogleClient(): - - def __init__(self): - self.client = gdata.contacts.client.ContactsClient() - # self.token = gdata.gauth.OAuth2Token( - # client_id = GOOGLE_CLIENT_ID, - # client_secret = GOOGLE_CLIENT_SECRET, - # scope = 'https://www.google.com/m8/feeds/contacts', - # user_agent = 'whatTrans' - # ) - - def getTokenUrl(self, uri = 'urn:ietf:wg:oauth:2.0:oob'): - return self.token.generate_authorize_url(redirect_uri=uri) - - def getContacts(self, request_token): - access_token = self.token.get_access_token(request_token) - - self.token.authorize(self.client) - - numbers = { } - - feed = self.client.GetContacts() - while feed: - for i, entry in enumerate(feed.entry): - for number in entry.phone_number: - numbers[number.text] = entry.title.text - - next = feed.GetNextLink() - if next: - feed = self.client.GetContacts(next.href) - else: - break - - return numbers diff --git a/utils.py b/utils.py index c2e1ba6..69a0c44 100644 --- a/utils.py +++ b/utils.py @@ -22,23 +22,10 @@ __status__ = "Prototype" along with transWhat. If not, see . """ -import urllib -import json import e4u import base64 import hashlib -def shorten(url): - url = urllib.urlopen("http://d.0l.de/add.json?type=URL&rdata=%s" % urllib.quote(url)) - response = url.read() - response = json.loads(response) - - for entry in response: - if entry['type'] == 'success': - host = entry['data'][0]['host'] - return "http://s.%s/%s" % (host['zone']['name'], host['punycode']) - - def ago(secs): periods = ["second", "minute", "hour", "day", "week", "month", "year", "decade"] lengths = [60, 60, 24, 7,4.35, 12, 10]