├── intercom ├── gdata │ ├── sites │ │ └── __init__.py │ ├── apps │ │ ├── groups │ │ │ └── __init__.py │ │ ├── audit │ │ │ └── __init__.py │ │ ├── organization │ │ │ └── __init__.py │ │ ├── emailsettings │ │ │ └── __init__.py │ │ ├── adminsettings │ │ │ └── __init__.py │ │ └── migration │ │ │ └── service.py │ ├── marketplace │ │ ├── __init__.py │ │ └── data.py │ ├── spreadsheets │ │ └── __init__.py │ ├── projecthosting │ │ ├── __init__.py │ │ └── data.py │ ├── calendar_resource │ │ └── __init__.py │ ├── Crypto │ │ ├── Hash │ │ │ ├── MD2.pyd │ │ │ ├── MD4.pyd │ │ │ ├── RIPEMD.pyd │ │ │ ├── SHA256.pyd │ │ │ ├── SHA.py │ │ │ ├── MD5.py │ │ │ ├── __init__.py │ │ │ └── HMAC.py │ │ ├── Cipher │ │ │ ├── AES.pyd │ │ │ ├── ARC2.pyd │ │ │ ├── ARC4.pyd │ │ │ ├── CAST.pyd │ │ │ ├── DES.pyd │ │ │ ├── DES3.pyd │ │ │ ├── IDEA.pyd │ │ │ ├── RC5.pyd │ │ │ ├── XOR.pyd │ │ │ ├── Blowfish.pyd │ │ │ └── __init__.py │ │ ├── Util │ │ │ └── __init__.py │ │ ├── Protocol │ │ │ └── __init__.py │ │ ├── PublicKey │ │ │ ├── __init__.py │ │ │ └── ElGamal.py │ │ ├── test.py │ │ └── __init__.py │ ├── tlslite │ │ ├── utils │ │ │ ├── RC4.py │ │ │ ├── PyCrypto_RC4.py │ │ │ ├── PyCrypto_AES.py │ │ │ ├── OpenSSL_RC4.py │ │ │ ├── PyCrypto_TripleDES.py │ │ │ ├── TripleDES.py │ │ │ ├── __init__.py │ │ │ ├── Cryptlib_RC4.py │ │ │ ├── AES.py │ │ │ ├── ASN1Parser.py │ │ │ ├── Python_RC4.py │ │ │ ├── win32prng.c │ │ │ ├── Cryptlib_AES.py │ │ │ ├── Cryptlib_TripleDES.py │ │ │ ├── OpenSSL_TripleDES.py │ │ │ ├── OpenSSL_AES.py │ │ │ ├── PyCrypto_RSAKey.py │ │ │ ├── Python_AES.py │ │ │ ├── dateFuncs.py │ │ │ ├── codec.py │ │ │ ├── cipherfactory.py │ │ │ ├── hmac.py │ │ │ └── compat.py │ │ ├── integration │ │ │ ├── __init__.py │ │ │ ├── IntegrationHelper.py │ │ │ ├── TLSSocketServerMixIn.py │ │ │ ├── SMTP_TLS.py │ │ │ └── TLSAsyncDispatcherMixIn.py │ │ ├── __init__.py │ │ ├── SharedKeyDB.py │ │ ├── api.py │ │ ├── VerifierDB.py │ │ ├── SessionCache.py │ │ ├── BaseDB.py │ │ ├── X509.py │ │ └── Session.py │ ├── acl │ │ ├── __init__.py │ │ └── data.py │ ├── dublincore │ │ ├── __init__.py │ │ └── data.py │ ├── notebook │ │ ├── __init__.py │ │ └── data.py │ ├── opensearch │ │ ├── __init__.py │ │ └── data.py │ ├── contentforshopping │ │ └── __init__.py │ ├── oauth │ │ ├── CHANGES.txt │ │ └── rsa.py │ ├── alt │ │ ├── __init__.py │ │ └── app_engine.py │ ├── apps_property.py │ ├── geo │ │ └── data.py │ ├── books │ │ └── data.py │ ├── media │ │ └── data.py │ ├── finance │ │ └── data.py │ ├── codesearch │ │ ├── service.py │ │ └── __init__.py │ └── blogger │ │ └── data.py ├── twilio │ ├── contrib │ │ ├── __init__.py │ │ ├── jwt │ │ │ └── __init__.py │ │ └── httplib2 │ │ │ └── iri2uri.py │ ├── __init__.py │ ├── rest │ │ └── __init__.py │ └── util.py ├── static │ ├── images │ │ ├── logo.png │ │ ├── noisy.png │ │ └── padded.png │ └── css │ │ └── intercom.css ├── templates │ └── twiml.html ├── settings.py ├── .gitignore ├── index.yaml ├── app.yaml ├── organization.py ├── atom │ ├── auth.py │ ├── token_store.py │ ├── url.py │ └── mock_http.py ├── README.md └── main.py ├── README.md └── LICENSE /intercom/gdata/sites/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /intercom/gdata/apps/groups/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /intercom/twilio/contrib/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /intercom/gdata/apps/audit/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /intercom/gdata/marketplace/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /intercom/gdata/spreadsheets/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /intercom/gdata/apps/organization/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /intercom/gdata/projecthosting/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /intercom/gdata/calendar_resource/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /intercom/static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilio/howtos/HEAD/intercom/static/images/logo.png -------------------------------------------------------------------------------- /intercom/static/images/noisy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilio/howtos/HEAD/intercom/static/images/noisy.png -------------------------------------------------------------------------------- /intercom/gdata/Crypto/Hash/MD2.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilio/howtos/HEAD/intercom/gdata/Crypto/Hash/MD2.pyd -------------------------------------------------------------------------------- /intercom/gdata/Crypto/Hash/MD4.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilio/howtos/HEAD/intercom/gdata/Crypto/Hash/MD4.pyd -------------------------------------------------------------------------------- /intercom/static/images/padded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilio/howtos/HEAD/intercom/static/images/padded.png -------------------------------------------------------------------------------- /intercom/gdata/Crypto/Cipher/AES.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilio/howtos/HEAD/intercom/gdata/Crypto/Cipher/AES.pyd -------------------------------------------------------------------------------- /intercom/gdata/Crypto/Cipher/ARC2.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilio/howtos/HEAD/intercom/gdata/Crypto/Cipher/ARC2.pyd -------------------------------------------------------------------------------- /intercom/gdata/Crypto/Cipher/ARC4.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilio/howtos/HEAD/intercom/gdata/Crypto/Cipher/ARC4.pyd -------------------------------------------------------------------------------- /intercom/gdata/Crypto/Cipher/CAST.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilio/howtos/HEAD/intercom/gdata/Crypto/Cipher/CAST.pyd -------------------------------------------------------------------------------- /intercom/gdata/Crypto/Cipher/DES.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilio/howtos/HEAD/intercom/gdata/Crypto/Cipher/DES.pyd -------------------------------------------------------------------------------- /intercom/gdata/Crypto/Cipher/DES3.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilio/howtos/HEAD/intercom/gdata/Crypto/Cipher/DES3.pyd -------------------------------------------------------------------------------- /intercom/gdata/Crypto/Cipher/IDEA.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilio/howtos/HEAD/intercom/gdata/Crypto/Cipher/IDEA.pyd -------------------------------------------------------------------------------- /intercom/gdata/Crypto/Cipher/RC5.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilio/howtos/HEAD/intercom/gdata/Crypto/Cipher/RC5.pyd -------------------------------------------------------------------------------- /intercom/gdata/Crypto/Cipher/XOR.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilio/howtos/HEAD/intercom/gdata/Crypto/Cipher/XOR.pyd -------------------------------------------------------------------------------- /intercom/gdata/Crypto/Hash/RIPEMD.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilio/howtos/HEAD/intercom/gdata/Crypto/Hash/RIPEMD.pyd -------------------------------------------------------------------------------- /intercom/gdata/Crypto/Hash/SHA256.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilio/howtos/HEAD/intercom/gdata/Crypto/Hash/SHA256.pyd -------------------------------------------------------------------------------- /intercom/templates/twiml.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{client}} 4 | 5 | 6 | -------------------------------------------------------------------------------- /intercom/gdata/Crypto/Cipher/Blowfish.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilio/howtos/HEAD/intercom/gdata/Crypto/Cipher/Blowfish.pyd -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Example Twilio Applications 2 | 3 | To help get you up and running on with Twilio, we provide sample applications for common use cases. 4 | 5 | ## Twilio Client 6 | 7 | * [Twilio Intercom](https://github.com/twilio/howtos/tree/master/intercom) 8 | 9 | -------------------------------------------------------------------------------- /intercom/gdata/Crypto/Hash/SHA.py: -------------------------------------------------------------------------------- 1 | 2 | # Just use the SHA module from the Python standard library 3 | 4 | __revision__ = "$Id: SHA.py,v 1.4 2002/07/11 14:31:19 akuchling Exp $" 5 | 6 | from sha import * 7 | import sha 8 | if hasattr(sha, 'digestsize'): 9 | digest_size = digestsize 10 | del digestsize 11 | del sha 12 | -------------------------------------------------------------------------------- /intercom/gdata/Crypto/Hash/MD5.py: -------------------------------------------------------------------------------- 1 | 2 | # Just use the MD5 module from the Python standard library 3 | 4 | __revision__ = "$Id: MD5.py,v 1.4 2002/07/11 14:31:19 akuchling Exp $" 5 | 6 | from md5 import * 7 | 8 | import md5 9 | if hasattr(md5, 'digestsize'): 10 | digest_size = digestsize 11 | del digestsize 12 | del md5 13 | 14 | -------------------------------------------------------------------------------- /intercom/settings.py: -------------------------------------------------------------------------------- 1 | AUTH_TOKEN = "" # Your Twilio Auth Token 2 | ACCOUNT_SID = "" # Your Twilio Account Sid 3 | APP_SID = "" # Your TwiML Application Sid 4 | 5 | CONSUMER_KEY = "" # Consumer Token key from Google Apps 6 | CONSUMER_SECRET = '' # Consumer Secret key from Google Apps 7 | REQUESTOR = "" # Your Google Apps username 8 | -------------------------------------------------------------------------------- /intercom/.gitignore: -------------------------------------------------------------------------------- 1 | *.py[co] 2 | 3 | # Packages 4 | *.egg 5 | *.egg-info 6 | dist 7 | build 8 | eggs 9 | parts 10 | bin 11 | var 12 | sdist 13 | develop-eggs 14 | .installed.cfg 15 | 16 | # Installer logs 17 | pip-log.txt 18 | 19 | # Unit test / coverage reports 20 | .coverage 21 | .tox 22 | 23 | #Translations 24 | *.mo 25 | 26 | #Mr Developer 27 | .mr.developer.cfg -------------------------------------------------------------------------------- /intercom/twilio/__init__.py: -------------------------------------------------------------------------------- 1 | __version_info__ = ('3', '2', '3') 2 | __version__ = '.'.join(__version_info__) 3 | 4 | 5 | class TwilioException(Exception): 6 | pass 7 | 8 | 9 | class TwilioRestException(TwilioException): 10 | 11 | def __init__(self, status, uri, msg=""): 12 | self.uri = uri 13 | self.status = status 14 | self.msg = msg 15 | 16 | def __str__(self): 17 | return "HTTP ERROR %s: %s \n %s" % (self.status, self.msg, self.uri) 18 | -------------------------------------------------------------------------------- /intercom/index.yaml: -------------------------------------------------------------------------------- 1 | indexes: 2 | 3 | # AUTOGENERATED 4 | 5 | # This index.yaml is automatically updated whenever the dev_appserver 6 | # detects that a new type of query is run. If you want to manage the 7 | # index.yaml file manually, remove the above marker line (the line 8 | # saying "# AUTOGENERATED"). If you want to manage some indexes 9 | # manually, move them above the marker line. The index.yaml file is 10 | # automatically uploaded to the admin console when you next deploy 11 | # your application using appcfg.py. 12 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/RC4.py: -------------------------------------------------------------------------------- 1 | """Abstract class for RC4.""" 2 | 3 | from compat import * #For False 4 | 5 | class RC4: 6 | def __init__(self, keyBytes, implementation): 7 | if len(keyBytes) < 16 or len(keyBytes) > 256: 8 | raise ValueError() 9 | self.isBlockCipher = False 10 | self.name = "rc4" 11 | self.implementation = implementation 12 | 13 | def encrypt(self, plaintext): 14 | raise NotImplementedError() 15 | 16 | def decrypt(self, ciphertext): 17 | raise NotImplementedError() -------------------------------------------------------------------------------- /intercom/gdata/tlslite/integration/__init__.py: -------------------------------------------------------------------------------- 1 | """Classes for integrating TLS Lite with other packages.""" 2 | 3 | __all__ = ["AsyncStateMachine", 4 | "HTTPTLSConnection", 5 | "POP3_TLS", 6 | "IMAP4_TLS", 7 | "SMTP_TLS", 8 | "XMLRPCTransport", 9 | "TLSSocketServerMixIn", 10 | "TLSAsyncDispatcherMixIn", 11 | "TLSTwistedProtocolWrapper"] 12 | 13 | try: 14 | import twisted 15 | del twisted 16 | except ImportError: 17 | del __all__[__all__.index("TLSTwistedProtocolWrapper")] 18 | -------------------------------------------------------------------------------- /intercom/gdata/Crypto/Util/__init__.py: -------------------------------------------------------------------------------- 1 | """Miscellaneous modules 2 | 3 | Contains useful modules that don't belong into any of the 4 | other Crypto.* subpackages. 5 | 6 | Crypto.Util.number Number-theoretic functions (primality testing, etc.) 7 | Crypto.Util.randpool Random number generation 8 | Crypto.Util.RFC1751 Converts between 128-bit keys and human-readable 9 | strings of words. 10 | 11 | """ 12 | 13 | __all__ = ['randpool', 'RFC1751', 'number'] 14 | 15 | __revision__ = "$Id: __init__.py,v 1.4 2003/02/28 15:26:00 akuchling Exp $" 16 | 17 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/PyCrypto_RC4.py: -------------------------------------------------------------------------------- 1 | """PyCrypto RC4 implementation.""" 2 | 3 | from cryptomath import * 4 | from RC4 import * 5 | 6 | if pycryptoLoaded: 7 | import Crypto.Cipher.ARC4 8 | 9 | def new(key): 10 | return PyCrypto_RC4(key) 11 | 12 | class PyCrypto_RC4(RC4): 13 | 14 | def __init__(self, key): 15 | RC4.__init__(self, key, "pycrypto") 16 | self.context = Crypto.Cipher.ARC4.new(key) 17 | 18 | def encrypt(self, plaintext): 19 | return self.context.encrypt(plaintext) 20 | 21 | def decrypt(self, ciphertext): 22 | return self.context.decrypt(ciphertext) -------------------------------------------------------------------------------- /intercom/gdata/acl/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2009 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | -------------------------------------------------------------------------------- /intercom/gdata/dublincore/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2009 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | -------------------------------------------------------------------------------- /intercom/gdata/notebook/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2009 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | -------------------------------------------------------------------------------- /intercom/gdata/opensearch/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2009 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | -------------------------------------------------------------------------------- /intercom/gdata/apps/emailsettings/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2008 Google 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | -------------------------------------------------------------------------------- /intercom/gdata/apps/adminsettings/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2008 Google 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/PyCrypto_AES.py: -------------------------------------------------------------------------------- 1 | """PyCrypto AES implementation.""" 2 | 3 | from cryptomath import * 4 | from AES import * 5 | 6 | if pycryptoLoaded: 7 | import Crypto.Cipher.AES 8 | 9 | def new(key, mode, IV): 10 | return PyCrypto_AES(key, mode, IV) 11 | 12 | class PyCrypto_AES(AES): 13 | 14 | def __init__(self, key, mode, IV): 15 | AES.__init__(self, key, mode, IV, "pycrypto") 16 | self.context = Crypto.Cipher.AES.new(key, mode, IV) 17 | 18 | def encrypt(self, plaintext): 19 | return self.context.encrypt(plaintext) 20 | 21 | def decrypt(self, ciphertext): 22 | return self.context.decrypt(ciphertext) -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/OpenSSL_RC4.py: -------------------------------------------------------------------------------- 1 | """OpenSSL/M2Crypto RC4 implementation.""" 2 | 3 | from cryptomath import * 4 | from RC4 import RC4 5 | 6 | if m2cryptoLoaded: 7 | 8 | def new(key): 9 | return OpenSSL_RC4(key) 10 | 11 | class OpenSSL_RC4(RC4): 12 | 13 | def __init__(self, key): 14 | RC4.__init__(self, key, "openssl") 15 | self.rc4 = m2.rc4_new() 16 | m2.rc4_set_key(self.rc4, key) 17 | 18 | def __del__(self): 19 | m2.rc4_free(self.rc4) 20 | 21 | def encrypt(self, plaintext): 22 | return m2.rc4_update(self.rc4, plaintext) 23 | 24 | def decrypt(self, ciphertext): 25 | return self.encrypt(ciphertext) 26 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/PyCrypto_TripleDES.py: -------------------------------------------------------------------------------- 1 | """PyCrypto 3DES implementation.""" 2 | 3 | from cryptomath import * 4 | from TripleDES import * 5 | 6 | if pycryptoLoaded: 7 | import Crypto.Cipher.DES3 8 | 9 | def new(key, mode, IV): 10 | return PyCrypto_TripleDES(key, mode, IV) 11 | 12 | class PyCrypto_TripleDES(TripleDES): 13 | 14 | def __init__(self, key, mode, IV): 15 | TripleDES.__init__(self, key, mode, IV, "pycrypto") 16 | self.context = Crypto.Cipher.DES3.new(key, mode, IV) 17 | 18 | def encrypt(self, plaintext): 19 | return self.context.encrypt(plaintext) 20 | 21 | def decrypt(self, ciphertext): 22 | return self.context.decrypt(ciphertext) -------------------------------------------------------------------------------- /intercom/gdata/Crypto/Protocol/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | """Cryptographic protocols 3 | 4 | Implements various cryptographic protocols. (Don't expect to find 5 | network protocols here.) 6 | 7 | Crypto.Protocol.AllOrNothing Transforms a message into a set of message 8 | blocks, such that the blocks can be 9 | recombined to get the message back. 10 | 11 | Crypto.Protocol.Chaffing Takes a set of authenticated message blocks 12 | (the wheat) and adds a number of 13 | randomly generated blocks (the chaff). 14 | """ 15 | 16 | __all__ = ['AllOrNothing', 'Chaffing'] 17 | __revision__ = "$Id: __init__.py,v 1.4 2003/02/28 15:23:21 akuchling Exp $" 18 | -------------------------------------------------------------------------------- /intercom/gdata/Crypto/PublicKey/__init__.py: -------------------------------------------------------------------------------- 1 | """Public-key encryption and signature algorithms. 2 | 3 | Public-key encryption uses two different keys, one for encryption and 4 | one for decryption. The encryption key can be made public, and the 5 | decryption key is kept private. Many public-key algorithms can also 6 | be used to sign messages, and some can *only* be used for signatures. 7 | 8 | Crypto.PublicKey.DSA Digital Signature Algorithm. (Signature only) 9 | Crypto.PublicKey.ElGamal (Signing and encryption) 10 | Crypto.PublicKey.RSA (Signing, encryption, and blinding) 11 | Crypto.PublicKey.qNEW (Signature only) 12 | 13 | """ 14 | 15 | __all__ = ['RSA', 'DSA', 'ElGamal', 'qNEW'] 16 | __revision__ = "$Id: __init__.py,v 1.4 2003/04/03 20:27:13 akuchling Exp $" 17 | 18 | -------------------------------------------------------------------------------- /intercom/app.yaml: -------------------------------------------------------------------------------- 1 | application: twilio-intercom 2 | version: 1 3 | runtime: python 4 | api_version: 1 5 | 6 | builtins: 7 | - remote_api: on 8 | 9 | handlers: 10 | - url: /console/.* 11 | script: $PYTHON_LIB/google/appengine/ext/admin 12 | login: admin 13 | - url: /js 14 | static_dir: static/js 15 | - url: /images 16 | static_dir: static/images 17 | - url: /css 18 | static_dir: static/css 19 | - url: /call 20 | script: main.py 21 | - url: .* 22 | script: main.py 23 | login: required 24 | 25 | admin_console: 26 | pages: 27 | - name: Memcache 28 | url: /console/memcache 29 | 30 | skip_files: | 31 | ^(.*/)?( 32 | (#.*#)| 33 | (.*~)| 34 | (.*\.py[co])| 35 | (.*/RCS/.*)| 36 | (\..*)| 37 | (dev/.*)| 38 | (tests/.*)| 39 | (docs/.*)| 40 | (.*\.markdown)| 41 | (license\.txt)| 42 | (setup.py) 43 | )$ 44 | -------------------------------------------------------------------------------- /intercom/gdata/contentforshopping/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2010-2011 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | """Support for the Content API for Shopping 19 | 20 | See: http://code.google.com/apis/shopping/content/index.html 21 | """ 22 | -------------------------------------------------------------------------------- /intercom/gdata/oauth/CHANGES.txt: -------------------------------------------------------------------------------- 1 | 1. Moved oauth.py to __init__.py 2 | 3 | 2. Refactored __init__.py for compatibility with python 2.2 (Issue 59) 4 | 5 | 3. Refactored rsa.py for compatibility with python 2.2 (Issue 59) 6 | 7 | 4. Refactored OAuthRequest.from_token_and_callback since the callback url was 8 | getting double url-encoding the callback url in place of single. (Issue 43) 9 | 10 | 5. Added build_signature_base_string method to rsa.py since it used the 11 | implementation of this method from oauth.OAuthSignatureMethod_HMAC_SHA1 which 12 | was incorrect since it enforced the presence of a consumer secret and a token 13 | secret. Also, changed its super class from oauth.OAuthSignatureMethod_HMAC_SHA1 14 | to oauth.OAuthSignatureMethod (Issue 64) 15 | 16 | 6. Refactored .to_header method since it returned non-oauth params 17 | as well which was incorrect. (Issue 31) -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/TripleDES.py: -------------------------------------------------------------------------------- 1 | """Abstract class for 3DES.""" 2 | 3 | from compat import * #For True 4 | 5 | class TripleDES: 6 | def __init__(self, key, mode, IV, implementation): 7 | if len(key) != 24: 8 | raise ValueError() 9 | if mode != 2: 10 | raise ValueError() 11 | if len(IV) != 8: 12 | raise ValueError() 13 | self.isBlockCipher = True 14 | self.block_size = 8 15 | self.implementation = implementation 16 | self.name = "3des" 17 | 18 | #CBC-Mode encryption, returns ciphertext 19 | #WARNING: *MAY* modify the input as well 20 | def encrypt(self, plaintext): 21 | assert(len(plaintext) % 8 == 0) 22 | 23 | #CBC-Mode decryption, returns plaintext 24 | #WARNING: *MAY* modify the input as well 25 | def decrypt(self, ciphertext): 26 | assert(len(ciphertext) % 8 == 0) 27 | -------------------------------------------------------------------------------- /intercom/gdata/alt/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2008 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | """This package's modules adapt the gdata library to run in other environments 17 | 18 | The first example is the appengine module which contains functions and 19 | classes which modify a GDataService object to run on Google App Engine. 20 | """ 21 | -------------------------------------------------------------------------------- /intercom/gdata/Crypto/Hash/__init__.py: -------------------------------------------------------------------------------- 1 | """Hashing algorithms 2 | 3 | Hash functions take arbitrary strings as input, and produce an output 4 | of fixed size that is dependent on the input; it should never be 5 | possible to derive the input data given only the hash function's 6 | output. Hash functions can be used simply as a checksum, or, in 7 | association with a public-key algorithm, can be used to implement 8 | digital signatures. 9 | 10 | The hashing modules here all support the interface described in PEP 11 | 247, "API for Cryptographic Hash Functions". 12 | 13 | Submodules: 14 | Crypto.Hash.HMAC RFC 2104: Keyed-Hashing for Message Authentication 15 | Crypto.Hash.MD2 16 | Crypto.Hash.MD4 17 | Crypto.Hash.MD5 18 | Crypto.Hash.RIPEMD 19 | Crypto.Hash.SHA 20 | """ 21 | 22 | __all__ = ['HMAC', 'MD2', 'MD4', 'MD5', 'RIPEMD', 'SHA', 'SHA256'] 23 | __revision__ = "$Id: __init__.py,v 1.6 2003/12/19 14:24:25 akuchling Exp $" 24 | 25 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/__init__.py: -------------------------------------------------------------------------------- 1 | """Toolkit for crypto and other stuff.""" 2 | 3 | __all__ = ["AES", 4 | "ASN1Parser", 5 | "cipherfactory", 6 | "codec", 7 | "Cryptlib_AES", 8 | "Cryptlib_RC4", 9 | "Cryptlib_TripleDES", 10 | "cryptomath: cryptomath module", 11 | "dateFuncs", 12 | "hmac", 13 | "JCE_RSAKey", 14 | "compat", 15 | "keyfactory", 16 | "OpenSSL_AES", 17 | "OpenSSL_RC4", 18 | "OpenSSL_RSAKey", 19 | "OpenSSL_TripleDES", 20 | "PyCrypto_AES", 21 | "PyCrypto_RC4", 22 | "PyCrypto_RSAKey", 23 | "PyCrypto_TripleDES", 24 | "Python_AES", 25 | "Python_RC4", 26 | "Python_RSAKey", 27 | "RC4", 28 | "rijndael", 29 | "RSAKey", 30 | "TripleDES", 31 | "xmltools"] 32 | -------------------------------------------------------------------------------- /intercom/gdata/Crypto/test.py: -------------------------------------------------------------------------------- 1 | # 2 | # Test script for the Python Cryptography Toolkit. 3 | # 4 | 5 | __revision__ = "$Id: test.py,v 1.7 2002/07/11 14:31:19 akuchling Exp $" 6 | 7 | import os, sys 8 | 9 | 10 | # Add the build directory to the front of sys.path 11 | from distutils.util import get_platform 12 | s = "build/lib.%s-%.3s" % (get_platform(), sys.version) 13 | s = os.path.join(os.getcwd(), s) 14 | sys.path.insert(0, s) 15 | s = os.path.join(os.getcwd(), 'test') 16 | sys.path.insert(0, s) 17 | 18 | from Crypto.Util import test 19 | 20 | args = sys.argv[1:] 21 | quiet = "--quiet" in args 22 | if quiet: args.remove('--quiet') 23 | 24 | if not quiet: 25 | print '\nStream Ciphers:' 26 | print '===============' 27 | 28 | if args: test.TestStreamModules(args, verbose= not quiet) 29 | else: test.TestStreamModules(verbose= not quiet) 30 | 31 | if not quiet: 32 | print '\nBlock Ciphers:' 33 | print '==============' 34 | 35 | if args: test.TestBlockModules(args, verbose= not quiet) 36 | else: test.TestBlockModules(verbose= not quiet) 37 | 38 | 39 | -------------------------------------------------------------------------------- /intercom/gdata/Crypto/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | """Python Cryptography Toolkit 3 | 4 | A collection of cryptographic modules implementing various algorithms 5 | and protocols. 6 | 7 | Subpackages: 8 | Crypto.Cipher Secret-key encryption algorithms (AES, DES, ARC4) 9 | Crypto.Hash Hashing algorithms (MD5, SHA, HMAC) 10 | Crypto.Protocol Cryptographic protocols (Chaffing, all-or-nothing 11 | transform). This package does not contain any 12 | network protocols. 13 | Crypto.PublicKey Public-key encryption and signature algorithms 14 | (RSA, DSA) 15 | Crypto.Util Various useful modules and functions (long-to-string 16 | conversion, random number generation, number 17 | theoretic functions) 18 | """ 19 | 20 | __all__ = ['Cipher', 'Hash', 'Protocol', 'PublicKey', 'Util'] 21 | 22 | __version__ = '2.0.1' 23 | __revision__ = "$Id: __init__.py,v 1.12 2005/06/14 01:20:22 akuchling Exp $" 24 | 25 | 26 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/Cryptlib_RC4.py: -------------------------------------------------------------------------------- 1 | """Cryptlib RC4 implementation.""" 2 | 3 | from cryptomath import * 4 | from RC4 import RC4 5 | 6 | if cryptlibpyLoaded: 7 | 8 | def new(key): 9 | return Cryptlib_RC4(key) 10 | 11 | class Cryptlib_RC4(RC4): 12 | 13 | def __init__(self, key): 14 | RC4.__init__(self, key, "cryptlib") 15 | self.context = cryptlib_py.cryptCreateContext(cryptlib_py.CRYPT_UNUSED, cryptlib_py.CRYPT_ALGO_RC4) 16 | cryptlib_py.cryptSetAttribute(self.context, cryptlib_py.CRYPT_CTXINFO_KEYSIZE, len(key)) 17 | cryptlib_py.cryptSetAttributeString(self.context, cryptlib_py.CRYPT_CTXINFO_KEY, key) 18 | 19 | def __del__(self): 20 | cryptlib_py.cryptDestroyContext(self.context) 21 | 22 | def encrypt(self, plaintext): 23 | bytes = stringToBytes(plaintext) 24 | cryptlib_py.cryptEncrypt(self.context, bytes) 25 | return bytesToString(bytes) 26 | 27 | def decrypt(self, ciphertext): 28 | return self.encrypt(ciphertext) -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/AES.py: -------------------------------------------------------------------------------- 1 | """Abstract class for AES.""" 2 | 3 | class AES: 4 | def __init__(self, key, mode, IV, implementation): 5 | if len(key) not in (16, 24, 32): 6 | raise AssertionError() 7 | if mode != 2: 8 | raise AssertionError() 9 | if len(IV) != 16: 10 | raise AssertionError() 11 | self.isBlockCipher = True 12 | self.block_size = 16 13 | self.implementation = implementation 14 | if len(key)==16: 15 | self.name = "aes128" 16 | elif len(key)==24: 17 | self.name = "aes192" 18 | elif len(key)==32: 19 | self.name = "aes256" 20 | else: 21 | raise AssertionError() 22 | 23 | #CBC-Mode encryption, returns ciphertext 24 | #WARNING: *MAY* modify the input as well 25 | def encrypt(self, plaintext): 26 | assert(len(plaintext) % 16 == 0) 27 | 28 | #CBC-Mode decryption, returns plaintext 29 | #WARNING: *MAY* modify the input as well 30 | def decrypt(self, ciphertext): 31 | assert(len(ciphertext) % 16 == 0) -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/ASN1Parser.py: -------------------------------------------------------------------------------- 1 | """Class for parsing ASN.1""" 2 | from compat import * 3 | from codec import * 4 | 5 | #Takes a byte array which has a DER TLV field at its head 6 | class ASN1Parser: 7 | def __init__(self, bytes): 8 | p = Parser(bytes) 9 | p.get(1) #skip Type 10 | 11 | #Get Length 12 | self.length = self._getASN1Length(p) 13 | 14 | #Get Value 15 | self.value = p.getFixBytes(self.length) 16 | 17 | #Assuming this is a sequence... 18 | def getChild(self, which): 19 | p = Parser(self.value) 20 | for x in range(which+1): 21 | markIndex = p.index 22 | p.get(1) #skip Type 23 | length = self._getASN1Length(p) 24 | p.getFixBytes(length) 25 | return ASN1Parser(p.bytes[markIndex : p.index]) 26 | 27 | #Decode the ASN.1 DER length field 28 | def _getASN1Length(self, p): 29 | firstLength = p.get(1) 30 | if firstLength<=127: 31 | return firstLength 32 | else: 33 | lengthLength = firstLength & 0x7F 34 | return p.get(lengthLength) 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 Twilio, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /intercom/organization.py: -------------------------------------------------------------------------------- 1 | import gdata 2 | import settings 3 | from gdata.alt.appengine import run_on_appengine 4 | from gdata.apps.service import AppsService 5 | from google.appengine.api import memcache 6 | 7 | 8 | SIG_METHOD = gdata.auth.OAuthSignatureMethod.HMAC_SHA1 9 | 10 | 11 | def users(): 12 | results = memcache.get("roster") 13 | 14 | if results is not None: 15 | return results 16 | 17 | apps = AppsService(domain=settings.CONSUMER_KEY, source="intercom") 18 | apps.SetOAuthInputParameters( 19 | SIG_METHOD, settings.CONSUMER_KEY, 20 | consumer_secret=settings.CONSUMER_SECRET, 21 | two_legged_oauth=True, requestor_id=settings.REQUESTOR) 22 | feed = apps.GetGeneratorForAllUsers() 23 | 24 | results = [] 25 | 26 | def get_person(person): 27 | return { 28 | "name": "%s %s" % (person.name.given_name, 29 | person.name.family_name), 30 | "id": person.login.user_name, 31 | } 32 | 33 | for entry in feed: 34 | for person in entry.entry: 35 | results.append(get_person(person)) 36 | 37 | memcache.add("roster", results, 14400) 38 | return results 39 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/Python_RC4.py: -------------------------------------------------------------------------------- 1 | """Pure-Python RC4 implementation.""" 2 | 3 | from RC4 import RC4 4 | from cryptomath import * 5 | 6 | def new(key): 7 | return Python_RC4(key) 8 | 9 | class Python_RC4(RC4): 10 | def __init__(self, key): 11 | RC4.__init__(self, key, "python") 12 | keyBytes = stringToBytes(key) 13 | S = [i for i in range(256)] 14 | j = 0 15 | for i in range(256): 16 | j = (j + S[i] + keyBytes[i % len(keyBytes)]) % 256 17 | S[i], S[j] = S[j], S[i] 18 | 19 | self.S = S 20 | self.i = 0 21 | self.j = 0 22 | 23 | def encrypt(self, plaintext): 24 | plaintextBytes = stringToBytes(plaintext) 25 | S = self.S 26 | i = self.i 27 | j = self.j 28 | for x in range(len(plaintextBytes)): 29 | i = (i + 1) % 256 30 | j = (j + S[i]) % 256 31 | S[i], S[j] = S[j], S[i] 32 | t = (S[i] + S[j]) % 256 33 | plaintextBytes[x] ^= S[t] 34 | self.i = i 35 | self.j = j 36 | return bytesToString(plaintextBytes) 37 | 38 | def decrypt(self, ciphertext): 39 | return self.encrypt(ciphertext) 40 | -------------------------------------------------------------------------------- /intercom/gdata/apps_property.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (C) 2010 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | # This module is used for version 2 of the Google Data APIs. 19 | 20 | 21 | """Provides a base class to represent property elements in feeds. 22 | 23 | This module is used for version 2 of the Google Data APIs. The primary class 24 | in this module is AppsProperty. 25 | """ 26 | 27 | 28 | __author__ = 'Vic Fryzel ' 29 | 30 | 31 | import atom.core 32 | import gdata.apps 33 | 34 | 35 | class AppsProperty(atom.core.XmlElement): 36 | """Represents an element in a feed.""" 37 | _qname = gdata.apps.APPS_TEMPLATE % 'property' 38 | name = 'name' 39 | value = 'value' 40 | -------------------------------------------------------------------------------- /intercom/gdata/Crypto/Cipher/__init__.py: -------------------------------------------------------------------------------- 1 | """Secret-key encryption algorithms. 2 | 3 | Secret-key encryption algorithms transform plaintext in some way that 4 | is dependent on a key, producing ciphertext. This transformation can 5 | easily be reversed, if (and, hopefully, only if) one knows the key. 6 | 7 | The encryption modules here all support the interface described in PEP 8 | 272, "API for Block Encryption Algorithms". 9 | 10 | If you don't know which algorithm to choose, use AES because it's 11 | standard and has undergone a fair bit of examination. 12 | 13 | Crypto.Cipher.AES Advanced Encryption Standard 14 | Crypto.Cipher.ARC2 Alleged RC2 15 | Crypto.Cipher.ARC4 Alleged RC4 16 | Crypto.Cipher.Blowfish 17 | Crypto.Cipher.CAST 18 | Crypto.Cipher.DES The Data Encryption Standard. Very commonly used 19 | in the past, but today its 56-bit keys are too small. 20 | Crypto.Cipher.DES3 Triple DES. 21 | Crypto.Cipher.IDEA 22 | Crypto.Cipher.RC5 23 | Crypto.Cipher.XOR The simple XOR cipher. 24 | """ 25 | 26 | __all__ = ['AES', 'ARC2', 'ARC4', 27 | 'Blowfish', 'CAST', 'DES', 'DES3', 'IDEA', 'RC5', 28 | 'XOR' 29 | ] 30 | 31 | __revision__ = "$Id: __init__.py,v 1.7 2003/02/28 15:28:35 akuchling Exp $" 32 | 33 | 34 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | TLS Lite is a free python library that implements SSL v3, TLS v1, and 3 | TLS v1.1. TLS Lite supports non-traditional authentication methods 4 | such as SRP, shared keys, and cryptoIDs, in addition to X.509 5 | certificates. TLS Lite is pure python, however it can access OpenSSL, 6 | cryptlib, pycrypto, and GMPY for faster crypto operations. TLS Lite 7 | integrates with httplib, xmlrpclib, poplib, imaplib, smtplib, 8 | SocketServer, asyncore, and Twisted. 9 | 10 | To use, do:: 11 | 12 | from tlslite.api import * 13 | 14 | Then use the L{tlslite.TLSConnection.TLSConnection} class with a socket, 15 | or use one of the integration classes in L{tlslite.integration}. 16 | 17 | @version: 0.3.8 18 | """ 19 | __version__ = "0.3.8" 20 | 21 | __all__ = ["api", 22 | "BaseDB", 23 | "Checker", 24 | "constants", 25 | "errors", 26 | "FileObject", 27 | "HandshakeSettings", 28 | "mathtls", 29 | "messages", 30 | "Session", 31 | "SessionCache", 32 | "SharedKeyDB", 33 | "TLSConnection", 34 | "TLSRecordLayer", 35 | "VerifierDB", 36 | "X509", 37 | "X509CertChain", 38 | "integration", 39 | "utils"] 40 | -------------------------------------------------------------------------------- /intercom/atom/auth.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (C) 2009 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | # This module is used for version 2 of the Google Data APIs. 19 | 20 | 21 | __author__ = 'j.s@google.com (Jeff Scudder)' 22 | 23 | 24 | import base64 25 | 26 | 27 | class BasicAuth(object): 28 | """Sets the Authorization header as defined in RFC1945""" 29 | 30 | def __init__(self, user_id, password): 31 | self.basic_cookie = base64.encodestring( 32 | '%s:%s' % (user_id, password)).strip() 33 | 34 | def modify_request(self, http_request): 35 | http_request.headers['Authorization'] = 'Basic %s' % self.basic_cookie 36 | 37 | ModifyRequest = modify_request 38 | 39 | 40 | class NoAuth(object): 41 | 42 | def modify_request(self, http_request): 43 | pass 44 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/win32prng.c: -------------------------------------------------------------------------------- 1 | 2 | #include "Python.h" 3 | #define _WIN32_WINNT 0x0400 /* Needed for CryptoAPI on some systems */ 4 | #include 5 | 6 | 7 | static PyObject* getRandomBytes(PyObject *self, PyObject *args) 8 | { 9 | int howMany; 10 | HCRYPTPROV hCryptProv; 11 | unsigned char* bytes = NULL; 12 | PyObject* returnVal = NULL; 13 | 14 | 15 | /* Read Arguments */ 16 | if (!PyArg_ParseTuple(args, "i", &howMany)) 17 | return(NULL); 18 | 19 | /* Get Context */ 20 | if(CryptAcquireContext( 21 | &hCryptProv, 22 | NULL, 23 | NULL, 24 | PROV_RSA_FULL, 25 | CRYPT_VERIFYCONTEXT) == 0) 26 | return Py_BuildValue("s#", NULL, 0); 27 | 28 | 29 | /* Allocate bytes */ 30 | bytes = malloc(howMany); 31 | 32 | 33 | /* Get random data */ 34 | if(CryptGenRandom( 35 | hCryptProv, 36 | howMany, 37 | bytes) == 0) 38 | returnVal = Py_BuildValue("s#", NULL, 0); 39 | else 40 | returnVal = Py_BuildValue("s#", bytes, howMany); 41 | 42 | free(bytes); 43 | CryptReleaseContext(hCryptProv, 0); 44 | 45 | return returnVal; 46 | } 47 | 48 | 49 | 50 | /* List of functions exported by this module */ 51 | 52 | static struct PyMethodDef win32prng_functions[] = { 53 | {"getRandomBytes", (PyCFunction)getRandomBytes, METH_VARARGS}, 54 | {NULL, NULL} /* Sentinel */ 55 | }; 56 | 57 | 58 | /* Initialize this module. */ 59 | 60 | DL_EXPORT(void) initwin32prng(void) 61 | { 62 | Py_InitModule("win32prng", win32prng_functions); 63 | } 64 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/Cryptlib_AES.py: -------------------------------------------------------------------------------- 1 | """Cryptlib AES implementation.""" 2 | 3 | from cryptomath import * 4 | from AES import * 5 | 6 | if cryptlibpyLoaded: 7 | 8 | def new(key, mode, IV): 9 | return Cryptlib_AES(key, mode, IV) 10 | 11 | class Cryptlib_AES(AES): 12 | 13 | def __init__(self, key, mode, IV): 14 | AES.__init__(self, key, mode, IV, "cryptlib") 15 | self.context = cryptlib_py.cryptCreateContext(cryptlib_py.CRYPT_UNUSED, cryptlib_py.CRYPT_ALGO_AES) 16 | cryptlib_py.cryptSetAttribute(self.context, cryptlib_py.CRYPT_CTXINFO_MODE, cryptlib_py.CRYPT_MODE_CBC) 17 | cryptlib_py.cryptSetAttribute(self.context, cryptlib_py.CRYPT_CTXINFO_KEYSIZE, len(key)) 18 | cryptlib_py.cryptSetAttributeString(self.context, cryptlib_py.CRYPT_CTXINFO_KEY, key) 19 | cryptlib_py.cryptSetAttributeString(self.context, cryptlib_py.CRYPT_CTXINFO_IV, IV) 20 | 21 | def __del__(self): 22 | cryptlib_py.cryptDestroyContext(self.context) 23 | 24 | def encrypt(self, plaintext): 25 | AES.encrypt(self, plaintext) 26 | bytes = stringToBytes(plaintext) 27 | cryptlib_py.cryptEncrypt(self.context, bytes) 28 | return bytesToString(bytes) 29 | 30 | def decrypt(self, ciphertext): 31 | AES.decrypt(self, ciphertext) 32 | bytes = stringToBytes(ciphertext) 33 | cryptlib_py.cryptDecrypt(self.context, bytes) 34 | return bytesToString(bytes) 35 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/Cryptlib_TripleDES.py: -------------------------------------------------------------------------------- 1 | """Cryptlib 3DES implementation.""" 2 | 3 | from cryptomath import * 4 | 5 | from TripleDES import * 6 | 7 | if cryptlibpyLoaded: 8 | 9 | def new(key, mode, IV): 10 | return Cryptlib_TripleDES(key, mode, IV) 11 | 12 | class Cryptlib_TripleDES(TripleDES): 13 | 14 | def __init__(self, key, mode, IV): 15 | TripleDES.__init__(self, key, mode, IV, "cryptlib") 16 | self.context = cryptlib_py.cryptCreateContext(cryptlib_py.CRYPT_UNUSED, cryptlib_py.CRYPT_ALGO_3DES) 17 | cryptlib_py.cryptSetAttribute(self.context, cryptlib_py.CRYPT_CTXINFO_MODE, cryptlib_py.CRYPT_MODE_CBC) 18 | cryptlib_py.cryptSetAttribute(self.context, cryptlib_py.CRYPT_CTXINFO_KEYSIZE, len(key)) 19 | cryptlib_py.cryptSetAttributeString(self.context, cryptlib_py.CRYPT_CTXINFO_KEY, key) 20 | cryptlib_py.cryptSetAttributeString(self.context, cryptlib_py.CRYPT_CTXINFO_IV, IV) 21 | 22 | def __del__(self): 23 | cryptlib_py.cryptDestroyContext(self.context) 24 | 25 | def encrypt(self, plaintext): 26 | TripleDES.encrypt(self, plaintext) 27 | bytes = stringToBytes(plaintext) 28 | cryptlib_py.cryptEncrypt(self.context, bytes) 29 | return bytesToString(bytes) 30 | 31 | def decrypt(self, ciphertext): 32 | TripleDES.decrypt(self, ciphertext) 33 | bytes = stringToBytes(ciphertext) 34 | cryptlib_py.cryptDecrypt(self.context, bytes) 35 | return bytesToString(bytes) -------------------------------------------------------------------------------- /intercom/README.md: -------------------------------------------------------------------------------- 1 | # Twilio Intercom 2 | 3 | Does your company use Google Apps for email and documents? If so, you can deploy a web-based intercom system, based on Twilio Client, in just minutes. The most difficult part is getting authentication keys from Google. 4 | 5 | ## Getting Your Users 6 | 7 | For Twilio Intercom to work, it needs two pieces of information to work: the current user and the list of all memebers in your company. The latter is handled by `organization.py`. 8 | 9 | ## Google Apps 10 | 11 | The default implementation of `organization.py` uses the [Google Apps Data API](http://code.google.com/googleapps/domain/gdata_provisioning_api_v2.0_developers_protocol.html) to get the necessary information. To access this API, you'll need to jump through some hoops on Google's end of things to allow Intercom access to your organization's members. 12 | 13 | ### Google Apps and OAuth 14 | 15 | The `gdata` libraries use OAuth to authenticate client API calls. First, you'll need to log into your Google Apps dashboard. 16 | 17 | Navigate to **Advanced Options > Manage OAuth domain key third party** 18 | 19 | Check both boxes on the page: one next to **Enable this consumer key** and the other next to **Allow access to all APIs**. 20 | 21 | Navigate to **Advanced Options > Manage third party OAuth Client access** 22 | 23 | Under Client Name, add `your-domain.com` and under One or More API Scopes, add the two feeds like this: `https://apps-apis.google.com/a/feeds/group/#readonly,https://apps-apis.google.com/a/feeds/user/#readonly` 24 | 25 | Finally, fill in **OAuth consumer secret** and **OAuth consumer key** values in `organization.py` to finish up 26 | -------------------------------------------------------------------------------- /intercom/gdata/notebook/data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2009 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """Contains the data classes of the Google Notebook Data API""" 18 | 19 | 20 | __author__ = 'j.s@google.com (Jeff Scudder)' 21 | 22 | 23 | import atom.core 24 | import atom.data 25 | import gdata.data 26 | import gdata.opensearch.data 27 | 28 | 29 | NB_TEMPLATE = '{http://schemas.google.com/notes/2008/}%s' 30 | 31 | 32 | class ComesAfter(atom.core.XmlElement): 33 | """Preceding element.""" 34 | _qname = NB_TEMPLATE % 'comesAfter' 35 | id = 'id' 36 | 37 | 38 | class NoteEntry(gdata.data.GDEntry): 39 | """Describes a note entry in the feed of a user's notebook.""" 40 | 41 | 42 | class NotebookFeed(gdata.data.GDFeed): 43 | """Describes a notebook feed.""" 44 | entry = [NoteEntry] 45 | 46 | 47 | class NotebookListEntry(gdata.data.GDEntry): 48 | """Describes a note list entry in the feed of a user's list of public notebooks.""" 49 | 50 | 51 | class NotebookListFeed(gdata.data.GDFeed): 52 | """Describes a notebook list feed.""" 53 | entry = [NotebookListEntry] 54 | 55 | 56 | -------------------------------------------------------------------------------- /intercom/gdata/opensearch/data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2009 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | """Contains the data classes of the OpenSearch Extension""" 19 | 20 | 21 | __author__ = 'j.s@google.com (Jeff Scudder)' 22 | 23 | 24 | import atom.core 25 | 26 | 27 | OPENSEARCH_TEMPLATE_V1 = '{http://a9.com/-/spec/opensearchrss/1.0//}%s' 28 | OPENSEARCH_TEMPLATE_V2 = '{http://a9.com/-/spec/opensearch/1.1//}%s' 29 | 30 | 31 | class ItemsPerPage(atom.core.XmlElement): 32 | """Describes the number of items that will be returned per page for paged feeds""" 33 | _qname = (OPENSEARCH_TEMPLATE_V1 % 'itemsPerPage', 34 | OPENSEARCH_TEMPLATE_V2 % 'itemsPerPage') 35 | 36 | 37 | class StartIndex(atom.core.XmlElement): 38 | """Describes the starting index of the contained entries for paged feeds""" 39 | _qname = (OPENSEARCH_TEMPLATE_V1 % 'startIndex', 40 | OPENSEARCH_TEMPLATE_V2 % 'startIndex') 41 | 42 | 43 | class TotalResults(atom.core.XmlElement): 44 | """Describes the total number of results associated with this feed""" 45 | _qname = (OPENSEARCH_TEMPLATE_V1 % 'totalResults', 46 | OPENSEARCH_TEMPLATE_V2 % 'totalResults') 47 | 48 | 49 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/OpenSSL_TripleDES.py: -------------------------------------------------------------------------------- 1 | """OpenSSL/M2Crypto 3DES implementation.""" 2 | 3 | from cryptomath import * 4 | from TripleDES import * 5 | 6 | if m2cryptoLoaded: 7 | 8 | def new(key, mode, IV): 9 | return OpenSSL_TripleDES(key, mode, IV) 10 | 11 | class OpenSSL_TripleDES(TripleDES): 12 | 13 | def __init__(self, key, mode, IV): 14 | TripleDES.__init__(self, key, mode, IV, "openssl") 15 | self.key = key 16 | self.IV = IV 17 | 18 | def _createContext(self, encrypt): 19 | context = m2.cipher_ctx_new() 20 | cipherType = m2.des_ede3_cbc() 21 | m2.cipher_init(context, cipherType, self.key, self.IV, encrypt) 22 | return context 23 | 24 | def encrypt(self, plaintext): 25 | TripleDES.encrypt(self, plaintext) 26 | context = self._createContext(1) 27 | ciphertext = m2.cipher_update(context, plaintext) 28 | m2.cipher_ctx_free(context) 29 | self.IV = ciphertext[-self.block_size:] 30 | return ciphertext 31 | 32 | def decrypt(self, ciphertext): 33 | TripleDES.decrypt(self, ciphertext) 34 | context = self._createContext(0) 35 | #I think M2Crypto has a bug - it fails to decrypt and return the last block passed in. 36 | #To work around this, we append sixteen zeros to the string, below: 37 | plaintext = m2.cipher_update(context, ciphertext+('\0'*16)) 38 | 39 | #If this bug is ever fixed, then plaintext will end up having a garbage 40 | #plaintext block on the end. That's okay - the below code will ignore it. 41 | plaintext = plaintext[:len(ciphertext)] 42 | m2.cipher_ctx_free(context) 43 | self.IV = ciphertext[-self.block_size:] 44 | return plaintext -------------------------------------------------------------------------------- /intercom/gdata/acl/data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2009 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """Contains the data classes of the Google Access Control List (ACL) Extension""" 18 | 19 | 20 | __author__ = 'j.s@google.com (Jeff Scudder)' 21 | 22 | 23 | import atom.core 24 | import atom.data 25 | import gdata.data 26 | import gdata.opensearch.data 27 | 28 | 29 | GACL_TEMPLATE = '{http://schemas.google.com/acl/2007}%s' 30 | 31 | 32 | class AclRole(atom.core.XmlElement): 33 | """Describes the role of an entry in an access control list.""" 34 | _qname = GACL_TEMPLATE % 'role' 35 | value = 'value' 36 | 37 | 38 | class AclScope(atom.core.XmlElement): 39 | """Describes the scope of an entry in an access control list.""" 40 | _qname = GACL_TEMPLATE % 'scope' 41 | type = 'type' 42 | value = 'value' 43 | 44 | 45 | class AclWithKey(atom.core.XmlElement): 46 | """Describes a key that can be used to access a document.""" 47 | _qname = GACL_TEMPLATE % 'withKey' 48 | key = 'key' 49 | role = AclRole 50 | 51 | 52 | class AclEntry(gdata.data.GDEntry): 53 | """Describes an entry in a feed of an access control list (ACL).""" 54 | scope = AclScope 55 | role = AclRole 56 | with_key = AclWithKey 57 | 58 | 59 | class AclFeed(gdata.data.GDFeed): 60 | """Describes a feed of an access control list (ACL).""" 61 | entry = [AclEntry] 62 | 63 | 64 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/OpenSSL_AES.py: -------------------------------------------------------------------------------- 1 | """OpenSSL/M2Crypto AES implementation.""" 2 | 3 | from cryptomath import * 4 | from AES import * 5 | 6 | if m2cryptoLoaded: 7 | 8 | def new(key, mode, IV): 9 | return OpenSSL_AES(key, mode, IV) 10 | 11 | class OpenSSL_AES(AES): 12 | 13 | def __init__(self, key, mode, IV): 14 | AES.__init__(self, key, mode, IV, "openssl") 15 | self.key = key 16 | self.IV = IV 17 | 18 | def _createContext(self, encrypt): 19 | context = m2.cipher_ctx_new() 20 | if len(self.key)==16: 21 | cipherType = m2.aes_128_cbc() 22 | if len(self.key)==24: 23 | cipherType = m2.aes_192_cbc() 24 | if len(self.key)==32: 25 | cipherType = m2.aes_256_cbc() 26 | m2.cipher_init(context, cipherType, self.key, self.IV, encrypt) 27 | return context 28 | 29 | def encrypt(self, plaintext): 30 | AES.encrypt(self, plaintext) 31 | context = self._createContext(1) 32 | ciphertext = m2.cipher_update(context, plaintext) 33 | m2.cipher_ctx_free(context) 34 | self.IV = ciphertext[-self.block_size:] 35 | return ciphertext 36 | 37 | def decrypt(self, ciphertext): 38 | AES.decrypt(self, ciphertext) 39 | context = self._createContext(0) 40 | #I think M2Crypto has a bug - it fails to decrypt and return the last block passed in. 41 | #To work around this, we append sixteen zeros to the string, below: 42 | plaintext = m2.cipher_update(context, ciphertext+('\0'*16)) 43 | 44 | #If this bug is ever fixed, then plaintext will end up having a garbage 45 | #plaintext block on the end. That's okay - the below code will discard it. 46 | plaintext = plaintext[:len(ciphertext)] 47 | m2.cipher_ctx_free(context) 48 | self.IV = ciphertext[-self.block_size:] 49 | return plaintext 50 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/integration/IntegrationHelper.py: -------------------------------------------------------------------------------- 1 | 2 | class IntegrationHelper: 3 | 4 | def __init__(self, 5 | username=None, password=None, sharedKey=None, 6 | certChain=None, privateKey=None, 7 | cryptoID=None, protocol=None, 8 | x509Fingerprint=None, 9 | x509TrustList=None, x509CommonName=None, 10 | settings = None): 11 | 12 | self.username = None 13 | self.password = None 14 | self.sharedKey = None 15 | self.certChain = None 16 | self.privateKey = None 17 | self.checker = None 18 | 19 | #SRP Authentication 20 | if username and password and not \ 21 | (sharedKey or certChain or privateKey): 22 | self.username = username 23 | self.password = password 24 | 25 | #Shared Key Authentication 26 | elif username and sharedKey and not \ 27 | (password or certChain or privateKey): 28 | self.username = username 29 | self.sharedKey = sharedKey 30 | 31 | #Certificate Chain Authentication 32 | elif certChain and privateKey and not \ 33 | (username or password or sharedKey): 34 | self.certChain = certChain 35 | self.privateKey = privateKey 36 | 37 | #No Authentication 38 | elif not password and not username and not \ 39 | sharedKey and not certChain and not privateKey: 40 | pass 41 | 42 | else: 43 | raise ValueError("Bad parameters") 44 | 45 | #Authenticate the server based on its cryptoID or fingerprint 46 | if sharedKey and (cryptoID or protocol or x509Fingerprint): 47 | raise ValueError("Can't use shared keys with other forms of"\ 48 | "authentication") 49 | 50 | self.checker = Checker(cryptoID, protocol, x509Fingerprint, 51 | x509TrustList, x509CommonName) 52 | self.settings = settings -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/PyCrypto_RSAKey.py: -------------------------------------------------------------------------------- 1 | """PyCrypto RSA implementation.""" 2 | 3 | from cryptomath import * 4 | 5 | from RSAKey import * 6 | from Python_RSAKey import Python_RSAKey 7 | 8 | if pycryptoLoaded: 9 | 10 | from Crypto.PublicKey import RSA 11 | 12 | class PyCrypto_RSAKey(RSAKey): 13 | def __init__(self, n=0, e=0, d=0, p=0, q=0, dP=0, dQ=0, qInv=0): 14 | if not d: 15 | self.rsa = RSA.construct( (n, e) ) 16 | else: 17 | self.rsa = RSA.construct( (n, e, d, p, q) ) 18 | 19 | def __getattr__(self, name): 20 | return getattr(self.rsa, name) 21 | 22 | def hasPrivateKey(self): 23 | return self.rsa.has_private() 24 | 25 | def hash(self): 26 | return Python_RSAKey(self.n, self.e).hash() 27 | 28 | def _rawPrivateKeyOp(self, m): 29 | s = numberToString(m) 30 | byteLength = numBytes(self.n) 31 | if len(s)== byteLength: 32 | pass 33 | elif len(s) == byteLength-1: 34 | s = '\0' + s 35 | else: 36 | raise AssertionError() 37 | c = stringToNumber(self.rsa.decrypt((s,))) 38 | return c 39 | 40 | def _rawPublicKeyOp(self, c): 41 | s = numberToString(c) 42 | byteLength = numBytes(self.n) 43 | if len(s)== byteLength: 44 | pass 45 | elif len(s) == byteLength-1: 46 | s = '\0' + s 47 | else: 48 | raise AssertionError() 49 | m = stringToNumber(self.rsa.encrypt(s, None)[0]) 50 | return m 51 | 52 | def writeXMLPublicKey(self, indent=''): 53 | return Python_RSAKey(self.n, self.e).write(indent) 54 | 55 | def generate(bits): 56 | key = PyCrypto_RSAKey() 57 | def f(numBytes): 58 | return bytesToString(getRandomBytes(numBytes)) 59 | key.rsa = RSA.generate(bits, f) 60 | return key 61 | generate = staticmethod(generate) 62 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/SharedKeyDB.py: -------------------------------------------------------------------------------- 1 | """Class for storing shared keys.""" 2 | 3 | from utils.cryptomath import * 4 | from utils.compat import * 5 | from mathtls import * 6 | from Session import Session 7 | from BaseDB import BaseDB 8 | 9 | class SharedKeyDB(BaseDB): 10 | """This class represent an in-memory or on-disk database of shared 11 | keys. 12 | 13 | A SharedKeyDB can be passed to a server handshake function to 14 | authenticate a client based on one of the shared keys. 15 | 16 | This class is thread-safe. 17 | """ 18 | 19 | def __init__(self, filename=None): 20 | """Create a new SharedKeyDB. 21 | 22 | @type filename: str 23 | @param filename: Filename for an on-disk database, or None for 24 | an in-memory database. If the filename already exists, follow 25 | this with a call to open(). To create a new on-disk database, 26 | follow this with a call to create(). 27 | """ 28 | BaseDB.__init__(self, filename, "shared key") 29 | 30 | def _getItem(self, username, valueStr): 31 | session = Session() 32 | session._createSharedKey(username, valueStr) 33 | return session 34 | 35 | def __setitem__(self, username, sharedKey): 36 | """Add a shared key to the database. 37 | 38 | @type username: str 39 | @param username: The username to associate the shared key with. 40 | Must be less than or equal to 16 characters in length, and must 41 | not already be in the database. 42 | 43 | @type sharedKey: str 44 | @param sharedKey: The shared key to add. Must be less than 48 45 | characters in length. 46 | """ 47 | BaseDB.__setitem__(self, username, sharedKey) 48 | 49 | def _setItem(self, username, value): 50 | if len(username)>16: 51 | raise ValueError("username too long") 52 | if len(value)>=48: 53 | raise ValueError("shared key too long") 54 | return value 55 | 56 | def _checkItem(self, value, username, param): 57 | newSession = self._getItem(username, param) 58 | return value.masterSecret == newSession.masterSecret -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/Python_AES.py: -------------------------------------------------------------------------------- 1 | """Pure-Python AES implementation.""" 2 | 3 | from cryptomath import * 4 | 5 | from AES import * 6 | from rijndael import rijndael 7 | 8 | def new(key, mode, IV): 9 | return Python_AES(key, mode, IV) 10 | 11 | class Python_AES(AES): 12 | def __init__(self, key, mode, IV): 13 | AES.__init__(self, key, mode, IV, "python") 14 | self.rijndael = rijndael(key, 16) 15 | self.IV = IV 16 | 17 | def encrypt(self, plaintext): 18 | AES.encrypt(self, plaintext) 19 | 20 | plaintextBytes = stringToBytes(plaintext) 21 | chainBytes = stringToBytes(self.IV) 22 | 23 | #CBC Mode: For each block... 24 | for x in range(len(plaintextBytes)/16): 25 | 26 | #XOR with the chaining block 27 | blockBytes = plaintextBytes[x*16 : (x*16)+16] 28 | for y in range(16): 29 | blockBytes[y] ^= chainBytes[y] 30 | blockString = bytesToString(blockBytes) 31 | 32 | #Encrypt it 33 | encryptedBytes = stringToBytes(self.rijndael.encrypt(blockString)) 34 | 35 | #Overwrite the input with the output 36 | for y in range(16): 37 | plaintextBytes[(x*16)+y] = encryptedBytes[y] 38 | 39 | #Set the next chaining block 40 | chainBytes = encryptedBytes 41 | 42 | self.IV = bytesToString(chainBytes) 43 | return bytesToString(plaintextBytes) 44 | 45 | def decrypt(self, ciphertext): 46 | AES.decrypt(self, ciphertext) 47 | 48 | ciphertextBytes = stringToBytes(ciphertext) 49 | chainBytes = stringToBytes(self.IV) 50 | 51 | #CBC Mode: For each block... 52 | for x in range(len(ciphertextBytes)/16): 53 | 54 | #Decrypt it 55 | blockBytes = ciphertextBytes[x*16 : (x*16)+16] 56 | blockString = bytesToString(blockBytes) 57 | decryptedBytes = stringToBytes(self.rijndael.decrypt(blockString)) 58 | 59 | #XOR with the chaining block and overwrite the input with output 60 | for y in range(16): 61 | decryptedBytes[y] ^= chainBytes[y] 62 | ciphertextBytes[(x*16)+y] = decryptedBytes[y] 63 | 64 | #Set the next chaining block 65 | chainBytes = blockBytes 66 | 67 | self.IV = bytesToString(chainBytes) 68 | return bytesToString(ciphertextBytes) 69 | -------------------------------------------------------------------------------- /intercom/gdata/dublincore/data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2009 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """Contains the data classes of the Dublin Core Metadata Initiative (DCMI) Extension""" 18 | 19 | 20 | __author__ = 'j.s@google.com (Jeff Scudder)' 21 | 22 | 23 | import atom.core 24 | 25 | 26 | DC_TEMPLATE = '{http://purl.org/dc/terms/}%s' 27 | 28 | 29 | class Creator(atom.core.XmlElement): 30 | """Entity primarily responsible for making the resource.""" 31 | _qname = DC_TEMPLATE % 'creator' 32 | 33 | 34 | class Date(atom.core.XmlElement): 35 | """Point or period of time associated with an event in the lifecycle of the resource.""" 36 | _qname = DC_TEMPLATE % 'date' 37 | 38 | 39 | class Description(atom.core.XmlElement): 40 | """Account of the resource.""" 41 | _qname = DC_TEMPLATE % 'description' 42 | 43 | 44 | class Format(atom.core.XmlElement): 45 | """File format, physical medium, or dimensions of the resource.""" 46 | _qname = DC_TEMPLATE % 'format' 47 | 48 | 49 | class Identifier(atom.core.XmlElement): 50 | """An unambiguous reference to the resource within a given context.""" 51 | _qname = DC_TEMPLATE % 'identifier' 52 | 53 | 54 | class Language(atom.core.XmlElement): 55 | """Language of the resource.""" 56 | _qname = DC_TEMPLATE % 'language' 57 | 58 | 59 | class Publisher(atom.core.XmlElement): 60 | """Entity responsible for making the resource available.""" 61 | _qname = DC_TEMPLATE % 'publisher' 62 | 63 | 64 | class Rights(atom.core.XmlElement): 65 | """Information about rights held in and over the resource.""" 66 | _qname = DC_TEMPLATE % 'rights' 67 | 68 | 69 | class Subject(atom.core.XmlElement): 70 | """Topic of the resource.""" 71 | _qname = DC_TEMPLATE % 'subject' 72 | 73 | 74 | class Title(atom.core.XmlElement): 75 | """Name given to the resource.""" 76 | _qname = DC_TEMPLATE % 'title' 77 | 78 | 79 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/integration/TLSSocketServerMixIn.py: -------------------------------------------------------------------------------- 1 | """TLS Lite + SocketServer.""" 2 | 3 | from gdata.tlslite.TLSConnection import TLSConnection 4 | 5 | class TLSSocketServerMixIn: 6 | """ 7 | This class can be mixed in with any L{SocketServer.TCPServer} to 8 | add TLS support. 9 | 10 | To use this class, define a new class that inherits from it and 11 | some L{SocketServer.TCPServer} (with the mix-in first). Then 12 | implement the handshake() method, doing some sort of server 13 | handshake on the connection argument. If the handshake method 14 | returns True, the RequestHandler will be triggered. Below is a 15 | complete example of a threaded HTTPS server:: 16 | 17 | from SocketServer import * 18 | from BaseHTTPServer import * 19 | from SimpleHTTPServer import * 20 | from tlslite.api import * 21 | 22 | s = open("./serverX509Cert.pem").read() 23 | x509 = X509() 24 | x509.parse(s) 25 | certChain = X509CertChain([x509]) 26 | 27 | s = open("./serverX509Key.pem").read() 28 | privateKey = parsePEMKey(s, private=True) 29 | 30 | sessionCache = SessionCache() 31 | 32 | class MyHTTPServer(ThreadingMixIn, TLSSocketServerMixIn, 33 | HTTPServer): 34 | def handshake(self, tlsConnection): 35 | try: 36 | tlsConnection.handshakeServer(certChain=certChain, 37 | privateKey=privateKey, 38 | sessionCache=sessionCache) 39 | tlsConnection.ignoreAbruptClose = True 40 | return True 41 | except TLSError, error: 42 | print "Handshake failure:", str(error) 43 | return False 44 | 45 | httpd = MyHTTPServer(('localhost', 443), SimpleHTTPRequestHandler) 46 | httpd.serve_forever() 47 | """ 48 | 49 | 50 | def finish_request(self, sock, client_address): 51 | tlsConnection = TLSConnection(sock) 52 | if self.handshake(tlsConnection) == True: 53 | self.RequestHandlerClass(tlsConnection, client_address, self) 54 | tlsConnection.close() 55 | 56 | #Implement this method to do some form of handshaking. Return True 57 | #if the handshake finishes properly and the request is authorized. 58 | def handshake(self, tlsConnection): 59 | raise NotImplementedError() 60 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/dateFuncs.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | 4 | #Functions for manipulating datetime objects 5 | #CCYY-MM-DDThh:mm:ssZ 6 | def parseDateClass(s): 7 | year, month, day = s.split("-") 8 | day, tail = day[:2], day[2:] 9 | hour, minute, second = tail[1:].split(":") 10 | second = second[:2] 11 | year, month, day = int(year), int(month), int(day) 12 | hour, minute, second = int(hour), int(minute), int(second) 13 | return createDateClass(year, month, day, hour, minute, second) 14 | 15 | 16 | if os.name != "java": 17 | from datetime import datetime, timedelta 18 | 19 | #Helper functions for working with a date/time class 20 | def createDateClass(year, month, day, hour, minute, second): 21 | return datetime(year, month, day, hour, minute, second) 22 | 23 | def printDateClass(d): 24 | #Split off fractional seconds, append 'Z' 25 | return d.isoformat().split(".")[0]+"Z" 26 | 27 | def getNow(): 28 | return datetime.utcnow() 29 | 30 | def getHoursFromNow(hours): 31 | return datetime.utcnow() + timedelta(hours=hours) 32 | 33 | def getMinutesFromNow(minutes): 34 | return datetime.utcnow() + timedelta(minutes=minutes) 35 | 36 | def isDateClassExpired(d): 37 | return d < datetime.utcnow() 38 | 39 | def isDateClassBefore(d1, d2): 40 | return d1 < d2 41 | 42 | else: 43 | #Jython 2.1 is missing lots of python 2.3 stuff, 44 | #which we have to emulate here: 45 | import java 46 | import jarray 47 | 48 | def createDateClass(year, month, day, hour, minute, second): 49 | c = java.util.Calendar.getInstance() 50 | c.setTimeZone(java.util.TimeZone.getTimeZone("UTC")) 51 | c.set(year, month-1, day, hour, minute, second) 52 | return c 53 | 54 | def printDateClass(d): 55 | return "%04d-%02d-%02dT%02d:%02d:%02dZ" % \ 56 | (d.get(d.YEAR), d.get(d.MONTH)+1, d.get(d.DATE), \ 57 | d.get(d.HOUR_OF_DAY), d.get(d.MINUTE), d.get(d.SECOND)) 58 | 59 | def getNow(): 60 | c = java.util.Calendar.getInstance() 61 | c.setTimeZone(java.util.TimeZone.getTimeZone("UTC")) 62 | c.get(c.HOUR) #force refresh? 63 | return c 64 | 65 | def getHoursFromNow(hours): 66 | d = getNow() 67 | d.add(d.HOUR, hours) 68 | return d 69 | 70 | def isDateClassExpired(d): 71 | n = getNow() 72 | return d.before(n) 73 | 74 | def isDateClassBefore(d1, d2): 75 | return d1.before(d2) 76 | -------------------------------------------------------------------------------- /intercom/twilio/contrib/jwt/__init__.py: -------------------------------------------------------------------------------- 1 | """ JSON Web Token implementation 2 | 3 | Minimum implementation based on this spec: 4 | http://self-issued.info/docs/draft-jones-json-web-token-01.html 5 | """ 6 | import base64 7 | import hashlib 8 | import hmac 9 | 10 | try: 11 | import json 12 | except ImportError: 13 | import simplejson as json 14 | 15 | __all__ = ['encode', 'decode', 'DecodeError'] 16 | 17 | class DecodeError(Exception): pass 18 | 19 | signing_methods = { 20 | 'HS256': lambda msg, key: hmac.new(key, msg, hashlib.sha256).digest(), 21 | 'HS384': lambda msg, key: hmac.new(key, msg, hashlib.sha384).digest(), 22 | 'HS512': lambda msg, key: hmac.new(key, msg, hashlib.sha512).digest(), 23 | } 24 | 25 | def base64url_decode(input): 26 | input += '=' * (4 - (len(input) % 4)) 27 | return base64.urlsafe_b64decode(input) 28 | 29 | def base64url_encode(input): 30 | return base64.urlsafe_b64encode(input).replace('=', '') 31 | 32 | def header(jwt): 33 | header_segment = jwt.split('.', 1)[0] 34 | try: 35 | return json.loads(base64url_decode(header_segment)) 36 | except (ValueError, TypeError): 37 | raise DecodeError("Invalid header encoding") 38 | 39 | def encode(payload, key, algorithm='HS256'): 40 | segments = [] 41 | header = {"typ": "JWT", "alg": algorithm} 42 | segments.append(base64url_encode(json.dumps(header))) 43 | segments.append(base64url_encode(json.dumps(payload))) 44 | signing_input = '.'.join(segments) 45 | try: 46 | ascii_key = unicode(key).encode('utf8') 47 | signature = signing_methods[algorithm](signing_input, ascii_key) 48 | except KeyError: 49 | raise NotImplementedError("Algorithm not supported") 50 | segments.append(base64url_encode(signature)) 51 | return '.'.join(segments) 52 | 53 | def decode(jwt, key='', verify=True): 54 | try: 55 | signing_input, crypto_segment = jwt.rsplit('.', 1) 56 | header_segment, payload_segment = signing_input.split('.', 1) 57 | except ValueError: 58 | raise DecodeError("Not enough segments") 59 | try: 60 | header = json.loads(base64url_decode(header_segment)) 61 | payload = json.loads(base64url_decode(payload_segment)) 62 | signature = base64url_decode(crypto_segment) 63 | except (ValueError, TypeError): 64 | raise DecodeError("Invalid segment encoding") 65 | if verify: 66 | try: 67 | ascii_key = unicode(key).encode('utf8') 68 | if not signature == signing_methods[header['alg']](signing_input, ascii_key): 69 | raise DecodeError("Signature verification failed") 70 | except KeyError: 71 | raise DecodeError("Algorithm not supported") 72 | return payload 73 | -------------------------------------------------------------------------------- /intercom/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright 2007 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | import os 18 | import organization 19 | import settings 20 | from django.utils import simplejson as json 21 | from google.appengine.api import users 22 | from google.appengine.ext import webapp 23 | from google.appengine.ext.webapp import template 24 | from google.appengine.ext.webapp import util 25 | from twilio.util import TwilioCapability 26 | 27 | 28 | class IntercomHandler(webapp.RequestHandler): 29 | 30 | def get(self, user_filter="all"): 31 | 32 | user = users.get_current_user() 33 | client_name = user.email().split("@")[0] 34 | 35 | capability = TwilioCapability(settings.ACCOUNT_SID, 36 | settings.AUTH_TOKEN) 37 | capability.allow_client_outgoing(settings.APP_SID) 38 | capability.allow_client_incoming(client_name) 39 | 40 | tp = { 41 | 'token': capability.generate(), 42 | "user_filter": user_filter, 43 | } 44 | 45 | path = os.path.join(os.path.dirname(__file__), 46 | 'templates', 'intercom.html') 47 | self.response.out.write(template.render(path, tp)) 48 | 49 | 50 | class UsersHandler(webapp.RequestHandler): 51 | 52 | def get(self): 53 | self.response.headers["Content-Type"] = "application/json" 54 | self.response.out.write(json.dumps(organization.users())) 55 | 56 | 57 | class TwimlHandler(webapp.RequestHandler): 58 | 59 | def get(self): 60 | tp = {"client": self.request.get("Person")} 61 | 62 | self.response.headers["Content-Type"] = "application/xml" 63 | path = os.path.join(os.path.dirname(__file__), 64 | 'templates', 'twiml.html') 65 | self.response.out.write(template.render(path, tp)) 66 | 67 | def post(self): 68 | self.get() 69 | 70 | 71 | def main(): 72 | application = webapp.WSGIApplication([ 73 | ('/(available|unavailable)?', IntercomHandler), 74 | ('/users', UsersHandler), 75 | ('/call', TwimlHandler), 76 | ], debug=True) 77 | util.run_wsgi_app(application) 78 | 79 | 80 | if __name__ == '__main__': 81 | main() 82 | -------------------------------------------------------------------------------- /intercom/gdata/geo/data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2009 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """Contains the data classes of the Geography Extension""" 18 | 19 | 20 | __author__ = 'j.s@google.com (Jeff Scudder)' 21 | 22 | 23 | import atom.core 24 | 25 | 26 | GEORSS_TEMPLATE = '{http://www.georss.org/georss/}%s' 27 | GML_TEMPLATE = '{http://www.opengis.net/gml/}%s' 28 | GEO_TEMPLATE = '{http://www.w3.org/2003/01/geo/wgs84_pos#/}%s' 29 | 30 | 31 | class GeoLat(atom.core.XmlElement): 32 | """Describes a W3C latitude.""" 33 | _qname = GEO_TEMPLATE % 'lat' 34 | 35 | 36 | class GeoLong(atom.core.XmlElement): 37 | """Describes a W3C longitude.""" 38 | _qname = GEO_TEMPLATE % 'long' 39 | 40 | 41 | class GeoRssBox(atom.core.XmlElement): 42 | """Describes a geographical region.""" 43 | _qname = GEORSS_TEMPLATE % 'box' 44 | 45 | 46 | class GeoRssPoint(atom.core.XmlElement): 47 | """Describes a geographical location.""" 48 | _qname = GEORSS_TEMPLATE % 'point' 49 | 50 | 51 | class GmlLowerCorner(atom.core.XmlElement): 52 | """Describes a lower corner of a region.""" 53 | _qname = GML_TEMPLATE % 'lowerCorner' 54 | 55 | 56 | class GmlPos(atom.core.XmlElement): 57 | """Describes a latitude and longitude.""" 58 | _qname = GML_TEMPLATE % 'pos' 59 | 60 | 61 | class GmlPoint(atom.core.XmlElement): 62 | """Describes a particular geographical point.""" 63 | _qname = GML_TEMPLATE % 'Point' 64 | pos = GmlPos 65 | 66 | 67 | class GmlUpperCorner(atom.core.XmlElement): 68 | """Describes an upper corner of a region.""" 69 | _qname = GML_TEMPLATE % 'upperCorner' 70 | 71 | 72 | class GmlEnvelope(atom.core.XmlElement): 73 | """Describes a Gml geographical region.""" 74 | _qname = GML_TEMPLATE % 'Envelope' 75 | lower_corner = GmlLowerCorner 76 | upper_corner = GmlUpperCorner 77 | 78 | 79 | class GeoRssWhere(atom.core.XmlElement): 80 | """Describes a geographical location or region.""" 81 | _qname = GEORSS_TEMPLATE % 'where' 82 | Point = GmlPoint 83 | Envelope = GmlEnvelope 84 | 85 | 86 | class W3CPoint(atom.core.XmlElement): 87 | """Describes a W3C geographical location.""" 88 | _qname = GEO_TEMPLATE % 'Point' 89 | long = GeoLong 90 | lat = GeoLat 91 | 92 | 93 | -------------------------------------------------------------------------------- /intercom/gdata/books/data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2009 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """Contains the data classes of the Google Book Search Data API""" 18 | 19 | 20 | __author__ = 'j.s@google.com (Jeff Scudder)' 21 | 22 | 23 | import atom.core 24 | import atom.data 25 | import gdata.data 26 | import gdata.dublincore.data 27 | import gdata.opensearch.data 28 | 29 | 30 | GBS_TEMPLATE = '{http://schemas.google.com/books/2008/}%s' 31 | 32 | 33 | class CollectionEntry(gdata.data.GDEntry): 34 | """Describes an entry in a feed of collections.""" 35 | 36 | 37 | class CollectionFeed(gdata.data.BatchFeed): 38 | """Describes a Book Search collection feed.""" 39 | entry = [CollectionEntry] 40 | 41 | 42 | class Embeddability(atom.core.XmlElement): 43 | """Describes an embeddability.""" 44 | _qname = GBS_TEMPLATE % 'embeddability' 45 | value = 'value' 46 | 47 | 48 | class OpenAccess(atom.core.XmlElement): 49 | """Describes an open access.""" 50 | _qname = GBS_TEMPLATE % 'openAccess' 51 | value = 'value' 52 | 53 | 54 | class Review(atom.core.XmlElement): 55 | """User-provided review.""" 56 | _qname = GBS_TEMPLATE % 'review' 57 | lang = 'lang' 58 | type = 'type' 59 | 60 | 61 | class Viewability(atom.core.XmlElement): 62 | """Describes a viewability.""" 63 | _qname = GBS_TEMPLATE % 'viewability' 64 | value = 'value' 65 | 66 | 67 | class VolumeEntry(gdata.data.GDEntry): 68 | """Describes an entry in a feed of Book Search volumes.""" 69 | comments = gdata.data.Comments 70 | language = [gdata.dublincore.data.Language] 71 | open_access = OpenAccess 72 | format = [gdata.dublincore.data.Format] 73 | dc_title = [gdata.dublincore.data.Title] 74 | viewability = Viewability 75 | embeddability = Embeddability 76 | creator = [gdata.dublincore.data.Creator] 77 | rating = gdata.data.Rating 78 | description = [gdata.dublincore.data.Description] 79 | publisher = [gdata.dublincore.data.Publisher] 80 | date = [gdata.dublincore.data.Date] 81 | subject = [gdata.dublincore.data.Subject] 82 | identifier = [gdata.dublincore.data.Identifier] 83 | review = Review 84 | 85 | 86 | class VolumeFeed(gdata.data.BatchFeed): 87 | """Describes a Book Search volume feed.""" 88 | entry = [VolumeEntry] 89 | 90 | 91 | -------------------------------------------------------------------------------- /intercom/static/css/intercom.css: -------------------------------------------------------------------------------- 1 | h1, h2, h3, h4, h5, h6, ul{ 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | body { 7 | background: #111 url("../images/padded.png"); 8 | } 9 | 10 | #wrapper { 11 | background: transparent; 12 | display: -webkit-box; 13 | -webkit-box-orient: vertical; 14 | -webkit-box-align: center; 15 | position: absolute; 16 | top: 0px; 17 | bottom: 0px; 18 | left: 0px; 19 | right: 0px; 20 | } 21 | 22 | section { 23 | display: -webkit-box; 24 | -webkit-box-orient: vertical; 25 | max-width: 400px; 26 | width: 100%; 27 | background: #FFF; 28 | color: #111; 29 | -webkit-box-flex: 1; 30 | } 31 | 32 | section > header h1{ 33 | text-align: left; 34 | } 35 | 36 | section > ul { 37 | overflow-y: auto; 38 | -webkit-box-flex: 1; 39 | } 40 | 41 | 42 | section > footer h1 { 43 | -webkit-box-flex: 1; 44 | text-align: left; 45 | } 46 | 47 | section > footer { 48 | display: -webkit-box; 49 | -webkit-box-align: center; 50 | padding: 15px; 51 | border-top: 1px solid #aaa; 52 | } 53 | 54 | section > footer > button{ 55 | border: 1px solid #aaa !important; 56 | } 57 | 58 | header { 59 | display: -webkit-box; 60 | -webkit-box-align: center; 61 | border-bottom: 1px solid #aaa; 62 | } 63 | 64 | header, footer { 65 | padding: 15px; 66 | text-align: center; 67 | display: -webkit-box; 68 | -webkit-box-align: center; 69 | background: #efefef; /* Old browsers */ 70 | background: -moz-linear-gradient(top, #efefef 0%, #bcbcbc 100%); /* FF3.6+ */ 71 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#efefef), color-stop(100%,#bcbcbc)); /* Chrome,Safari4+ */ 72 | background: -webkit-linear-gradient(top, #efefef 0%,#bcbcbc 100%); /* Chrome10+,Safari5.1+ */ 73 | background: -o-linear-gradient(top, #efefef 0%,#bcbcbc 100%); /* Opera11.10+ */ 74 | background: -ms-linear-gradient(top, #efefef 0%,#bcbcbc 100%); /* IE10+ */ 75 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#efefef', endColorstr='#bcbcbc',GradientType=0 ); /* IE6-9 */ 76 | background: linear-gradient(top, #efefef 0%,#bcbcbc 100%); /* W3C */ 77 | } 78 | 79 | header h1, header aside { 80 | -webkit-box-flex: 1; 81 | } 82 | 83 | ul li { 84 | padding: 10px 15px; 85 | display: -webkit-box; 86 | -webkit-box-align: center; 87 | border-bottom: 1px solid #ddd; 88 | } 89 | 90 | ul li button, ul li span { 91 | display: block; 92 | } 93 | 94 | ul li button { 95 | width: 50px; 96 | margin-left: 10px; 97 | } 98 | 99 | ul li span { 100 | -webkit-box-flex: 1; 101 | } 102 | 103 | ul li div { 104 | margin-right: 10px; 105 | width: 10px; 106 | height: 10px; 107 | border-radius: 100px; 108 | border-width: 1px; 109 | border-style: solid; 110 | } 111 | 112 | div.unavailable { 113 | background: #ccc; 114 | border-color: #aaa; 115 | } 116 | 117 | div.available { 118 | background: #8ee63b; 119 | border-color: #6ab601; 120 | } 121 | 122 | select option { 123 | text-transform:capitalize; 124 | } 125 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/codec.py: -------------------------------------------------------------------------------- 1 | """Classes for reading/writing binary data (such as TLS records).""" 2 | 3 | from compat import * 4 | 5 | class Writer: 6 | def __init__(self, length=0): 7 | #If length is zero, then this is just a "trial run" to determine length 8 | self.index = 0 9 | self.bytes = createByteArrayZeros(length) 10 | 11 | def add(self, x, length): 12 | if self.bytes: 13 | newIndex = self.index+length-1 14 | while newIndex >= self.index: 15 | self.bytes[newIndex] = x & 0xFF 16 | x >>= 8 17 | newIndex -= 1 18 | self.index += length 19 | 20 | def addFixSeq(self, seq, length): 21 | if self.bytes: 22 | for e in seq: 23 | self.add(e, length) 24 | else: 25 | self.index += len(seq)*length 26 | 27 | def addVarSeq(self, seq, length, lengthLength): 28 | if self.bytes: 29 | self.add(len(seq)*length, lengthLength) 30 | for e in seq: 31 | self.add(e, length) 32 | else: 33 | self.index += lengthLength + (len(seq)*length) 34 | 35 | 36 | class Parser: 37 | def __init__(self, bytes): 38 | self.bytes = bytes 39 | self.index = 0 40 | 41 | def get(self, length): 42 | if self.index + length > len(self.bytes): 43 | raise SyntaxError() 44 | x = 0 45 | for count in range(length): 46 | x <<= 8 47 | x |= self.bytes[self.index] 48 | self.index += 1 49 | return x 50 | 51 | def getFixBytes(self, lengthBytes): 52 | bytes = self.bytes[self.index : self.index+lengthBytes] 53 | self.index += lengthBytes 54 | return bytes 55 | 56 | def getVarBytes(self, lengthLength): 57 | lengthBytes = self.get(lengthLength) 58 | return self.getFixBytes(lengthBytes) 59 | 60 | def getFixList(self, length, lengthList): 61 | l = [0] * lengthList 62 | for x in range(lengthList): 63 | l[x] = self.get(length) 64 | return l 65 | 66 | def getVarList(self, length, lengthLength): 67 | lengthList = self.get(lengthLength) 68 | if lengthList % length != 0: 69 | raise SyntaxError() 70 | lengthList = int(lengthList/length) 71 | l = [0] * lengthList 72 | for x in range(lengthList): 73 | l[x] = self.get(length) 74 | return l 75 | 76 | def startLengthCheck(self, lengthLength): 77 | self.lengthCheck = self.get(lengthLength) 78 | self.indexCheck = self.index 79 | 80 | def setLengthCheck(self, length): 81 | self.lengthCheck = length 82 | self.indexCheck = self.index 83 | 84 | def stopLengthCheck(self): 85 | if (self.index - self.indexCheck) != self.lengthCheck: 86 | raise SyntaxError() 87 | 88 | def atLengthCheck(self): 89 | if (self.index - self.indexCheck) < self.lengthCheck: 90 | return False 91 | elif (self.index - self.indexCheck) == self.lengthCheck: 92 | return True 93 | else: 94 | raise SyntaxError() -------------------------------------------------------------------------------- /intercom/gdata/marketplace/data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright 2009 Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """Data model for parsing and generating XML for the Google Apps Marketplace Licensing API.""" 18 | 19 | 20 | __author__ = 'Alexandre Vivien ' 21 | 22 | 23 | import atom.core 24 | import gdata 25 | import gdata.data 26 | 27 | 28 | LICENSES_NAMESPACE = 'http://www.w3.org/2005/Atom' 29 | LICENSES_TEMPLATE = '{%s}%%s' % LICENSES_NAMESPACE 30 | 31 | 32 | class Enabled(atom.core.XmlElement): 33 | """ """ 34 | 35 | _qname = LICENSES_TEMPLATE % 'enabled' 36 | 37 | 38 | class Id(atom.core.XmlElement): 39 | """ """ 40 | 41 | _qname = LICENSES_TEMPLATE % 'id' 42 | 43 | 44 | class CustomerId(atom.core.XmlElement): 45 | """ """ 46 | 47 | _qname = LICENSES_TEMPLATE % 'customerid' 48 | 49 | 50 | class DomainName(atom.core.XmlElement): 51 | """ """ 52 | 53 | _qname = LICENSES_TEMPLATE % 'domainname' 54 | 55 | 56 | class InstallerEmail(atom.core.XmlElement): 57 | """ """ 58 | 59 | _qname = LICENSES_TEMPLATE % 'installeremail' 60 | 61 | 62 | class TosAcceptanceTime(atom.core.XmlElement): 63 | """ """ 64 | 65 | _qname = LICENSES_TEMPLATE % 'tosacceptancetime' 66 | 67 | 68 | class LastChangeTime(atom.core.XmlElement): 69 | """ """ 70 | 71 | _qname = LICENSES_TEMPLATE % 'lastchangetime' 72 | 73 | 74 | class ProductConfigId(atom.core.XmlElement): 75 | """ """ 76 | 77 | _qname = LICENSES_TEMPLATE % 'productconfigid' 78 | 79 | 80 | class State(atom.core.XmlElement): 81 | """ """ 82 | 83 | _qname = LICENSES_TEMPLATE % 'state' 84 | 85 | 86 | class Entity(atom.core.XmlElement): 87 | """ The entity representing the License. """ 88 | 89 | _qname = LICENSES_TEMPLATE % 'entity' 90 | 91 | enabled = Enabled 92 | id = Id 93 | customer_id = CustomerId 94 | domain_name = DomainName 95 | installer_email = InstallerEmail 96 | tos_acceptance_time = TosAcceptanceTime 97 | last_change_time = LastChangeTime 98 | product_config_id = ProductConfigId 99 | state = State 100 | 101 | 102 | class Content(atom.data.Content): 103 | entity = Entity 104 | 105 | class LicenseEntry(gdata.data.GDEntry): 106 | """ Represents a LicenseEntry object. """ 107 | 108 | content = Content 109 | 110 | 111 | class LicenseFeed(gdata.data.GDFeed): 112 | """ Represents a feed of LicenseEntry objects. """ 113 | 114 | # Override entry so that this feed knows how to type its list of entries. 115 | entry = [LicenseEntry] 116 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/api.py: -------------------------------------------------------------------------------- 1 | """Import this module for easy access to TLS Lite objects. 2 | 3 | The TLS Lite API consists of classes, functions, and variables spread 4 | throughout this package. Instead of importing them individually with:: 5 | 6 | from tlslite.TLSConnection import TLSConnection 7 | from tlslite.HandshakeSettings import HandshakeSettings 8 | from tlslite.errors import * 9 | . 10 | . 11 | 12 | It's easier to do:: 13 | 14 | from tlslite.api import * 15 | 16 | This imports all the important objects (TLSConnection, Checker, 17 | HandshakeSettings, etc.) into the global namespace. In particular, it 18 | imports:: 19 | 20 | from constants import AlertLevel, AlertDescription, Fault 21 | from errors import * 22 | from Checker import Checker 23 | from HandshakeSettings import HandshakeSettings 24 | from Session import Session 25 | from SessionCache import SessionCache 26 | from SharedKeyDB import SharedKeyDB 27 | from TLSConnection import TLSConnection 28 | from VerifierDB import VerifierDB 29 | from X509 import X509 30 | from X509CertChain import X509CertChain 31 | 32 | from integration.HTTPTLSConnection import HTTPTLSConnection 33 | from integration.POP3_TLS import POP3_TLS 34 | from integration.IMAP4_TLS import IMAP4_TLS 35 | from integration.SMTP_TLS import SMTP_TLS 36 | from integration.XMLRPCTransport import XMLRPCTransport 37 | from integration.TLSSocketServerMixIn import TLSSocketServerMixIn 38 | from integration.TLSAsyncDispatcherMixIn import TLSAsyncDispatcherMixIn 39 | from integration.TLSTwistedProtocolWrapper import TLSTwistedProtocolWrapper 40 | from utils.cryptomath import cryptlibpyLoaded, m2cryptoLoaded, 41 | gmpyLoaded, pycryptoLoaded, prngName 42 | from utils.keyfactory import generateRSAKey, parsePEMKey, parseXMLKey, 43 | parseAsPublicKey, parsePrivateKey 44 | """ 45 | 46 | from constants import AlertLevel, AlertDescription, Fault 47 | from errors import * 48 | from Checker import Checker 49 | from HandshakeSettings import HandshakeSettings 50 | from Session import Session 51 | from SessionCache import SessionCache 52 | from SharedKeyDB import SharedKeyDB 53 | from TLSConnection import TLSConnection 54 | from VerifierDB import VerifierDB 55 | from X509 import X509 56 | from X509CertChain import X509CertChain 57 | 58 | from integration.HTTPTLSConnection import HTTPTLSConnection 59 | from integration.TLSSocketServerMixIn import TLSSocketServerMixIn 60 | from integration.TLSAsyncDispatcherMixIn import TLSAsyncDispatcherMixIn 61 | from integration.POP3_TLS import POP3_TLS 62 | from integration.IMAP4_TLS import IMAP4_TLS 63 | from integration.SMTP_TLS import SMTP_TLS 64 | from integration.XMLRPCTransport import XMLRPCTransport 65 | try: 66 | import twisted 67 | del(twisted) 68 | from integration.TLSTwistedProtocolWrapper import TLSTwistedProtocolWrapper 69 | except ImportError: 70 | pass 71 | 72 | from utils.cryptomath import cryptlibpyLoaded, m2cryptoLoaded, gmpyLoaded, \ 73 | pycryptoLoaded, prngName 74 | from utils.keyfactory import generateRSAKey, parsePEMKey, parseXMLKey, \ 75 | parseAsPublicKey, parsePrivateKey 76 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/VerifierDB.py: -------------------------------------------------------------------------------- 1 | """Class for storing SRP password verifiers.""" 2 | 3 | from utils.cryptomath import * 4 | from utils.compat import * 5 | import mathtls 6 | from BaseDB import BaseDB 7 | 8 | class VerifierDB(BaseDB): 9 | """This class represent an in-memory or on-disk database of SRP 10 | password verifiers. 11 | 12 | A VerifierDB can be passed to a server handshake to authenticate 13 | a client based on one of the verifiers. 14 | 15 | This class is thread-safe. 16 | """ 17 | def __init__(self, filename=None): 18 | """Create a new VerifierDB instance. 19 | 20 | @type filename: str 21 | @param filename: Filename for an on-disk database, or None for 22 | an in-memory database. If the filename already exists, follow 23 | this with a call to open(). To create a new on-disk database, 24 | follow this with a call to create(). 25 | """ 26 | BaseDB.__init__(self, filename, "verifier") 27 | 28 | def _getItem(self, username, valueStr): 29 | (N, g, salt, verifier) = valueStr.split(" ") 30 | N = base64ToNumber(N) 31 | g = base64ToNumber(g) 32 | salt = base64ToString(salt) 33 | verifier = base64ToNumber(verifier) 34 | return (N, g, salt, verifier) 35 | 36 | def __setitem__(self, username, verifierEntry): 37 | """Add a verifier entry to the database. 38 | 39 | @type username: str 40 | @param username: The username to associate the verifier with. 41 | Must be less than 256 characters in length. Must not already 42 | be in the database. 43 | 44 | @type verifierEntry: tuple 45 | @param verifierEntry: The verifier entry to add. Use 46 | L{tlslite.VerifierDB.VerifierDB.makeVerifier} to create a 47 | verifier entry. 48 | """ 49 | BaseDB.__setitem__(self, username, verifierEntry) 50 | 51 | 52 | def _setItem(self, username, value): 53 | if len(username)>=256: 54 | raise ValueError("username too long") 55 | N, g, salt, verifier = value 56 | N = numberToBase64(N) 57 | g = numberToBase64(g) 58 | salt = stringToBase64(salt) 59 | verifier = numberToBase64(verifier) 60 | valueStr = " ".join( (N, g, salt, verifier) ) 61 | return valueStr 62 | 63 | def _checkItem(self, value, username, param): 64 | (N, g, salt, verifier) = value 65 | x = mathtls.makeX(salt, username, param) 66 | v = powMod(g, x, N) 67 | return (verifier == v) 68 | 69 | 70 | def makeVerifier(username, password, bits): 71 | """Create a verifier entry which can be stored in a VerifierDB. 72 | 73 | @type username: str 74 | @param username: The username for this verifier. Must be less 75 | than 256 characters in length. 76 | 77 | @type password: str 78 | @param password: The password for this verifier. 79 | 80 | @type bits: int 81 | @param bits: This values specifies which SRP group parameters 82 | to use. It must be one of (1024, 1536, 2048, 3072, 4096, 6144, 83 | 8192). Larger values are more secure but slower. 2048 is a 84 | good compromise between safety and speed. 85 | 86 | @rtype: tuple 87 | @return: A tuple which may be stored in a VerifierDB. 88 | """ 89 | return mathtls.makeVerifier(username, password, bits) 90 | makeVerifier = staticmethod(makeVerifier) -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/cipherfactory.py: -------------------------------------------------------------------------------- 1 | """Factory functions for symmetric cryptography.""" 2 | 3 | import os 4 | 5 | import Python_AES 6 | import Python_RC4 7 | 8 | import cryptomath 9 | 10 | tripleDESPresent = False 11 | 12 | if cryptomath.m2cryptoLoaded: 13 | import OpenSSL_AES 14 | import OpenSSL_RC4 15 | import OpenSSL_TripleDES 16 | tripleDESPresent = True 17 | 18 | if cryptomath.cryptlibpyLoaded: 19 | import Cryptlib_AES 20 | import Cryptlib_RC4 21 | import Cryptlib_TripleDES 22 | tripleDESPresent = True 23 | 24 | if cryptomath.pycryptoLoaded: 25 | import PyCrypto_AES 26 | import PyCrypto_RC4 27 | import PyCrypto_TripleDES 28 | tripleDESPresent = True 29 | 30 | # ************************************************************************** 31 | # Factory Functions for AES 32 | # ************************************************************************** 33 | 34 | def createAES(key, IV, implList=None): 35 | """Create a new AES object. 36 | 37 | @type key: str 38 | @param key: A 16, 24, or 32 byte string. 39 | 40 | @type IV: str 41 | @param IV: A 16 byte string 42 | 43 | @rtype: L{tlslite.utils.AES} 44 | @return: An AES object. 45 | """ 46 | if implList == None: 47 | implList = ["cryptlib", "openssl", "pycrypto", "python"] 48 | 49 | for impl in implList: 50 | if impl == "cryptlib" and cryptomath.cryptlibpyLoaded: 51 | return Cryptlib_AES.new(key, 2, IV) 52 | elif impl == "openssl" and cryptomath.m2cryptoLoaded: 53 | return OpenSSL_AES.new(key, 2, IV) 54 | elif impl == "pycrypto" and cryptomath.pycryptoLoaded: 55 | return PyCrypto_AES.new(key, 2, IV) 56 | elif impl == "python": 57 | return Python_AES.new(key, 2, IV) 58 | raise NotImplementedError() 59 | 60 | def createRC4(key, IV, implList=None): 61 | """Create a new RC4 object. 62 | 63 | @type key: str 64 | @param key: A 16 to 32 byte string. 65 | 66 | @type IV: object 67 | @param IV: Ignored, whatever it is. 68 | 69 | @rtype: L{tlslite.utils.RC4} 70 | @return: An RC4 object. 71 | """ 72 | if implList == None: 73 | implList = ["cryptlib", "openssl", "pycrypto", "python"] 74 | 75 | if len(IV) != 0: 76 | raise AssertionError() 77 | for impl in implList: 78 | if impl == "cryptlib" and cryptomath.cryptlibpyLoaded: 79 | return Cryptlib_RC4.new(key) 80 | elif impl == "openssl" and cryptomath.m2cryptoLoaded: 81 | return OpenSSL_RC4.new(key) 82 | elif impl == "pycrypto" and cryptomath.pycryptoLoaded: 83 | return PyCrypto_RC4.new(key) 84 | elif impl == "python": 85 | return Python_RC4.new(key) 86 | raise NotImplementedError() 87 | 88 | #Create a new TripleDES instance 89 | def createTripleDES(key, IV, implList=None): 90 | """Create a new 3DES object. 91 | 92 | @type key: str 93 | @param key: A 24 byte string. 94 | 95 | @type IV: str 96 | @param IV: An 8 byte string 97 | 98 | @rtype: L{tlslite.utils.TripleDES} 99 | @return: A 3DES object. 100 | """ 101 | if implList == None: 102 | implList = ["cryptlib", "openssl", "pycrypto"] 103 | 104 | for impl in implList: 105 | if impl == "cryptlib" and cryptomath.cryptlibpyLoaded: 106 | return Cryptlib_TripleDES.new(key, 2, IV) 107 | elif impl == "openssl" and cryptomath.m2cryptoLoaded: 108 | return OpenSSL_TripleDES.new(key, 2, IV) 109 | elif impl == "pycrypto" and cryptomath.pycryptoLoaded: 110 | return PyCrypto_TripleDES.new(key, 2, IV) 111 | raise NotImplementedError() -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/hmac.py: -------------------------------------------------------------------------------- 1 | """HMAC (Keyed-Hashing for Message Authentication) Python module. 2 | 3 | Implements the HMAC algorithm as described by RFC 2104. 4 | 5 | (This file is modified from the standard library version to do faster 6 | copying) 7 | """ 8 | 9 | def _strxor(s1, s2): 10 | """Utility method. XOR the two strings s1 and s2 (must have same length). 11 | """ 12 | return "".join(map(lambda x, y: chr(ord(x) ^ ord(y)), s1, s2)) 13 | 14 | # The size of the digests returned by HMAC depends on the underlying 15 | # hashing module used. 16 | digest_size = None 17 | 18 | class HMAC: 19 | """RFC2104 HMAC class. 20 | 21 | This supports the API for Cryptographic Hash Functions (PEP 247). 22 | """ 23 | 24 | def __init__(self, key, msg = None, digestmod = None): 25 | """Create a new HMAC object. 26 | 27 | key: key for the keyed hash object. 28 | msg: Initial input for the hash, if provided. 29 | digestmod: A module supporting PEP 247. Defaults to the md5 module. 30 | """ 31 | if digestmod is None: 32 | import md5 33 | digestmod = md5 34 | 35 | if key == None: #TREVNEW - for faster copying 36 | return #TREVNEW 37 | 38 | self.digestmod = digestmod 39 | self.outer = digestmod.new() 40 | self.inner = digestmod.new() 41 | self.digest_size = digestmod.digest_size 42 | 43 | blocksize = 64 44 | ipad = "\x36" * blocksize 45 | opad = "\x5C" * blocksize 46 | 47 | if len(key) > blocksize: 48 | key = digestmod.new(key).digest() 49 | 50 | key = key + chr(0) * (blocksize - len(key)) 51 | self.outer.update(_strxor(key, opad)) 52 | self.inner.update(_strxor(key, ipad)) 53 | if msg is not None: 54 | self.update(msg) 55 | 56 | ## def clear(self): 57 | ## raise NotImplementedError, "clear() method not available in HMAC." 58 | 59 | def update(self, msg): 60 | """Update this hashing object with the string msg. 61 | """ 62 | self.inner.update(msg) 63 | 64 | def copy(self): 65 | """Return a separate copy of this hashing object. 66 | 67 | An update to this copy won't affect the original object. 68 | """ 69 | other = HMAC(None) #TREVNEW - for faster copying 70 | other.digest_size = self.digest_size #TREVNEW 71 | other.digestmod = self.digestmod 72 | other.inner = self.inner.copy() 73 | other.outer = self.outer.copy() 74 | return other 75 | 76 | def digest(self): 77 | """Return the hash value of this hashing object. 78 | 79 | This returns a string containing 8-bit data. The object is 80 | not altered in any way by this function; you can continue 81 | updating the object after calling this function. 82 | """ 83 | h = self.outer.copy() 84 | h.update(self.inner.digest()) 85 | return h.digest() 86 | 87 | def hexdigest(self): 88 | """Like digest(), but returns a string of hexadecimal digits instead. 89 | """ 90 | return "".join([hex(ord(x))[2:].zfill(2) 91 | for x in tuple(self.digest())]) 92 | 93 | def new(key, msg = None, digestmod = None): 94 | """Create a new hashing object and return it. 95 | 96 | key: The starting key for the hash. 97 | msg: if available, will immediately be hashed into the object's starting 98 | state. 99 | 100 | You can now feed arbitrary strings into the object using its update() 101 | method, and can ask for the hash value at any time by calling its digest() 102 | method. 103 | """ 104 | return HMAC(key, msg, digestmod) 105 | -------------------------------------------------------------------------------- /intercom/gdata/Crypto/Hash/HMAC.py: -------------------------------------------------------------------------------- 1 | """HMAC (Keyed-Hashing for Message Authentication) Python module. 2 | 3 | Implements the HMAC algorithm as described by RFC 2104. 4 | 5 | This is just a copy of the Python 2.2 HMAC module, modified to work when 6 | used on versions of Python before 2.2. 7 | """ 8 | 9 | __revision__ = "$Id: HMAC.py,v 1.5 2002/07/25 17:19:02 z3p Exp $" 10 | 11 | import string 12 | 13 | def _strxor(s1, s2): 14 | """Utility method. XOR the two strings s1 and s2 (must have same length). 15 | """ 16 | return "".join(map(lambda x, y: chr(ord(x) ^ ord(y)), s1, s2)) 17 | 18 | # The size of the digests returned by HMAC depends on the underlying 19 | # hashing module used. 20 | digest_size = None 21 | 22 | class HMAC: 23 | """RFC2104 HMAC class. 24 | 25 | This supports the API for Cryptographic Hash Functions (PEP 247). 26 | """ 27 | 28 | def __init__(self, key, msg = None, digestmod = None): 29 | """Create a new HMAC object. 30 | 31 | key: key for the keyed hash object. 32 | msg: Initial input for the hash, if provided. 33 | digestmod: A module supporting PEP 247. Defaults to the md5 module. 34 | """ 35 | if digestmod == None: 36 | import md5 37 | digestmod = md5 38 | 39 | self.digestmod = digestmod 40 | self.outer = digestmod.new() 41 | self.inner = digestmod.new() 42 | try: 43 | self.digest_size = digestmod.digest_size 44 | except AttributeError: 45 | self.digest_size = len(self.outer.digest()) 46 | 47 | blocksize = 64 48 | ipad = "\x36" * blocksize 49 | opad = "\x5C" * blocksize 50 | 51 | if len(key) > blocksize: 52 | key = digestmod.new(key).digest() 53 | 54 | key = key + chr(0) * (blocksize - len(key)) 55 | self.outer.update(_strxor(key, opad)) 56 | self.inner.update(_strxor(key, ipad)) 57 | if (msg): 58 | self.update(msg) 59 | 60 | ## def clear(self): 61 | ## raise NotImplementedError, "clear() method not available in HMAC." 62 | 63 | def update(self, msg): 64 | """Update this hashing object with the string msg. 65 | """ 66 | self.inner.update(msg) 67 | 68 | def copy(self): 69 | """Return a separate copy of this hashing object. 70 | 71 | An update to this copy won't affect the original object. 72 | """ 73 | other = HMAC("") 74 | other.digestmod = self.digestmod 75 | other.inner = self.inner.copy() 76 | other.outer = self.outer.copy() 77 | return other 78 | 79 | def digest(self): 80 | """Return the hash value of this hashing object. 81 | 82 | This returns a string containing 8-bit data. The object is 83 | not altered in any way by this function; you can continue 84 | updating the object after calling this function. 85 | """ 86 | h = self.outer.copy() 87 | h.update(self.inner.digest()) 88 | return h.digest() 89 | 90 | def hexdigest(self): 91 | """Like digest(), but returns a string of hexadecimal digits instead. 92 | """ 93 | return "".join([string.zfill(hex(ord(x))[2:], 2) 94 | for x in tuple(self.digest())]) 95 | 96 | def new(key, msg = None, digestmod = None): 97 | """Create a new hashing object and return it. 98 | 99 | key: The starting key for the hash. 100 | msg: if available, will immediately be hashed into the object's starting 101 | state. 102 | 103 | You can now feed arbitrary strings into the object using its update() 104 | method, and can ask for the hash value at any time by calling its digest() 105 | method. 106 | """ 107 | return HMAC(key, msg, digestmod) 108 | 109 | -------------------------------------------------------------------------------- /intercom/gdata/alt/app_engine.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2009 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | """Provides functions to persist serialized auth tokens in the datastore. 19 | 20 | The get_token and set_token functions should be used in conjunction with 21 | gdata.gauth's token_from_blob and token_to_blob to allow auth token objects 22 | to be reused across requests. It is up to your own code to ensure that the 23 | token key's are unique. 24 | """ 25 | 26 | __author__ = 'j.s@google.com (Jeff Scudder)' 27 | 28 | 29 | from google.appengine.ext import db 30 | from google.appengine.api import memcache 31 | 32 | 33 | class Token(db.Model): 34 | """Datastore Model which stores a serialized auth token.""" 35 | t = db.BlobProperty() 36 | 37 | 38 | def get_token(unique_key): 39 | """Searches for a stored token with the desired key. 40 | 41 | Checks memcache and then the datastore if required. 42 | 43 | Args: 44 | unique_key: str which uniquely identifies the desired auth token. 45 | 46 | Returns: 47 | A string encoding the auth token data. Use gdata.gauth.token_from_blob to 48 | convert back into a usable token object. None if the token was not found 49 | in memcache or the datastore. 50 | """ 51 | token_string = memcache.get(unique_key) 52 | if token_string is None: 53 | # The token wasn't in memcache, so look in the datastore. 54 | token = Token.get_by_key_name(unique_key) 55 | if token is None: 56 | return None 57 | return token.t 58 | return token_string 59 | 60 | 61 | def set_token(unique_key, token_str): 62 | """Saves the serialized auth token in the datastore. 63 | 64 | The token is also stored in memcache to speed up retrieval on a cache hit. 65 | 66 | Args: 67 | unique_key: The unique name for this token as a string. It is up to your 68 | code to ensure that this token value is unique in your application. 69 | Previous values will be silently overwitten. 70 | token_str: A serialized auth token as a string. I expect that this string 71 | will be generated by gdata.gauth.token_to_blob. 72 | 73 | Returns: 74 | True if the token was stored sucessfully, False if the token could not be 75 | safely cached (if an old value could not be cleared). If the token was 76 | set in memcache, but not in the datastore, this function will return None. 77 | However, in that situation an exception will likely be raised. 78 | 79 | Raises: 80 | Datastore exceptions may be raised from the App Engine SDK in the event of 81 | failure. 82 | """ 83 | # First try to save in memcache. 84 | result = memcache.set(unique_key, token_str) 85 | # If memcache fails to save the value, clear the cached value. 86 | if not result: 87 | result = memcache.delete(unique_key) 88 | # If we could not clear the cached value for this token, refuse to save. 89 | if result == 0: 90 | return False 91 | # Save to the datastore. 92 | if Token(key_name=unique_key, t=token_str).put(): 93 | return True 94 | return None 95 | 96 | 97 | def delete_token(unique_key): 98 | # Clear from memcache. 99 | memcache.delete(unique_key) 100 | # Clear from the datastore. 101 | Token(key_name=unique_key).delete() 102 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/SessionCache.py: -------------------------------------------------------------------------------- 1 | """Class for caching TLS sessions.""" 2 | 3 | import thread 4 | import time 5 | 6 | class SessionCache: 7 | """This class is used by the server to cache TLS sessions. 8 | 9 | Caching sessions allows the client to use TLS session resumption 10 | and avoid the expense of a full handshake. To use this class, 11 | simply pass a SessionCache instance into the server handshake 12 | function. 13 | 14 | This class is thread-safe. 15 | """ 16 | 17 | #References to these instances 18 | #are also held by the caller, who may change the 'resumable' 19 | #flag, so the SessionCache must return the same instances 20 | #it was passed in. 21 | 22 | def __init__(self, maxEntries=10000, maxAge=14400): 23 | """Create a new SessionCache. 24 | 25 | @type maxEntries: int 26 | @param maxEntries: The maximum size of the cache. When this 27 | limit is reached, the oldest sessions will be deleted as 28 | necessary to make room for new ones. The default is 10000. 29 | 30 | @type maxAge: int 31 | @param maxAge: The number of seconds before a session expires 32 | from the cache. The default is 14400 (i.e. 4 hours).""" 33 | 34 | self.lock = thread.allocate_lock() 35 | 36 | # Maps sessionIDs to sessions 37 | self.entriesDict = {} 38 | 39 | #Circular list of (sessionID, timestamp) pairs 40 | self.entriesList = [(None,None)] * maxEntries 41 | 42 | self.firstIndex = 0 43 | self.lastIndex = 0 44 | self.maxAge = maxAge 45 | 46 | def __getitem__(self, sessionID): 47 | self.lock.acquire() 48 | try: 49 | self._purge() #Delete old items, so we're assured of a new one 50 | session = self.entriesDict[sessionID] 51 | 52 | #When we add sessions they're resumable, but it's possible 53 | #for the session to be invalidated later on (if a fatal alert 54 | #is returned), so we have to check for resumability before 55 | #returning the session. 56 | 57 | if session.valid(): 58 | return session 59 | else: 60 | raise KeyError() 61 | finally: 62 | self.lock.release() 63 | 64 | 65 | def __setitem__(self, sessionID, session): 66 | self.lock.acquire() 67 | try: 68 | #Add the new element 69 | self.entriesDict[sessionID] = session 70 | self.entriesList[self.lastIndex] = (sessionID, time.time()) 71 | self.lastIndex = (self.lastIndex+1) % len(self.entriesList) 72 | 73 | #If the cache is full, we delete the oldest element to make an 74 | #empty space 75 | if self.lastIndex == self.firstIndex: 76 | del(self.entriesDict[self.entriesList[self.firstIndex][0]]) 77 | self.firstIndex = (self.firstIndex+1) % len(self.entriesList) 78 | finally: 79 | self.lock.release() 80 | 81 | #Delete expired items 82 | def _purge(self): 83 | currentTime = time.time() 84 | 85 | #Search through the circular list, deleting expired elements until 86 | #we reach a non-expired element. Since elements in list are 87 | #ordered in time, we can break once we reach the first non-expired 88 | #element 89 | index = self.firstIndex 90 | while index != self.lastIndex: 91 | if currentTime - self.entriesList[index][1] > self.maxAge: 92 | del(self.entriesDict[self.entriesList[index][0]]) 93 | index = (index+1) % len(self.entriesList) 94 | else: 95 | break 96 | self.firstIndex = index 97 | 98 | def _test(): 99 | import doctest, SessionCache 100 | return doctest.testmod(SessionCache) 101 | 102 | if __name__ == "__main__": 103 | _test() 104 | -------------------------------------------------------------------------------- /intercom/gdata/projecthosting/data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright 2009 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | # This module is used for version 2 of the Google Data APIs. 19 | 20 | 21 | """Provides classes and constants for XML in the Google Project Hosting API. 22 | 23 | Canonical documentation for the raw XML which these classes represent can be 24 | found here: http://code.google.com/p/support/wiki/IssueTrackerAPI 25 | """ 26 | 27 | 28 | __author__ = 'jlapenna@google.com (Joe LaPenna)' 29 | 30 | import atom.core 31 | import gdata.data 32 | 33 | 34 | ISSUES_TEMPLATE = '{http://schemas.google.com/projecthosting/issues/2009}%s' 35 | 36 | 37 | ISSUES_FULL_FEED = '/feeds/issues/p/%s/issues/full' 38 | COMMENTS_FULL_FEED = '/feeds/issues/p/%s/issues/%s/comments/full' 39 | 40 | 41 | class Uri(atom.core.XmlElement): 42 | """The issues:uri element.""" 43 | _qname = ISSUES_TEMPLATE % 'uri' 44 | 45 | 46 | class Username(atom.core.XmlElement): 47 | """The issues:username element.""" 48 | _qname = ISSUES_TEMPLATE % 'username' 49 | 50 | 51 | class Cc(atom.core.XmlElement): 52 | """The issues:cc element.""" 53 | _qname = ISSUES_TEMPLATE % 'cc' 54 | uri = Uri 55 | username = Username 56 | 57 | 58 | class Label(atom.core.XmlElement): 59 | """The issues:label element.""" 60 | _qname = ISSUES_TEMPLATE % 'label' 61 | 62 | 63 | class Owner(atom.core.XmlElement): 64 | """The issues:owner element.""" 65 | _qname = ISSUES_TEMPLATE % 'owner' 66 | uri = Uri 67 | username = Username 68 | 69 | 70 | class Stars(atom.core.XmlElement): 71 | """The issues:stars element.""" 72 | _qname = ISSUES_TEMPLATE % 'stars' 73 | 74 | 75 | class State(atom.core.XmlElement): 76 | """The issues:state element.""" 77 | _qname = ISSUES_TEMPLATE % 'state' 78 | 79 | 80 | class Status(atom.core.XmlElement): 81 | """The issues:status element.""" 82 | _qname = ISSUES_TEMPLATE % 'status' 83 | 84 | 85 | class Summary(atom.core.XmlElement): 86 | """The issues:summary element.""" 87 | _qname = ISSUES_TEMPLATE % 'summary' 88 | 89 | 90 | class OwnerUpdate(atom.core.XmlElement): 91 | """The issues:ownerUpdate element.""" 92 | _qname = ISSUES_TEMPLATE % 'ownerUpdate' 93 | 94 | 95 | class CcUpdate(atom.core.XmlElement): 96 | """The issues:ccUpdate element.""" 97 | _qname = ISSUES_TEMPLATE % 'ccUpdate' 98 | 99 | 100 | class Updates(atom.core.XmlElement): 101 | """The issues:updates element.""" 102 | _qname = ISSUES_TEMPLATE % 'updates' 103 | summary = Summary 104 | status = Status 105 | ownerUpdate = OwnerUpdate 106 | label = [Label] 107 | ccUpdate = [CcUpdate] 108 | 109 | 110 | class IssueEntry(gdata.data.GDEntry): 111 | """Represents the information of one issue.""" 112 | _qname = atom.data.ATOM_TEMPLATE % 'entry' 113 | owner = Owner 114 | cc = [Cc] 115 | label = [Label] 116 | stars = Stars 117 | state = State 118 | status = Status 119 | 120 | 121 | class IssuesFeed(gdata.data.GDFeed): 122 | """An Atom feed listing a project's issues.""" 123 | entry = [IssueEntry] 124 | 125 | 126 | class CommentEntry(gdata.data.GDEntry): 127 | """An entry detailing one comment on an issue.""" 128 | _qname = atom.data.ATOM_TEMPLATE % 'entry' 129 | updates = Updates 130 | 131 | 132 | class CommentsFeed(gdata.data.GDFeed): 133 | """An Atom feed listing a project's issue's comments.""" 134 | entry = [CommentEntry] 135 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/BaseDB.py: -------------------------------------------------------------------------------- 1 | """Base class for SharedKeyDB and VerifierDB.""" 2 | 3 | import anydbm 4 | import thread 5 | 6 | class BaseDB: 7 | def __init__(self, filename, type): 8 | self.type = type 9 | self.filename = filename 10 | if self.filename: 11 | self.db = None 12 | else: 13 | self.db = {} 14 | self.lock = thread.allocate_lock() 15 | 16 | def create(self): 17 | """Create a new on-disk database. 18 | 19 | @raise anydbm.error: If there's a problem creating the database. 20 | """ 21 | if self.filename: 22 | self.db = anydbm.open(self.filename, "n") #raises anydbm.error 23 | self.db["--Reserved--type"] = self.type 24 | self.db.sync() 25 | else: 26 | self.db = {} 27 | 28 | def open(self): 29 | """Open a pre-existing on-disk database. 30 | 31 | @raise anydbm.error: If there's a problem opening the database. 32 | @raise ValueError: If the database is not of the right type. 33 | """ 34 | if not self.filename: 35 | raise ValueError("Can only open on-disk databases") 36 | self.db = anydbm.open(self.filename, "w") #raises anydbm.error 37 | try: 38 | if self.db["--Reserved--type"] != self.type: 39 | raise ValueError("Not a %s database" % self.type) 40 | except KeyError: 41 | raise ValueError("Not a recognized database") 42 | 43 | def __getitem__(self, username): 44 | if self.db == None: 45 | raise AssertionError("DB not open") 46 | 47 | self.lock.acquire() 48 | try: 49 | valueStr = self.db[username] 50 | finally: 51 | self.lock.release() 52 | 53 | return self._getItem(username, valueStr) 54 | 55 | def __setitem__(self, username, value): 56 | if self.db == None: 57 | raise AssertionError("DB not open") 58 | 59 | valueStr = self._setItem(username, value) 60 | 61 | self.lock.acquire() 62 | try: 63 | self.db[username] = valueStr 64 | if self.filename: 65 | self.db.sync() 66 | finally: 67 | self.lock.release() 68 | 69 | def __delitem__(self, username): 70 | if self.db == None: 71 | raise AssertionError("DB not open") 72 | 73 | self.lock.acquire() 74 | try: 75 | del(self.db[username]) 76 | if self.filename: 77 | self.db.sync() 78 | finally: 79 | self.lock.release() 80 | 81 | def __contains__(self, username): 82 | """Check if the database contains the specified username. 83 | 84 | @type username: str 85 | @param username: The username to check for. 86 | 87 | @rtype: bool 88 | @return: True if the database contains the username, False 89 | otherwise. 90 | 91 | """ 92 | if self.db == None: 93 | raise AssertionError("DB not open") 94 | 95 | self.lock.acquire() 96 | try: 97 | return self.db.has_key(username) 98 | finally: 99 | self.lock.release() 100 | 101 | def check(self, username, param): 102 | value = self.__getitem__(username) 103 | return self._checkItem(value, username, param) 104 | 105 | def keys(self): 106 | """Return a list of usernames in the database. 107 | 108 | @rtype: list 109 | @return: The usernames in the database. 110 | """ 111 | if self.db == None: 112 | raise AssertionError("DB not open") 113 | 114 | self.lock.acquire() 115 | try: 116 | usernames = self.db.keys() 117 | finally: 118 | self.lock.release() 119 | usernames = [u for u in usernames if not u.startswith("--Reserved--")] 120 | return usernames -------------------------------------------------------------------------------- /intercom/twilio/contrib/httplib2/iri2uri.py: -------------------------------------------------------------------------------- 1 | """ 2 | iri2uri 3 | 4 | Converts an IRI to a URI. 5 | 6 | """ 7 | __author__ = "Joe Gregorio (joe@bitworking.org)" 8 | __copyright__ = "Copyright 2006, Joe Gregorio" 9 | __contributors__ = [] 10 | __version__ = "1.0.0" 11 | __license__ = "MIT" 12 | __history__ = """ 13 | """ 14 | 15 | import urlparse 16 | 17 | 18 | # Convert an IRI to a URI following the rules in RFC 3987 19 | # 20 | # The characters we need to enocde and escape are defined in the spec: 21 | # 22 | # iprivate = %xE000-F8FF / %xF0000-FFFFD / %x100000-10FFFD 23 | # ucschar = %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF 24 | # / %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD 25 | # / %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD 26 | # / %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD 27 | # / %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD 28 | # / %xD0000-DFFFD / %xE1000-EFFFD 29 | 30 | escape_range = [ 31 | (0xA0, 0xD7FF ), 32 | (0xE000, 0xF8FF ), 33 | (0xF900, 0xFDCF ), 34 | (0xFDF0, 0xFFEF), 35 | (0x10000, 0x1FFFD ), 36 | (0x20000, 0x2FFFD ), 37 | (0x30000, 0x3FFFD), 38 | (0x40000, 0x4FFFD ), 39 | (0x50000, 0x5FFFD ), 40 | (0x60000, 0x6FFFD), 41 | (0x70000, 0x7FFFD ), 42 | (0x80000, 0x8FFFD ), 43 | (0x90000, 0x9FFFD), 44 | (0xA0000, 0xAFFFD ), 45 | (0xB0000, 0xBFFFD ), 46 | (0xC0000, 0xCFFFD), 47 | (0xD0000, 0xDFFFD ), 48 | (0xE1000, 0xEFFFD), 49 | (0xF0000, 0xFFFFD ), 50 | (0x100000, 0x10FFFD) 51 | ] 52 | 53 | def encode(c): 54 | retval = c 55 | i = ord(c) 56 | for low, high in escape_range: 57 | if i < low: 58 | break 59 | if i >= low and i <= high: 60 | retval = "".join(["%%%2X" % ord(o) for o in c.encode('utf-8')]) 61 | break 62 | return retval 63 | 64 | 65 | def iri2uri(uri): 66 | """Convert an IRI to a URI. Note that IRIs must be 67 | passed in a unicode strings. That is, do not utf-8 encode 68 | the IRI before passing it into the function.""" 69 | if isinstance(uri ,unicode): 70 | (scheme, authority, path, query, fragment) = urlparse.urlsplit(uri) 71 | authority = authority.encode('idna') 72 | # For each character in 'ucschar' or 'iprivate' 73 | # 1. encode as utf-8 74 | # 2. then %-encode each octet of that utf-8 75 | uri = urlparse.urlunsplit((scheme, authority, path, query, fragment)) 76 | uri = "".join([encode(c) for c in uri]) 77 | return uri 78 | 79 | if __name__ == "__main__": 80 | import unittest 81 | 82 | class Test(unittest.TestCase): 83 | 84 | def test_uris(self): 85 | """Test that URIs are invariant under the transformation.""" 86 | invariant = [ 87 | u"ftp://ftp.is.co.za/rfc/rfc1808.txt", 88 | u"http://www.ietf.org/rfc/rfc2396.txt", 89 | u"ldap://[2001:db8::7]/c=GB?objectClass?one", 90 | u"mailto:John.Doe@example.com", 91 | u"news:comp.infosystems.www.servers.unix", 92 | u"tel:+1-816-555-1212", 93 | u"telnet://192.0.2.16:80/", 94 | u"urn:oasis:names:specification:docbook:dtd:xml:4.1.2" ] 95 | for uri in invariant: 96 | self.assertEqual(uri, iri2uri(uri)) 97 | 98 | def test_iri(self): 99 | """ Test that the right type of escaping is done for each part of the URI.""" 100 | self.assertEqual("http://xn--o3h.com/%E2%98%84", iri2uri(u"http://\N{COMET}.com/\N{COMET}")) 101 | self.assertEqual("http://bitworking.org/?fred=%E2%98%84", iri2uri(u"http://bitworking.org/?fred=\N{COMET}")) 102 | self.assertEqual("http://bitworking.org/#%E2%98%84", iri2uri(u"http://bitworking.org/#\N{COMET}")) 103 | self.assertEqual("#%E2%98%84", iri2uri(u"#\N{COMET}")) 104 | self.assertEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri(u"/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}")) 105 | self.assertEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri(iri2uri(u"/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}"))) 106 | self.assertNotEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri(u"/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}".encode('utf-8'))) 107 | 108 | unittest.main() 109 | 110 | 111 | -------------------------------------------------------------------------------- /intercom/atom/token_store.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2008 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """This module provides a TokenStore class which is designed to manage 18 | auth tokens required for different services. 19 | 20 | Each token is valid for a set of scopes which is the start of a URL. An HTTP 21 | client will use a token store to find a valid Authorization header to send 22 | in requests to the specified URL. If the HTTP client determines that a token 23 | has expired or been revoked, it can remove the token from the store so that 24 | it will not be used in future requests. 25 | """ 26 | 27 | 28 | __author__ = 'api.jscudder (Jeff Scudder)' 29 | 30 | 31 | import atom.http_interface 32 | import atom.url 33 | 34 | 35 | SCOPE_ALL = 'http' 36 | 37 | 38 | class TokenStore(object): 39 | """Manages Authorization tokens which will be sent in HTTP headers.""" 40 | def __init__(self, scoped_tokens=None): 41 | self._tokens = scoped_tokens or {} 42 | 43 | def add_token(self, token): 44 | """Adds a new token to the store (replaces tokens with the same scope). 45 | 46 | Args: 47 | token: A subclass of http_interface.GenericToken. The token object is 48 | responsible for adding the Authorization header to the HTTP request. 49 | The scopes defined in the token are used to determine if the token 50 | is valid for a requested scope when find_token is called. 51 | 52 | Returns: 53 | True if the token was added, False if the token was not added becase 54 | no scopes were provided. 55 | """ 56 | if not hasattr(token, 'scopes') or not token.scopes: 57 | return False 58 | 59 | for scope in token.scopes: 60 | self._tokens[str(scope)] = token 61 | return True 62 | 63 | def find_token(self, url): 64 | """Selects an Authorization header token which can be used for the URL. 65 | 66 | Args: 67 | url: str or atom.url.Url or a list containing the same. 68 | The URL which is going to be requested. All 69 | tokens are examined to see if any scopes begin match the beginning 70 | of the URL. The first match found is returned. 71 | 72 | Returns: 73 | The token object which should execute the HTTP request. If there was 74 | no token for the url (the url did not begin with any of the token 75 | scopes available), then the atom.http_interface.GenericToken will be 76 | returned because the GenericToken calls through to the http client 77 | without adding an Authorization header. 78 | """ 79 | if url is None: 80 | return None 81 | if isinstance(url, (str, unicode)): 82 | url = atom.url.parse_url(url) 83 | if url in self._tokens: 84 | token = self._tokens[url] 85 | if token.valid_for_scope(url): 86 | return token 87 | else: 88 | del self._tokens[url] 89 | for scope, token in self._tokens.iteritems(): 90 | if token.valid_for_scope(url): 91 | return token 92 | return atom.http_interface.GenericToken() 93 | 94 | def remove_token(self, token): 95 | """Removes the token from the token_store. 96 | 97 | This method is used when a token is determined to be invalid. If the 98 | token was found by find_token, but resulted in a 401 or 403 error stating 99 | that the token was invlid, then the token should be removed to prevent 100 | future use. 101 | 102 | Returns: 103 | True if a token was found and then removed from the token 104 | store. False if the token was not in the TokenStore. 105 | """ 106 | token_found = False 107 | scopes_to_delete = [] 108 | for scope, stored_token in self._tokens.iteritems(): 109 | if stored_token == token: 110 | scopes_to_delete.append(scope) 111 | token_found = True 112 | for scope in scopes_to_delete: 113 | del self._tokens[scope] 114 | return token_found 115 | 116 | def remove_all_tokens(self): 117 | self._tokens = {} 118 | -------------------------------------------------------------------------------- /intercom/gdata/Crypto/PublicKey/ElGamal.py: -------------------------------------------------------------------------------- 1 | # 2 | # ElGamal.py : ElGamal encryption/decryption and signatures 3 | # 4 | # Part of the Python Cryptography Toolkit 5 | # 6 | # Distribute and use freely; there are no restrictions on further 7 | # dissemination and usage except those imposed by the laws of your 8 | # country of residence. This software is provided "as is" without 9 | # warranty of fitness for use or suitability for any purpose, express 10 | # or implied. Use at your own risk or not at all. 11 | # 12 | 13 | __revision__ = "$Id: ElGamal.py,v 1.9 2003/04/04 19:44:26 akuchling Exp $" 14 | 15 | from Crypto.PublicKey.pubkey import * 16 | from Crypto.Util import number 17 | 18 | class error (Exception): 19 | pass 20 | 21 | # Generate an ElGamal key with N bits 22 | def generate(bits, randfunc, progress_func=None): 23 | """generate(bits:int, randfunc:callable, progress_func:callable) 24 | 25 | Generate an ElGamal key of length 'bits', using 'randfunc' to get 26 | random data and 'progress_func', if present, to display 27 | the progress of the key generation. 28 | """ 29 | obj=ElGamalobj() 30 | # Generate prime p 31 | if progress_func: 32 | progress_func('p\n') 33 | obj.p=bignum(getPrime(bits, randfunc)) 34 | # Generate random number g 35 | if progress_func: 36 | progress_func('g\n') 37 | size=bits-1-(ord(randfunc(1)) & 63) # g will be from 1--64 bits smaller than p 38 | if size<1: 39 | size=bits-1 40 | while (1): 41 | obj.g=bignum(getPrime(size, randfunc)) 42 | if obj.g < obj.p: 43 | break 44 | size=(size+1) % bits 45 | if size==0: 46 | size=4 47 | # Generate random number x 48 | if progress_func: 49 | progress_func('x\n') 50 | while (1): 51 | size=bits-1-ord(randfunc(1)) # x will be from 1 to 256 bits smaller than p 52 | if size>2: 53 | break 54 | while (1): 55 | obj.x=bignum(getPrime(size, randfunc)) 56 | if obj.x < obj.p: 57 | break 58 | size = (size+1) % bits 59 | if size==0: 60 | size=4 61 | if progress_func: 62 | progress_func('y\n') 63 | obj.y = pow(obj.g, obj.x, obj.p) 64 | return obj 65 | 66 | def construct(tuple): 67 | """construct(tuple:(long,long,long,long)|(long,long,long,long,long))) 68 | : ElGamalobj 69 | Construct an ElGamal key from a 3- or 4-tuple of numbers. 70 | """ 71 | 72 | obj=ElGamalobj() 73 | if len(tuple) not in [3,4]: 74 | raise error, 'argument for construct() wrong length' 75 | for i in range(len(tuple)): 76 | field = obj.keydata[i] 77 | setattr(obj, field, tuple[i]) 78 | return obj 79 | 80 | class ElGamalobj(pubkey): 81 | keydata=['p', 'g', 'y', 'x'] 82 | 83 | def _encrypt(self, M, K): 84 | a=pow(self.g, K, self.p) 85 | b=( M*pow(self.y, K, self.p) ) % self.p 86 | return ( a,b ) 87 | 88 | def _decrypt(self, M): 89 | if (not hasattr(self, 'x')): 90 | raise error, 'Private key not available in this object' 91 | ax=pow(M[0], self.x, self.p) 92 | plaintext=(M[1] * inverse(ax, self.p ) ) % self.p 93 | return plaintext 94 | 95 | def _sign(self, M, K): 96 | if (not hasattr(self, 'x')): 97 | raise error, 'Private key not available in this object' 98 | p1=self.p-1 99 | if (GCD(K, p1)!=1): 100 | raise error, 'Bad K value: GCD(K,p-1)!=1' 101 | a=pow(self.g, K, self.p) 102 | t=(M-self.x*a) % p1 103 | while t<0: t=t+p1 104 | b=(t*inverse(K, p1)) % p1 105 | return (a, b) 106 | 107 | def _verify(self, M, sig): 108 | v1=pow(self.y, sig[0], self.p) 109 | v1=(v1*pow(sig[0], sig[1], self.p)) % self.p 110 | v2=pow(self.g, M, self.p) 111 | if v1==v2: 112 | return 1 113 | return 0 114 | 115 | def size(self): 116 | "Return the maximum number of bits that can be handled by this key." 117 | return number.size(self.p) - 1 118 | 119 | def has_private(self): 120 | """Return a Boolean denoting whether the object contains 121 | private components.""" 122 | if hasattr(self, 'x'): 123 | return 1 124 | else: 125 | return 0 126 | 127 | def publickey(self): 128 | """Return a new key object containing only the public information.""" 129 | return construct((self.p, self.g, self.y)) 130 | 131 | 132 | object=ElGamalobj 133 | -------------------------------------------------------------------------------- /intercom/gdata/media/data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2009 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """Contains the data classes of the Yahoo! Media RSS Extension""" 18 | 19 | 20 | __author__ = 'j.s@google.com (Jeff Scudder)' 21 | 22 | 23 | import atom.core 24 | 25 | 26 | MEDIA_TEMPLATE = '{http://search.yahoo.com/mrss//}%s' 27 | 28 | 29 | class MediaCategory(atom.core.XmlElement): 30 | """Describes a media category.""" 31 | _qname = MEDIA_TEMPLATE % 'category' 32 | scheme = 'scheme' 33 | label = 'label' 34 | 35 | 36 | class MediaCopyright(atom.core.XmlElement): 37 | """Describes a media copyright.""" 38 | _qname = MEDIA_TEMPLATE % 'copyright' 39 | url = 'url' 40 | 41 | 42 | class MediaCredit(atom.core.XmlElement): 43 | """Describes a media credit.""" 44 | _qname = MEDIA_TEMPLATE % 'credit' 45 | role = 'role' 46 | scheme = 'scheme' 47 | 48 | 49 | class MediaDescription(atom.core.XmlElement): 50 | """Describes a media description.""" 51 | _qname = MEDIA_TEMPLATE % 'description' 52 | type = 'type' 53 | 54 | 55 | class MediaHash(atom.core.XmlElement): 56 | """Describes a media hash.""" 57 | _qname = MEDIA_TEMPLATE % 'hash' 58 | algo = 'algo' 59 | 60 | 61 | class MediaKeywords(atom.core.XmlElement): 62 | """Describes a media keywords.""" 63 | _qname = MEDIA_TEMPLATE % 'keywords' 64 | 65 | 66 | class MediaPlayer(atom.core.XmlElement): 67 | """Describes a media player.""" 68 | _qname = MEDIA_TEMPLATE % 'player' 69 | height = 'height' 70 | width = 'width' 71 | url = 'url' 72 | 73 | 74 | class MediaRating(atom.core.XmlElement): 75 | """Describes a media rating.""" 76 | _qname = MEDIA_TEMPLATE % 'rating' 77 | scheme = 'scheme' 78 | 79 | 80 | class MediaRestriction(atom.core.XmlElement): 81 | """Describes a media restriction.""" 82 | _qname = MEDIA_TEMPLATE % 'restriction' 83 | relationship = 'relationship' 84 | type = 'type' 85 | 86 | 87 | class MediaText(atom.core.XmlElement): 88 | """Describes a media text.""" 89 | _qname = MEDIA_TEMPLATE % 'text' 90 | end = 'end' 91 | lang = 'lang' 92 | type = 'type' 93 | start = 'start' 94 | 95 | 96 | class MediaThumbnail(atom.core.XmlElement): 97 | """Describes a media thumbnail.""" 98 | _qname = MEDIA_TEMPLATE % 'thumbnail' 99 | time = 'time' 100 | url = 'url' 101 | width = 'width' 102 | height = 'height' 103 | 104 | 105 | class MediaTitle(atom.core.XmlElement): 106 | """Describes a media title.""" 107 | _qname = MEDIA_TEMPLATE % 'title' 108 | type = 'type' 109 | 110 | 111 | class MediaContent(atom.core.XmlElement): 112 | """Describes a media content.""" 113 | _qname = MEDIA_TEMPLATE % 'content' 114 | bitrate = 'bitrate' 115 | is_default = 'isDefault' 116 | medium = 'medium' 117 | height = 'height' 118 | credit = [MediaCredit] 119 | language = 'language' 120 | hash = MediaHash 121 | width = 'width' 122 | player = MediaPlayer 123 | url = 'url' 124 | file_size = 'fileSize' 125 | channels = 'channels' 126 | expression = 'expression' 127 | text = [MediaText] 128 | samplingrate = 'samplingrate' 129 | title = MediaTitle 130 | category = [MediaCategory] 131 | rating = [MediaRating] 132 | type = 'type' 133 | description = MediaDescription 134 | framerate = 'framerate' 135 | thumbnail = [MediaThumbnail] 136 | duration = 'duration' 137 | copyright = MediaCopyright 138 | keywords = MediaKeywords 139 | restriction = [MediaRestriction] 140 | 141 | 142 | class MediaGroup(atom.core.XmlElement): 143 | """Describes a media group.""" 144 | _qname = MEDIA_TEMPLATE % 'group' 145 | credit = [MediaCredit] 146 | content = [MediaContent] 147 | copyright = MediaCopyright 148 | description = MediaDescription 149 | category = [MediaCategory] 150 | player = MediaPlayer 151 | rating = [MediaRating] 152 | hash = MediaHash 153 | title = MediaTitle 154 | keywords = MediaKeywords 155 | restriction = [MediaRestriction] 156 | thumbnail = [MediaThumbnail] 157 | text = [MediaText] 158 | 159 | 160 | -------------------------------------------------------------------------------- /intercom/gdata/finance/data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2009 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | """Contains the data classes of the Google Finance Portfolio Data API""" 19 | 20 | 21 | __author__ = 'j.s@google.com (Jeff Scudder)' 22 | 23 | 24 | import atom.core 25 | import atom.data 26 | import gdata.data 27 | import gdata.opensearch.data 28 | 29 | 30 | GF_TEMPLATE = '{http://schemas.google.com/finance/2007/}%s' 31 | 32 | 33 | class Commission(atom.core.XmlElement): 34 | """Commission for the transaction""" 35 | _qname = GF_TEMPLATE % 'commission' 36 | money = [gdata.data.Money] 37 | 38 | 39 | class CostBasis(atom.core.XmlElement): 40 | """Cost basis for the portfolio or position""" 41 | _qname = GF_TEMPLATE % 'costBasis' 42 | money = [gdata.data.Money] 43 | 44 | 45 | class DaysGain(atom.core.XmlElement): 46 | """Today's gain for the portfolio or position""" 47 | _qname = GF_TEMPLATE % 'daysGain' 48 | money = [gdata.data.Money] 49 | 50 | 51 | class Gain(atom.core.XmlElement): 52 | """Total gain for the portfolio or position""" 53 | _qname = GF_TEMPLATE % 'gain' 54 | money = [gdata.data.Money] 55 | 56 | 57 | class MarketValue(atom.core.XmlElement): 58 | """Market value for the portfolio or position""" 59 | _qname = GF_TEMPLATE % 'marketValue' 60 | money = [gdata.data.Money] 61 | 62 | 63 | class PortfolioData(atom.core.XmlElement): 64 | """Data for the portfolio""" 65 | _qname = GF_TEMPLATE % 'portfolioData' 66 | return_overall = 'returnOverall' 67 | currency_code = 'currencyCode' 68 | return3y = 'return3y' 69 | return4w = 'return4w' 70 | market_value = MarketValue 71 | return_y_t_d = 'returnYTD' 72 | cost_basis = CostBasis 73 | gain_percentage = 'gainPercentage' 74 | days_gain = DaysGain 75 | return3m = 'return3m' 76 | return5y = 'return5y' 77 | return1w = 'return1w' 78 | gain = Gain 79 | return1y = 'return1y' 80 | 81 | 82 | class PortfolioEntry(gdata.data.GDEntry): 83 | """Describes an entry in a feed of Finance portfolios""" 84 | portfolio_data = PortfolioData 85 | 86 | 87 | class PortfolioFeed(gdata.data.GDFeed): 88 | """Describes a Finance portfolio feed""" 89 | entry = [PortfolioEntry] 90 | 91 | 92 | class PositionData(atom.core.XmlElement): 93 | """Data for the position""" 94 | _qname = GF_TEMPLATE % 'positionData' 95 | return_y_t_d = 'returnYTD' 96 | return5y = 'return5y' 97 | return_overall = 'returnOverall' 98 | cost_basis = CostBasis 99 | return3y = 'return3y' 100 | return1y = 'return1y' 101 | return4w = 'return4w' 102 | shares = 'shares' 103 | days_gain = DaysGain 104 | gain_percentage = 'gainPercentage' 105 | market_value = MarketValue 106 | gain = Gain 107 | return3m = 'return3m' 108 | return1w = 'return1w' 109 | 110 | 111 | class Price(atom.core.XmlElement): 112 | """Price of the transaction""" 113 | _qname = GF_TEMPLATE % 'price' 114 | money = [gdata.data.Money] 115 | 116 | 117 | class Symbol(atom.core.XmlElement): 118 | """Stock symbol for the company""" 119 | _qname = GF_TEMPLATE % 'symbol' 120 | symbol = 'symbol' 121 | exchange = 'exchange' 122 | full_name = 'fullName' 123 | 124 | 125 | class PositionEntry(gdata.data.GDEntry): 126 | """Describes an entry in a feed of Finance positions""" 127 | symbol = Symbol 128 | position_data = PositionData 129 | 130 | 131 | class PositionFeed(gdata.data.GDFeed): 132 | """Describes a Finance position feed""" 133 | entry = [PositionEntry] 134 | 135 | 136 | class TransactionData(atom.core.XmlElement): 137 | """Data for the transction""" 138 | _qname = GF_TEMPLATE % 'transactionData' 139 | shares = 'shares' 140 | notes = 'notes' 141 | date = 'date' 142 | type = 'type' 143 | commission = Commission 144 | price = Price 145 | 146 | 147 | class TransactionEntry(gdata.data.GDEntry): 148 | """Describes an entry in a feed of Finance transactions""" 149 | transaction_data = TransactionData 150 | 151 | 152 | class TransactionFeed(gdata.data.GDFeed): 153 | """Describes a Finance transaction feed""" 154 | entry = [TransactionEntry] 155 | 156 | 157 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/utils/compat.py: -------------------------------------------------------------------------------- 1 | """Miscellaneous functions to mask Python version differences.""" 2 | 3 | import sys 4 | import os 5 | 6 | if sys.version_info < (2,2): 7 | raise AssertionError("Python 2.2 or later required") 8 | 9 | if sys.version_info < (2,3): 10 | 11 | def enumerate(collection): 12 | return zip(range(len(collection)), collection) 13 | 14 | class Set: 15 | def __init__(self, seq=None): 16 | self.values = {} 17 | if seq: 18 | for e in seq: 19 | self.values[e] = None 20 | 21 | def add(self, e): 22 | self.values[e] = None 23 | 24 | def discard(self, e): 25 | if e in self.values.keys(): 26 | del(self.values[e]) 27 | 28 | def union(self, s): 29 | ret = Set() 30 | for e in self.values.keys(): 31 | ret.values[e] = None 32 | for e in s.values.keys(): 33 | ret.values[e] = None 34 | return ret 35 | 36 | def issubset(self, other): 37 | for e in self.values.keys(): 38 | if e not in other.values.keys(): 39 | return False 40 | return True 41 | 42 | def __nonzero__( self): 43 | return len(self.values.keys()) 44 | 45 | def __contains__(self, e): 46 | return e in self.values.keys() 47 | 48 | def __iter__(self): 49 | return iter(set.values.keys()) 50 | 51 | 52 | if os.name != "java": 53 | 54 | import array 55 | def createByteArraySequence(seq): 56 | return array.array('B', seq) 57 | def createByteArrayZeros(howMany): 58 | return array.array('B', [0] * howMany) 59 | def concatArrays(a1, a2): 60 | return a1+a2 61 | 62 | def bytesToString(bytes): 63 | return bytes.tostring() 64 | def stringToBytes(s): 65 | bytes = createByteArrayZeros(0) 66 | bytes.fromstring(s) 67 | return bytes 68 | 69 | import math 70 | def numBits(n): 71 | if n==0: 72 | return 0 73 | s = "%x" % n 74 | return ((len(s)-1)*4) + \ 75 | {'0':0, '1':1, '2':2, '3':2, 76 | '4':3, '5':3, '6':3, '7':3, 77 | '8':4, '9':4, 'a':4, 'b':4, 78 | 'c':4, 'd':4, 'e':4, 'f':4, 79 | }[s[0]] 80 | return int(math.floor(math.log(n, 2))+1) 81 | 82 | BaseException = Exception 83 | import sys 84 | import traceback 85 | def formatExceptionTrace(e): 86 | newStr = "".join(traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback)) 87 | return newStr 88 | 89 | else: 90 | #Jython 2.1 is missing lots of python 2.3 stuff, 91 | #which we have to emulate here: 92 | #NOTE: JYTHON SUPPORT NO LONGER WORKS, DUE TO USE OF GENERATORS. 93 | #THIS CODE IS LEFT IN SO THAT ONE JYTHON UPDATES TO 2.2, IT HAS A 94 | #CHANCE OF WORKING AGAIN. 95 | 96 | import java 97 | import jarray 98 | 99 | def createByteArraySequence(seq): 100 | if isinstance(seq, type("")): #If it's a string, convert 101 | seq = [ord(c) for c in seq] 102 | return jarray.array(seq, 'h') #use short instead of bytes, cause bytes are signed 103 | def createByteArrayZeros(howMany): 104 | return jarray.zeros(howMany, 'h') #use short instead of bytes, cause bytes are signed 105 | def concatArrays(a1, a2): 106 | l = list(a1)+list(a2) 107 | return createByteArraySequence(l) 108 | 109 | #WAY TOO SLOW - MUST BE REPLACED------------ 110 | def bytesToString(bytes): 111 | return "".join([chr(b) for b in bytes]) 112 | 113 | def stringToBytes(s): 114 | bytes = createByteArrayZeros(len(s)) 115 | for count, c in enumerate(s): 116 | bytes[count] = ord(c) 117 | return bytes 118 | #WAY TOO SLOW - MUST BE REPLACED------------ 119 | 120 | def numBits(n): 121 | if n==0: 122 | return 0 123 | n= 1L * n; #convert to long, if it isn't already 124 | return n.__tojava__(java.math.BigInteger).bitLength() 125 | 126 | #Adjust the string to an array of bytes 127 | def stringToJavaByteArray(s): 128 | bytes = jarray.zeros(len(s), 'b') 129 | for count, c in enumerate(s): 130 | x = ord(c) 131 | if x >= 128: x -= 256 132 | bytes[count] = x 133 | return bytes 134 | 135 | BaseException = java.lang.Exception 136 | import sys 137 | import traceback 138 | def formatExceptionTrace(e): 139 | newStr = "".join(traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback)) 140 | return newStr -------------------------------------------------------------------------------- /intercom/twilio/rest/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | from twilio import TwilioException 4 | from twilio.rest.resources import make_request 5 | from twilio.rest.resources import Accounts 6 | from twilio.rest.resources import Applications 7 | from twilio.rest.resources import Calls 8 | from twilio.rest.resources import CallerIds 9 | from twilio.rest.resources import Notifications 10 | from twilio.rest.resources import Recordings 11 | from twilio.rest.resources import Transcriptions 12 | from twilio.rest.resources import Sms 13 | from twilio.rest.resources import Participants 14 | from twilio.rest.resources import PhoneNumbers 15 | from twilio.rest.resources import Conferences 16 | from twilio.rest.resources import Sandboxes 17 | from urllib import urlencode 18 | from urlparse import urljoin 19 | 20 | 21 | def find_credentials(): 22 | """ 23 | Look in the current environment for Twilio credentails 24 | """ 25 | try: 26 | account = os.environ["TWILIO_ACCOUNT_SID"] 27 | token = os.environ["TWILIO_AUTH_TOKEN"] 28 | return account, token 29 | except KeyError: 30 | return None, None 31 | 32 | 33 | class TwilioRestClient(object): 34 | """ 35 | A client for accessing the Twilio REST API 36 | """ 37 | 38 | def request(self, path, method=None, vars=None): 39 | """sends a request and gets a response from the Twilio REST API 40 | 41 | .. deprecated:: 3.0 42 | 43 | :param path: the URL (relative to the endpoint URL, after the /v1 44 | :param url: the HTTP method to use, defaults to POST 45 | :param vars: for POST or PUT, a dict of data to send 46 | 47 | :returns: Twilio response in XML or raises an exception on error 48 | 49 | This method is only included for backwards compatability reasons. 50 | It will be removed in a future version 51 | """ 52 | logging.warning(":meth:`TwilioRestClient.request` is deprecated and " 53 | "will be removed in a future version") 54 | 55 | vars = vars or {} 56 | params = None 57 | data = None 58 | 59 | if not path or len(path) < 1: 60 | raise ValueError('Invalid path parameter') 61 | if method and method not in ['GET', 'POST', 'DELETE', 'PUT']: 62 | raise NotImplementedError( 63 | 'HTTP %s method not implemented' % method) 64 | 65 | if path[0] == '/': 66 | uri = _TWILIO_API_URL + path 67 | else: 68 | uri = _TWILIO_API_URL + '/' + path 69 | 70 | if method == "GET": 71 | params = vars 72 | elif method == "POST" or method == "PUT": 73 | data = vars 74 | 75 | headers = { 76 | "User-Agent": "twilio-python", 77 | } 78 | 79 | resp = make_request(method, uri, auth=self.auth, data=data, 80 | params=params, headers=headers) 81 | 82 | return resp.content 83 | 84 | def __init__(self, account=None, token=None, base="https://api.twilio.com", 85 | version="2010-04-01", client=None): 86 | """ 87 | Create a Twilio REST API client. 88 | """ 89 | 90 | # Get account credentials 91 | if not account or not token: 92 | account, token = find_credentials() 93 | if not account or not token: 94 | raise TwilioException("Could not find account credentials") 95 | 96 | auth = (account, token) 97 | version_uri = "%s/%s" % (base, version) 98 | account_uri = "%s/%s/Accounts/%s" % (base, version, account) 99 | 100 | self.accounts = Accounts(version_uri, auth) 101 | self.applications = Applications(account_uri, auth) 102 | self.calls = Calls(account_uri, auth) 103 | self.caller_ids = CallerIds(account_uri, auth) 104 | self.notifications = Notifications(account_uri, auth) 105 | self.recordings = Recordings(account_uri, auth) 106 | self.transcriptions = Transcriptions(account_uri, auth) 107 | self.sms = Sms(account_uri, auth) 108 | self.phone_numbers = PhoneNumbers(account_uri, auth) 109 | self.conferences = Conferences(account_uri, auth) 110 | self.sandboxes = Sandboxes(account_uri, auth) 111 | 112 | self.auth = auth 113 | self.account_uri = account_uri 114 | 115 | def participants(self, conference_sid): 116 | """ 117 | Return a :class:`Participants` instance for the :class:`Conference` 118 | with conference_sid, 119 | """ 120 | base_uri = "%s/Conferences/%s" % (self.account_uri, conference_sid) 121 | return Participants(base_uri, self.auth) 122 | 123 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/X509.py: -------------------------------------------------------------------------------- 1 | """Class representing an X.509 certificate.""" 2 | 3 | from utils.ASN1Parser import ASN1Parser 4 | from utils.cryptomath import * 5 | from utils.keyfactory import _createPublicRSAKey 6 | 7 | 8 | class X509: 9 | """This class represents an X.509 certificate. 10 | 11 | @type bytes: L{array.array} of unsigned bytes 12 | @ivar bytes: The DER-encoded ASN.1 certificate 13 | 14 | @type publicKey: L{tlslite.utils.RSAKey.RSAKey} 15 | @ivar publicKey: The subject public key from the certificate. 16 | """ 17 | 18 | def __init__(self): 19 | self.bytes = createByteArraySequence([]) 20 | self.publicKey = None 21 | 22 | def parse(self, s): 23 | """Parse a PEM-encoded X.509 certificate. 24 | 25 | @type s: str 26 | @param s: A PEM-encoded X.509 certificate (i.e. a base64-encoded 27 | certificate wrapped with "-----BEGIN CERTIFICATE-----" and 28 | "-----END CERTIFICATE-----" tags). 29 | """ 30 | 31 | start = s.find("-----BEGIN CERTIFICATE-----") 32 | end = s.find("-----END CERTIFICATE-----") 33 | if start == -1: 34 | raise SyntaxError("Missing PEM prefix") 35 | if end == -1: 36 | raise SyntaxError("Missing PEM postfix") 37 | s = s[start+len("-----BEGIN CERTIFICATE-----") : end] 38 | 39 | bytes = base64ToBytes(s) 40 | self.parseBinary(bytes) 41 | return self 42 | 43 | def parseBinary(self, bytes): 44 | """Parse a DER-encoded X.509 certificate. 45 | 46 | @type bytes: str or L{array.array} of unsigned bytes 47 | @param bytes: A DER-encoded X.509 certificate. 48 | """ 49 | 50 | if isinstance(bytes, type("")): 51 | bytes = stringToBytes(bytes) 52 | 53 | self.bytes = bytes 54 | p = ASN1Parser(bytes) 55 | 56 | #Get the tbsCertificate 57 | tbsCertificateP = p.getChild(0) 58 | 59 | #Is the optional version field present? 60 | #This determines which index the key is at. 61 | if tbsCertificateP.value[0]==0xA0: 62 | subjectPublicKeyInfoIndex = 6 63 | else: 64 | subjectPublicKeyInfoIndex = 5 65 | 66 | #Get the subjectPublicKeyInfo 67 | subjectPublicKeyInfoP = tbsCertificateP.getChild(\ 68 | subjectPublicKeyInfoIndex) 69 | 70 | #Get the algorithm 71 | algorithmP = subjectPublicKeyInfoP.getChild(0) 72 | rsaOID = algorithmP.value 73 | if list(rsaOID) != [6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0]: 74 | raise SyntaxError("Unrecognized AlgorithmIdentifier") 75 | 76 | #Get the subjectPublicKey 77 | subjectPublicKeyP = subjectPublicKeyInfoP.getChild(1) 78 | 79 | #Adjust for BIT STRING encapsulation 80 | if (subjectPublicKeyP.value[0] !=0): 81 | raise SyntaxError() 82 | subjectPublicKeyP = ASN1Parser(subjectPublicKeyP.value[1:]) 83 | 84 | #Get the modulus and exponent 85 | modulusP = subjectPublicKeyP.getChild(0) 86 | publicExponentP = subjectPublicKeyP.getChild(1) 87 | 88 | #Decode them into numbers 89 | n = bytesToNumber(modulusP.value) 90 | e = bytesToNumber(publicExponentP.value) 91 | 92 | #Create a public key instance 93 | self.publicKey = _createPublicRSAKey(n, e) 94 | 95 | def getFingerprint(self): 96 | """Get the hex-encoded fingerprint of this certificate. 97 | 98 | @rtype: str 99 | @return: A hex-encoded fingerprint. 100 | """ 101 | return sha.sha(self.bytes).hexdigest() 102 | 103 | def getCommonName(self): 104 | """Get the Subject's Common Name from the certificate. 105 | 106 | The cryptlib_py module must be installed in order to use this 107 | function. 108 | 109 | @rtype: str or None 110 | @return: The CN component of the certificate's subject DN, if 111 | present. 112 | """ 113 | import cryptlib_py 114 | import array 115 | c = cryptlib_py.cryptImportCert(self.bytes, cryptlib_py.CRYPT_UNUSED) 116 | name = cryptlib_py.CRYPT_CERTINFO_COMMONNAME 117 | try: 118 | try: 119 | length = cryptlib_py.cryptGetAttributeString(c, name, None) 120 | returnVal = array.array('B', [0] * length) 121 | cryptlib_py.cryptGetAttributeString(c, name, returnVal) 122 | returnVal = returnVal.tostring() 123 | except cryptlib_py.CryptException, e: 124 | if e[0] == cryptlib_py.CRYPT_ERROR_NOTFOUND: 125 | returnVal = None 126 | return returnVal 127 | finally: 128 | cryptlib_py.cryptDestroyCert(c) 129 | 130 | def writeBytes(self): 131 | return self.bytes 132 | 133 | 134 | -------------------------------------------------------------------------------- /intercom/atom/url.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2008 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | __author__ = 'api.jscudder (Jeff Scudder)' 19 | 20 | 21 | import urlparse 22 | import urllib 23 | 24 | 25 | DEFAULT_PROTOCOL = 'http' 26 | DEFAULT_PORT = 80 27 | 28 | 29 | def parse_url(url_string): 30 | """Creates a Url object which corresponds to the URL string. 31 | 32 | This method can accept partial URLs, but it will leave missing 33 | members of the Url unset. 34 | """ 35 | parts = urlparse.urlparse(url_string) 36 | url = Url() 37 | if parts[0]: 38 | url.protocol = parts[0] 39 | if parts[1]: 40 | host_parts = parts[1].split(':') 41 | if host_parts[0]: 42 | url.host = host_parts[0] 43 | if len(host_parts) > 1: 44 | url.port = host_parts[1] 45 | if parts[2]: 46 | url.path = parts[2] 47 | if parts[4]: 48 | param_pairs = parts[4].split('&') 49 | for pair in param_pairs: 50 | pair_parts = pair.split('=') 51 | if len(pair_parts) > 1: 52 | url.params[urllib.unquote_plus(pair_parts[0])] = ( 53 | urllib.unquote_plus(pair_parts[1])) 54 | elif len(pair_parts) == 1: 55 | url.params[urllib.unquote_plus(pair_parts[0])] = None 56 | return url 57 | 58 | class Url(object): 59 | """Represents a URL and implements comparison logic. 60 | 61 | URL strings which are not identical can still be equivalent, so this object 62 | provides a better interface for comparing and manipulating URLs than 63 | strings. URL parameters are represented as a dictionary of strings, and 64 | defaults are used for the protocol (http) and port (80) if not provided. 65 | """ 66 | def __init__(self, protocol=None, host=None, port=None, path=None, 67 | params=None): 68 | self.protocol = protocol 69 | self.host = host 70 | self.port = port 71 | self.path = path 72 | self.params = params or {} 73 | 74 | def to_string(self): 75 | url_parts = ['', '', '', '', '', ''] 76 | if self.protocol: 77 | url_parts[0] = self.protocol 78 | if self.host: 79 | if self.port: 80 | url_parts[1] = ':'.join((self.host, str(self.port))) 81 | else: 82 | url_parts[1] = self.host 83 | if self.path: 84 | url_parts[2] = self.path 85 | if self.params: 86 | url_parts[4] = self.get_param_string() 87 | return urlparse.urlunparse(url_parts) 88 | 89 | def get_param_string(self): 90 | param_pairs = [] 91 | for key, value in self.params.iteritems(): 92 | param_pairs.append('='.join((urllib.quote_plus(key), 93 | urllib.quote_plus(str(value))))) 94 | return '&'.join(param_pairs) 95 | 96 | def get_request_uri(self): 97 | """Returns the path with the parameters escaped and appended.""" 98 | param_string = self.get_param_string() 99 | if param_string: 100 | return '?'.join([self.path, param_string]) 101 | else: 102 | return self.path 103 | 104 | def __cmp__(self, other): 105 | if not isinstance(other, Url): 106 | return cmp(self.to_string(), str(other)) 107 | difference = 0 108 | # Compare the protocol 109 | if self.protocol and other.protocol: 110 | difference = cmp(self.protocol, other.protocol) 111 | elif self.protocol and not other.protocol: 112 | difference = cmp(self.protocol, DEFAULT_PROTOCOL) 113 | elif not self.protocol and other.protocol: 114 | difference = cmp(DEFAULT_PROTOCOL, other.protocol) 115 | if difference != 0: 116 | return difference 117 | # Compare the host 118 | difference = cmp(self.host, other.host) 119 | if difference != 0: 120 | return difference 121 | # Compare the port 122 | if self.port and other.port: 123 | difference = cmp(self.port, other.port) 124 | elif self.port and not other.port: 125 | difference = cmp(self.port, DEFAULT_PORT) 126 | elif not self.port and other.port: 127 | difference = cmp(DEFAULT_PORT, other.port) 128 | if difference != 0: 129 | return difference 130 | # Compare the path 131 | difference = cmp(self.path, other.path) 132 | if difference != 0: 133 | return difference 134 | # Compare the parameters 135 | return cmp(self.params, other.params) 136 | 137 | def __str__(self): 138 | return self.to_string() 139 | 140 | -------------------------------------------------------------------------------- /intercom/gdata/oauth/rsa.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | requires tlslite - http://trevp.net/tlslite/ 5 | 6 | """ 7 | 8 | import binascii 9 | 10 | from gdata.tlslite.utils import keyfactory 11 | from gdata.tlslite.utils import cryptomath 12 | 13 | # XXX andy: ugly local import due to module name, oauth.oauth 14 | import gdata.oauth as oauth 15 | 16 | class OAuthSignatureMethod_RSA_SHA1(oauth.OAuthSignatureMethod): 17 | def get_name(self): 18 | return "RSA-SHA1" 19 | 20 | def _fetch_public_cert(self, oauth_request): 21 | # not implemented yet, ideas are: 22 | # (1) do a lookup in a table of trusted certs keyed off of consumer 23 | # (2) fetch via http using a url provided by the requester 24 | # (3) some sort of specific discovery code based on request 25 | # 26 | # either way should return a string representation of the certificate 27 | raise NotImplementedError 28 | 29 | def _fetch_private_cert(self, oauth_request): 30 | # not implemented yet, ideas are: 31 | # (1) do a lookup in a table of trusted certs keyed off of consumer 32 | # 33 | # either way should return a string representation of the certificate 34 | raise NotImplementedError 35 | 36 | def build_signature_base_string(self, oauth_request, consumer, token): 37 | sig = ( 38 | oauth.escape(oauth_request.get_normalized_http_method()), 39 | oauth.escape(oauth_request.get_normalized_http_url()), 40 | oauth.escape(oauth_request.get_normalized_parameters()), 41 | ) 42 | key = '' 43 | raw = '&'.join(sig) 44 | return key, raw 45 | 46 | def build_signature(self, oauth_request, consumer, token): 47 | key, base_string = self.build_signature_base_string(oauth_request, 48 | consumer, 49 | token) 50 | 51 | # Fetch the private key cert based on the request 52 | cert = self._fetch_private_cert(oauth_request) 53 | 54 | # Pull the private key from the certificate 55 | privatekey = keyfactory.parsePrivateKey(cert) 56 | 57 | # Convert base_string to bytes 58 | #base_string_bytes = cryptomath.createByteArraySequence(base_string) 59 | 60 | # Sign using the key 61 | signed = privatekey.hashAndSign(base_string) 62 | 63 | return binascii.b2a_base64(signed)[:-1] 64 | 65 | def check_signature(self, oauth_request, consumer, token, signature): 66 | decoded_sig = base64.b64decode(signature); 67 | 68 | key, base_string = self.build_signature_base_string(oauth_request, 69 | consumer, 70 | token) 71 | 72 | # Fetch the public key cert based on the request 73 | cert = self._fetch_public_cert(oauth_request) 74 | 75 | # Pull the public key from the certificate 76 | publickey = keyfactory.parsePEMKey(cert, public=True) 77 | 78 | # Check the signature 79 | ok = publickey.hashAndVerify(decoded_sig, base_string) 80 | 81 | return ok 82 | 83 | 84 | class TestOAuthSignatureMethod_RSA_SHA1(OAuthSignatureMethod_RSA_SHA1): 85 | def _fetch_public_cert(self, oauth_request): 86 | cert = """ 87 | -----BEGIN CERTIFICATE----- 88 | MIIBpjCCAQ+gAwIBAgIBATANBgkqhkiG9w0BAQUFADAZMRcwFQYDVQQDDA5UZXN0 89 | IFByaW5jaXBhbDAeFw03MDAxMDEwODAwMDBaFw0zODEyMzEwODAwMDBaMBkxFzAV 90 | BgNVBAMMDlRlc3QgUHJpbmNpcGFsMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB 91 | gQC0YjCwIfYoprq/FQO6lb3asXrxLlJFuCvtinTF5p0GxvQGu5O3gYytUvtC2JlY 92 | zypSRjVxwxrsuRcP3e641SdASwfrmzyvIgP08N4S0IFzEURkV1wp/IpH7kH41Etb 93 | mUmrXSwfNZsnQRE5SYSOhh+LcK2wyQkdgcMv11l4KoBkcwIDAQABMA0GCSqGSIb3 94 | DQEBBQUAA4GBAGZLPEuJ5SiJ2ryq+CmEGOXfvlTtEL2nuGtr9PewxkgnOjZpUy+d 95 | 4TvuXJbNQc8f4AMWL/tO9w0Fk80rWKp9ea8/df4qMq5qlFWlx6yOLQxumNOmECKb 96 | WpkUQDIDJEoFUzKMVuJf4KO/FJ345+BNLGgbJ6WujreoM1X/gYfdnJ/J 97 | -----END CERTIFICATE----- 98 | """ 99 | return cert 100 | 101 | def _fetch_private_cert(self, oauth_request): 102 | cert = """ 103 | -----BEGIN PRIVATE KEY----- 104 | MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALRiMLAh9iimur8V 105 | A7qVvdqxevEuUkW4K+2KdMXmnQbG9Aa7k7eBjK1S+0LYmVjPKlJGNXHDGuy5Fw/d 106 | 7rjVJ0BLB+ubPK8iA/Tw3hLQgXMRRGRXXCn8ikfuQfjUS1uZSatdLB81mydBETlJ 107 | hI6GH4twrbDJCR2Bwy/XWXgqgGRzAgMBAAECgYBYWVtleUzavkbrPjy0T5FMou8H 108 | X9u2AC2ry8vD/l7cqedtwMPp9k7TubgNFo+NGvKsl2ynyprOZR1xjQ7WgrgVB+mm 109 | uScOM/5HVceFuGRDhYTCObE+y1kxRloNYXnx3ei1zbeYLPCHdhxRYW7T0qcynNmw 110 | rn05/KO2RLjgQNalsQJBANeA3Q4Nugqy4QBUCEC09SqylT2K9FrrItqL2QKc9v0Z 111 | zO2uwllCbg0dwpVuYPYXYvikNHHg+aCWF+VXsb9rpPsCQQDWR9TT4ORdzoj+Nccn 112 | qkMsDmzt0EfNaAOwHOmVJ2RVBspPcxt5iN4HI7HNeG6U5YsFBb+/GZbgfBT3kpNG 113 | WPTpAkBI+gFhjfJvRw38n3g/+UeAkwMI2TJQS4n8+hid0uus3/zOjDySH3XHCUno 114 | cn1xOJAyZODBo47E+67R4jV1/gzbAkEAklJaspRPXP877NssM5nAZMU0/O/NGCZ+ 115 | 3jPgDUno6WbJn5cqm8MqWhW1xGkImgRk+fkDBquiq4gPiT898jusgQJAd5Zrr6Q8 116 | AO/0isr/3aa6O6NLQxISLKcPDk2NOccAfS/xOtfOz4sJYM3+Bs4Io9+dZGSDCA54 117 | Lw03eHTNQghS0A== 118 | -----END PRIVATE KEY----- 119 | """ 120 | return cert 121 | -------------------------------------------------------------------------------- /intercom/atom/mock_http.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2008 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | __author__ = 'api.jscudder (Jeff Scudder)' 19 | 20 | 21 | import atom.http_interface 22 | import atom.url 23 | 24 | 25 | class Error(Exception): 26 | pass 27 | 28 | 29 | class NoRecordingFound(Error): 30 | pass 31 | 32 | 33 | class MockRequest(object): 34 | """Holds parameters of an HTTP request for matching against future requests. 35 | """ 36 | def __init__(self, operation, url, data=None, headers=None): 37 | self.operation = operation 38 | if isinstance(url, (str, unicode)): 39 | url = atom.url.parse_url(url) 40 | self.url = url 41 | self.data = data 42 | self.headers = headers 43 | 44 | 45 | class MockResponse(atom.http_interface.HttpResponse): 46 | """Simulates an httplib.HTTPResponse object.""" 47 | def __init__(self, body=None, status=None, reason=None, headers=None): 48 | if body and hasattr(body, 'read'): 49 | self.body = body.read() 50 | else: 51 | self.body = body 52 | if status is not None: 53 | self.status = int(status) 54 | else: 55 | self.status = None 56 | self.reason = reason 57 | self._headers = headers or {} 58 | 59 | def read(self): 60 | return self.body 61 | 62 | 63 | class MockHttpClient(atom.http_interface.GenericHttpClient): 64 | def __init__(self, headers=None, recordings=None, real_client=None): 65 | """An HttpClient which responds to request with stored data. 66 | 67 | The request-response pairs are stored as tuples in a member list named 68 | recordings. 69 | 70 | The MockHttpClient can be switched from replay mode to record mode by 71 | setting the real_client member to an instance of an HttpClient which will 72 | make real HTTP requests and store the server's response in list of 73 | recordings. 74 | 75 | Args: 76 | headers: dict containing HTTP headers which should be included in all 77 | HTTP requests. 78 | recordings: The initial recordings to be used for responses. This list 79 | contains tuples in the form: (MockRequest, MockResponse) 80 | real_client: An HttpClient which will make a real HTTP request. The 81 | response will be converted into a MockResponse and stored in 82 | recordings. 83 | """ 84 | self.recordings = recordings or [] 85 | self.real_client = real_client 86 | self.headers = headers or {} 87 | 88 | def add_response(self, response, operation, url, data=None, headers=None): 89 | """Adds a request-response pair to the recordings list. 90 | 91 | After the recording is added, future matching requests will receive the 92 | response. 93 | 94 | Args: 95 | response: MockResponse 96 | operation: str 97 | url: str 98 | data: str, Currently the data is ignored when looking for matching 99 | requests. 100 | headers: dict of strings: Currently the headers are ignored when 101 | looking for matching requests. 102 | """ 103 | request = MockRequest(operation, url, data=data, headers=headers) 104 | self.recordings.append((request, response)) 105 | 106 | def request(self, operation, url, data=None, headers=None): 107 | """Returns a matching MockResponse from the recordings. 108 | 109 | If the real_client is set, the request will be passed along and the 110 | server's response will be added to the recordings and also returned. 111 | 112 | If there is no match, a NoRecordingFound error will be raised. 113 | """ 114 | if self.real_client is None: 115 | if isinstance(url, (str, unicode)): 116 | url = atom.url.parse_url(url) 117 | for recording in self.recordings: 118 | if recording[0].operation == operation and recording[0].url == url: 119 | return recording[1] 120 | raise NoRecordingFound('No recodings found for %s %s' % ( 121 | operation, url)) 122 | else: 123 | # There is a real HTTP client, so make the request, and record the 124 | # response. 125 | response = self.real_client.request(operation, url, data=data, 126 | headers=headers) 127 | # TODO: copy the headers 128 | stored_response = MockResponse(body=response, status=response.status, 129 | reason=response.reason) 130 | self.add_response(stored_response, operation, url, data=data, 131 | headers=headers) 132 | return stored_response 133 | -------------------------------------------------------------------------------- /intercom/gdata/apps/migration/service.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2008 Google. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """Contains the methods to import mail via Google Apps Email Migration API. 18 | 19 | MigrationService: Provides methids to import mail. 20 | """ 21 | 22 | __author__ = 'google-apps-apis@googlegroups.com' 23 | 24 | 25 | import base64 26 | import gdata 27 | import gdata.apps.service 28 | import gdata.service 29 | from gdata.apps import migration 30 | 31 | 32 | API_VER = '2.0' 33 | 34 | 35 | class MigrationService(gdata.apps.service.AppsService): 36 | """Client for the EMAPI migration service. Use either ImportMail to import 37 | one message at a time, or AddBatchEntry and SubmitBatch to import a batch of 38 | messages at a time. 39 | """ 40 | def __init__(self, email=None, password=None, domain=None, source=None, 41 | server='apps-apis.google.com', additional_headers=None): 42 | gdata.apps.service.AppsService.__init__( 43 | self, email=email, password=password, domain=domain, source=source, 44 | server=server, additional_headers=additional_headers) 45 | self.mail_batch = migration.BatchMailEventFeed() 46 | 47 | def _BaseURL(self): 48 | return '/a/feeds/migration/%s/%s' % (API_VER, self.domain) 49 | 50 | def ImportMail(self, user_name, mail_message, mail_item_properties, 51 | mail_labels): 52 | """Import a single mail message. 53 | 54 | Args: 55 | user_name: The username to import messages to. 56 | mail_message: An RFC822 format email message. 57 | mail_item_properties: A list of Gmail properties to apply to the message. 58 | mail_labels: A list of labels to apply to the message. 59 | 60 | Returns: 61 | A MailEntry representing the successfully imported message. 62 | 63 | Raises: 64 | AppsForYourDomainException: An error occurred importing the message. 65 | """ 66 | uri = '%s/%s/mail' % (self._BaseURL(), user_name) 67 | 68 | mail_entry = migration.MailEntry() 69 | mail_entry.rfc822_msg = migration.Rfc822Msg(text=(base64.b64encode( 70 | mail_message))) 71 | mail_entry.rfc822_msg.encoding = 'base64' 72 | mail_entry.mail_item_property = map( 73 | lambda x: migration.MailItemProperty(value=x), mail_item_properties) 74 | mail_entry.label = map(lambda x: migration.Label(label_name=x), 75 | mail_labels) 76 | 77 | try: 78 | return migration.MailEntryFromString(str(self.Post(mail_entry, uri))) 79 | except gdata.service.RequestError, e: 80 | raise gdata.apps.service.AppsForYourDomainException(e.args[0]) 81 | 82 | def AddBatchEntry(self, mail_message, mail_item_properties, 83 | mail_labels): 84 | """Add a message to the current batch that you later will submit. 85 | 86 | Args: 87 | mail_message: An RFC822 format email message. 88 | mail_item_properties: A list of Gmail properties to apply to the message. 89 | mail_labels: A list of labels to apply to the message. 90 | 91 | Returns: 92 | The length of the MailEntry representing the message. 93 | """ 94 | mail_entry = migration.BatchMailEntry() 95 | mail_entry.rfc822_msg = migration.Rfc822Msg(text=(base64.b64encode( 96 | mail_message))) 97 | mail_entry.rfc822_msg.encoding = 'base64' 98 | mail_entry.mail_item_property = map( 99 | lambda x: migration.MailItemProperty(value=x), mail_item_properties) 100 | mail_entry.label = map(lambda x: migration.Label(label_name=x), 101 | mail_labels) 102 | 103 | self.mail_batch.AddBatchEntry(mail_entry) 104 | 105 | return len(str(mail_entry)) 106 | 107 | def SubmitBatch(self, user_name): 108 | """Send a all the mail items you have added to the batch to the server. 109 | 110 | Args: 111 | user_name: The username to import messages to. 112 | 113 | Returns: 114 | A HTTPResponse from the web service call. 115 | 116 | Raises: 117 | AppsForYourDomainException: An error occurred importing the batch. 118 | """ 119 | uri = '%s/%s/mail/batch' % (self._BaseURL(), user_name) 120 | 121 | try: 122 | self.result = self.Post(self.mail_batch, uri, 123 | converter=migration.BatchMailEventFeedFromString) 124 | except gdata.service.RequestError, e: 125 | raise gdata.apps.service.AppsForYourDomainException(e.args[0]) 126 | 127 | self.mail_batch = migration.BatchMailEventFeed() 128 | 129 | return self.result 130 | -------------------------------------------------------------------------------- /intercom/gdata/codesearch/service.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (c) 2007 Benoit Chesneau 4 | # 5 | # Permission to use, copy, modify, and distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | 18 | """CodesearchService extends GDataService to streamline Google Codesearch 19 | operations""" 20 | 21 | 22 | __author__ = 'Benoit Chesneau' 23 | 24 | 25 | import atom 26 | import gdata.service 27 | import gdata.codesearch 28 | 29 | 30 | class CodesearchService(gdata.service.GDataService): 31 | """Client extension for Google codesearch service""" 32 | ssl = True 33 | 34 | def __init__(self, email=None, password=None, source=None, 35 | server='www.google.com', additional_headers=None, **kwargs): 36 | """Creates a client for the Google codesearch service. 37 | 38 | Args: 39 | email: string (optional) The user's email address, used for 40 | authentication. 41 | password: string (optional) The user's password. 42 | source: string (optional) The name of the user's application. 43 | server: string (optional) The name of the server to which a connection 44 | will be opened. Default value: 'www.google.com'. 45 | **kwargs: The other parameters to pass to gdata.service.GDataService 46 | constructor. 47 | """ 48 | gdata.service.GDataService.__init__( 49 | self, email=email, password=password, service='codesearch', 50 | source=source, server=server, additional_headers=additional_headers, 51 | **kwargs) 52 | 53 | def Query(self, uri, converter=gdata.codesearch.CodesearchFeedFromString): 54 | """Queries the Codesearch feed and returns the resulting feed of 55 | entries. 56 | 57 | Args: 58 | uri: string The full URI to be queried. This can contain query 59 | parameters, a hostname, or simply the relative path to a Document 60 | List feed. The DocumentQuery object is useful when constructing 61 | query parameters. 62 | converter: func (optional) A function which will be executed on the 63 | retrieved item, generally to render it into a Python object. 64 | By default the CodesearchFeedFromString function is used to 65 | return a CodesearchFeed object. This is because most feed 66 | queries will result in a feed and not a single entry. 67 | 68 | Returns : 69 | A CodesearchFeed objects representing the feed returned by the server 70 | """ 71 | return self.Get(uri, converter=converter) 72 | 73 | def GetSnippetsFeed(self, text_query=None): 74 | """Retrieve Codesearch feed for a keyword 75 | 76 | Args: 77 | text_query : string (optional) The contents of the q query parameter. This 78 | string is URL escaped upon conversion to a URI. 79 | Returns: 80 | A CodesearchFeed objects representing the feed returned by the server 81 | """ 82 | 83 | query=gdata.codesearch.service.CodesearchQuery(text_query=text_query) 84 | feed = self.Query(query.ToUri()) 85 | return feed 86 | 87 | 88 | class CodesearchQuery(gdata.service.Query): 89 | """Object used to construct the query to the Google Codesearch feed. here only as a shorcut""" 90 | 91 | def __init__(self, feed='/codesearch/feeds/search', text_query=None, 92 | params=None, categories=None): 93 | """Constructor for Codesearch Query. 94 | 95 | Args: 96 | feed: string (optional) The path for the feed. (e.g. '/codesearch/feeds/search') 97 | text_query: string (optional) The contents of the q query parameter. This 98 | string is URL escaped upon conversion to a URI. 99 | params: dict (optional) Parameter value string pairs which become URL 100 | params when translated to a URI. These parameters are added to 101 | the query's items. 102 | categories: list (optional) List of category strings which should be 103 | included as query categories. See gdata.service.Query for 104 | additional documentation. 105 | 106 | Yelds: 107 | A CodesearchQuery object to construct a URI based on Codesearch feed 108 | """ 109 | 110 | gdata.service.Query.__init__(self, feed, text_query, params, categories) 111 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/integration/SMTP_TLS.py: -------------------------------------------------------------------------------- 1 | """TLS Lite + smtplib.""" 2 | 3 | from smtplib import SMTP 4 | from gdata.tlslite.TLSConnection import TLSConnection 5 | from gdata.tlslite.integration.ClientHelper import ClientHelper 6 | 7 | class SMTP_TLS(SMTP): 8 | """This class extends L{smtplib.SMTP} with TLS support.""" 9 | 10 | def starttls(self, 11 | username=None, password=None, sharedKey=None, 12 | certChain=None, privateKey=None, 13 | cryptoID=None, protocol=None, 14 | x509Fingerprint=None, 15 | x509TrustList=None, x509CommonName=None, 16 | settings=None): 17 | """Puts the connection to the SMTP server into TLS mode. 18 | 19 | If the server supports TLS, this will encrypt the rest of the SMTP 20 | session. 21 | 22 | For client authentication, use one of these argument 23 | combinations: 24 | - username, password (SRP) 25 | - username, sharedKey (shared-key) 26 | - certChain, privateKey (certificate) 27 | 28 | For server authentication, you can either rely on the 29 | implicit mutual authentication performed by SRP or 30 | shared-keys, or you can do certificate-based server 31 | authentication with one of these argument combinations: 32 | - cryptoID[, protocol] (requires cryptoIDlib) 33 | - x509Fingerprint 34 | - x509TrustList[, x509CommonName] (requires cryptlib_py) 35 | 36 | Certificate-based server authentication is compatible with 37 | SRP or certificate-based client authentication. It is 38 | not compatible with shared-keys. 39 | 40 | The caller should be prepared to handle TLS-specific 41 | exceptions. See the client handshake functions in 42 | L{tlslite.TLSConnection.TLSConnection} for details on which 43 | exceptions might be raised. 44 | 45 | @type username: str 46 | @param username: SRP or shared-key username. Requires the 47 | 'password' or 'sharedKey' argument. 48 | 49 | @type password: str 50 | @param password: SRP password for mutual authentication. 51 | Requires the 'username' argument. 52 | 53 | @type sharedKey: str 54 | @param sharedKey: Shared key for mutual authentication. 55 | Requires the 'username' argument. 56 | 57 | @type certChain: L{tlslite.X509CertChain.X509CertChain} or 58 | L{cryptoIDlib.CertChain.CertChain} 59 | @param certChain: Certificate chain for client authentication. 60 | Requires the 'privateKey' argument. Excludes the SRP or 61 | shared-key related arguments. 62 | 63 | @type privateKey: L{tlslite.utils.RSAKey.RSAKey} 64 | @param privateKey: Private key for client authentication. 65 | Requires the 'certChain' argument. Excludes the SRP or 66 | shared-key related arguments. 67 | 68 | @type cryptoID: str 69 | @param cryptoID: cryptoID for server authentication. Mutually 70 | exclusive with the 'x509...' arguments. 71 | 72 | @type protocol: str 73 | @param protocol: cryptoID protocol URI for server 74 | authentication. Requires the 'cryptoID' argument. 75 | 76 | @type x509Fingerprint: str 77 | @param x509Fingerprint: Hex-encoded X.509 fingerprint for 78 | server authentication. Mutually exclusive with the 'cryptoID' 79 | and 'x509TrustList' arguments. 80 | 81 | @type x509TrustList: list of L{tlslite.X509.X509} 82 | @param x509TrustList: A list of trusted root certificates. The 83 | other party must present a certificate chain which extends to 84 | one of these root certificates. The cryptlib_py module must be 85 | installed to use this parameter. Mutually exclusive with the 86 | 'cryptoID' and 'x509Fingerprint' arguments. 87 | 88 | @type x509CommonName: str 89 | @param x509CommonName: The end-entity certificate's 'CN' field 90 | must match this value. For a web server, this is typically a 91 | server name such as 'www.amazon.com'. Mutually exclusive with 92 | the 'cryptoID' and 'x509Fingerprint' arguments. Requires the 93 | 'x509TrustList' argument. 94 | 95 | @type settings: L{tlslite.HandshakeSettings.HandshakeSettings} 96 | @param settings: Various settings which can be used to control 97 | the ciphersuites, certificate types, and SSL/TLS versions 98 | offered by the client. 99 | """ 100 | (resp, reply) = self.docmd("STARTTLS") 101 | if resp == 220: 102 | helper = ClientHelper( 103 | username, password, sharedKey, 104 | certChain, privateKey, 105 | cryptoID, protocol, 106 | x509Fingerprint, 107 | x509TrustList, x509CommonName, 108 | settings) 109 | conn = TLSConnection(self.sock) 110 | conn.closeSocket = True 111 | helper._handshake(conn) 112 | self.sock = conn 113 | self.file = conn.makefile('rb') 114 | return (resp, reply) 115 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/Session.py: -------------------------------------------------------------------------------- 1 | """Class representing a TLS session.""" 2 | 3 | from utils.compat import * 4 | from mathtls import * 5 | from constants import * 6 | 7 | class Session: 8 | """ 9 | This class represents a TLS session. 10 | 11 | TLS distinguishes between connections and sessions. A new 12 | handshake creates both a connection and a session. Data is 13 | transmitted over the connection. 14 | 15 | The session contains a more permanent record of the handshake. The 16 | session can be inspected to determine handshake results. The 17 | session can also be used to create a new connection through 18 | "session resumption". If the client and server both support this, 19 | they can create a new connection based on an old session without 20 | the overhead of a full handshake. 21 | 22 | The session for a L{tlslite.TLSConnection.TLSConnection} can be 23 | retrieved from the connection's 'session' attribute. 24 | 25 | @type srpUsername: str 26 | @ivar srpUsername: The client's SRP username (or None). 27 | 28 | @type sharedKeyUsername: str 29 | @ivar sharedKeyUsername: The client's shared-key username (or 30 | None). 31 | 32 | @type clientCertChain: L{tlslite.X509CertChain.X509CertChain} or 33 | L{cryptoIDlib.CertChain.CertChain} 34 | @ivar clientCertChain: The client's certificate chain (or None). 35 | 36 | @type serverCertChain: L{tlslite.X509CertChain.X509CertChain} or 37 | L{cryptoIDlib.CertChain.CertChain} 38 | @ivar serverCertChain: The server's certificate chain (or None). 39 | """ 40 | 41 | def __init__(self): 42 | self.masterSecret = createByteArraySequence([]) 43 | self.sessionID = createByteArraySequence([]) 44 | self.cipherSuite = 0 45 | self.srpUsername = None 46 | self.sharedKeyUsername = None 47 | self.clientCertChain = None 48 | self.serverCertChain = None 49 | self.resumable = False 50 | self.sharedKey = False 51 | 52 | def _clone(self): 53 | other = Session() 54 | other.masterSecret = self.masterSecret 55 | other.sessionID = self.sessionID 56 | other.cipherSuite = self.cipherSuite 57 | other.srpUsername = self.srpUsername 58 | other.sharedKeyUsername = self.sharedKeyUsername 59 | other.clientCertChain = self.clientCertChain 60 | other.serverCertChain = self.serverCertChain 61 | other.resumable = self.resumable 62 | other.sharedKey = self.sharedKey 63 | return other 64 | 65 | def _calcMasterSecret(self, version, premasterSecret, clientRandom, 66 | serverRandom): 67 | if version == (3,0): 68 | self.masterSecret = PRF_SSL(premasterSecret, 69 | concatArrays(clientRandom, serverRandom), 48) 70 | elif version in ((3,1), (3,2)): 71 | self.masterSecret = PRF(premasterSecret, "master secret", 72 | concatArrays(clientRandom, serverRandom), 48) 73 | else: 74 | raise AssertionError() 75 | 76 | def valid(self): 77 | """If this session can be used for session resumption. 78 | 79 | @rtype: bool 80 | @return: If this session can be used for session resumption. 81 | """ 82 | return self.resumable or self.sharedKey 83 | 84 | def _setResumable(self, boolean): 85 | #Only let it be set if this isn't a shared key 86 | if not self.sharedKey: 87 | #Only let it be set to True if the sessionID is non-null 88 | if (not boolean) or (boolean and self.sessionID): 89 | self.resumable = boolean 90 | 91 | def getCipherName(self): 92 | """Get the name of the cipher used with this connection. 93 | 94 | @rtype: str 95 | @return: The name of the cipher used with this connection. 96 | Either 'aes128', 'aes256', 'rc4', or '3des'. 97 | """ 98 | if self.cipherSuite in CipherSuite.aes128Suites: 99 | return "aes128" 100 | elif self.cipherSuite in CipherSuite.aes256Suites: 101 | return "aes256" 102 | elif self.cipherSuite in CipherSuite.rc4Suites: 103 | return "rc4" 104 | elif self.cipherSuite in CipherSuite.tripleDESSuites: 105 | return "3des" 106 | else: 107 | return None 108 | 109 | def _createSharedKey(self, sharedKeyUsername, sharedKey): 110 | if len(sharedKeyUsername)>16: 111 | raise ValueError() 112 | if len(sharedKey)>47: 113 | raise ValueError() 114 | 115 | self.sharedKeyUsername = sharedKeyUsername 116 | 117 | self.sessionID = createByteArrayZeros(16) 118 | for x in range(len(sharedKeyUsername)): 119 | self.sessionID[x] = ord(sharedKeyUsername[x]) 120 | 121 | premasterSecret = createByteArrayZeros(48) 122 | sharedKey = chr(len(sharedKey)) + sharedKey 123 | for x in range(48): 124 | premasterSecret[x] = ord(sharedKey[x % len(sharedKey)]) 125 | 126 | self.masterSecret = PRF(premasterSecret, "shared secret", 127 | createByteArraySequence([]), 48) 128 | self.sharedKey = True 129 | return self 130 | 131 | 132 | -------------------------------------------------------------------------------- /intercom/gdata/blogger/data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (C) 2009 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | """Data model classes for parsing and generating XML for the Blogger API.""" 19 | 20 | 21 | __author__ = 'j.s@google.com (Jeff Scudder)' 22 | 23 | 24 | import re 25 | import urlparse 26 | import atom.core 27 | import gdata.data 28 | 29 | 30 | LABEL_SCHEME = 'http://www.blogger.com/atom/ns#' 31 | THR_TEMPLATE = '{http://purl.org/syndication/thread/1.0}%s' 32 | 33 | BLOG_NAME_PATTERN = re.compile('(http://)(\w*)') 34 | BLOG_ID_PATTERN = re.compile('(tag:blogger.com,1999:blog-)(\w*)') 35 | BLOG_ID2_PATTERN = re.compile('tag:blogger.com,1999:user-(\d+)\.blog-(\d+)') 36 | POST_ID_PATTERN = re.compile( 37 | '(tag:blogger.com,1999:blog-)(\w*)(.post-)(\w*)') 38 | PAGE_ID_PATTERN = re.compile( 39 | '(tag:blogger.com,1999:blog-)(\w*)(.page-)(\w*)') 40 | COMMENT_ID_PATTERN = re.compile('.*-(\w*)$') 41 | 42 | 43 | class BloggerEntry(gdata.data.GDEntry): 44 | """Adds convenience methods inherited by all Blogger entries.""" 45 | 46 | def get_blog_id(self): 47 | """Extracts the Blogger id of this blog. 48 | 49 | This method is useful when contructing URLs by hand. The blog id is 50 | often used in blogger operation URLs. This should not be confused with 51 | the id member of a BloggerBlog. The id element is the Atom id XML element. 52 | The blog id which this method returns is a part of the Atom id. 53 | 54 | Returns: 55 | The blog's unique id as a string. 56 | """ 57 | if self.id.text: 58 | match = BLOG_ID_PATTERN.match(self.id.text) 59 | if match: 60 | return match.group(2) 61 | else: 62 | return BLOG_ID2_PATTERN.match(self.id.text).group(2) 63 | return None 64 | 65 | GetBlogId = get_blog_id 66 | 67 | def get_blog_name(self): 68 | """Finds the name of this blog as used in the 'alternate' URL. 69 | 70 | An alternate URL is in the form 'http://blogName.blogspot.com/'. For an 71 | entry representing the above example, this method would return 'blogName'. 72 | 73 | Returns: 74 | The blog's URL name component as a string. 75 | """ 76 | for link in self.link: 77 | if link.rel == 'alternate': 78 | return urlparse.urlparse(link.href)[1].split(".", 1)[0] 79 | return None 80 | 81 | GetBlogName = get_blog_name 82 | 83 | 84 | class Blog(BloggerEntry): 85 | """Represents a blog which belongs to the user.""" 86 | 87 | 88 | class BlogFeed(gdata.data.GDFeed): 89 | entry = [Blog] 90 | 91 | 92 | class BlogPost(BloggerEntry): 93 | """Represents a single post on a blog.""" 94 | 95 | def add_label(self, label): 96 | """Adds a label to the blog post. 97 | 98 | The label is represented by an Atom category element, so this method 99 | is shorthand for appending a new atom.Category object. 100 | 101 | Args: 102 | label: str 103 | """ 104 | self.category.append(atom.data.Category(scheme=LABEL_SCHEME, term=label)) 105 | 106 | AddLabel = add_label 107 | 108 | def get_post_id(self): 109 | """Extracts the postID string from the entry's Atom id. 110 | 111 | Returns: A string of digits which identify this post within the blog. 112 | """ 113 | if self.id.text: 114 | return POST_ID_PATTERN.match(self.id.text).group(4) 115 | return None 116 | 117 | GetPostId = get_post_id 118 | 119 | 120 | class BlogPostFeed(gdata.data.GDFeed): 121 | entry = [BlogPost] 122 | 123 | 124 | class BlogPage(BloggerEntry): 125 | """Represents a single page on a blog.""" 126 | 127 | def get_page_id(self): 128 | """Extracts the pageID string from entry's Atom id. 129 | 130 | Returns: A string of digits which identify this post within the blog. 131 | """ 132 | if self.id.text: 133 | return PAGE_ID_PATTERN.match(self.id.text).group(4) 134 | return None 135 | 136 | GetPageId = get_page_id 137 | 138 | 139 | class BlogPageFeed(gdata.data.GDFeed): 140 | entry = [BlogPage] 141 | 142 | 143 | class InReplyTo(atom.core.XmlElement): 144 | _qname = THR_TEMPLATE % 'in-reply-to' 145 | href = 'href' 146 | ref = 'ref' 147 | source = 'source' 148 | type = 'type' 149 | 150 | 151 | class Comment(BloggerEntry): 152 | """Blog post comment entry in a feed listing comments on a post or blog.""" 153 | in_reply_to = InReplyTo 154 | 155 | def get_comment_id(self): 156 | """Extracts the commentID string from the entry's Atom id. 157 | 158 | Returns: A string of digits which identify this post within the blog. 159 | """ 160 | if self.id.text: 161 | return COMMENT_ID_PATTERN.match(self.id.text).group(1) 162 | return None 163 | 164 | GetCommentId = get_comment_id 165 | 166 | 167 | class CommentFeed(gdata.data.GDFeed): 168 | entry = [Comment] 169 | -------------------------------------------------------------------------------- /intercom/twilio/util.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import hmac 3 | import time 4 | import urllib 5 | from hashlib import sha1 6 | 7 | try: 8 | import jwt 9 | except: 10 | from twilio.contrib import jwt 11 | 12 | 13 | class RequestValidator(object): 14 | 15 | def __init__(self, token): 16 | self.token = token 17 | 18 | def compute_signature(self, uri, params): 19 | """Compute the signature for a given request 20 | 21 | :param uri: full URI that Twilio requested on your server 22 | :param params: post vars that Twilio sent with the request 23 | :param auth: tuple with (account_sid, token) 24 | 25 | :returns: The computed signature 26 | """ 27 | s = uri 28 | if len(params) > 0: 29 | for k, v in sorted(params.items()): 30 | s += k + v 31 | 32 | # compute signature and compare signatures 33 | computed = base64.encodestring(hmac.new(self.token, s, sha1).digest()) 34 | return computed.strip() 35 | 36 | def validate(self, uri, params, signature): 37 | """Validate a request from Twilio 38 | 39 | :param uri: full URI that Twilio requested on your server 40 | :param params: post vars that Twilio sent with the request 41 | :param signature: expexcted signature in HTTP X-Twilio-Signature header 42 | :param auth: tuple with (account_sid, token) 43 | 44 | :returns: True if the request passes validation, False if not 45 | """ 46 | return self.compute_signature(uri, params) == signature 47 | 48 | 49 | class TwilioCapability(object): 50 | """ 51 | A token to control permissions with Twilio Client 52 | 53 | :param string account_sid: the account sid to which this token 54 | is granted access 55 | :param string auth_token: the secret key used to sign the token. 56 | Note, this auth token is not visible to the 57 | user of the token. 58 | 59 | :returns: A new TwilioCapability with zero permissions 60 | """ 61 | 62 | def __init__(self, account_sid, auth_token): 63 | self.account_sid = account_sid 64 | self.auth_token = auth_token 65 | self.capabilities = {} 66 | self.client_name = None 67 | 68 | def payload(self): 69 | """Return the payload for this token.""" 70 | if "outgoing" in self.capabilities and self.client_name is not None: 71 | scope = self.capabilities["outgoing"] 72 | scope.params["clientName"] = self.client_name 73 | 74 | capabilities = self.capabilities.values() 75 | scope_uris = [str(scope_uri) for scope_uri in capabilities] 76 | 77 | return { 78 | "scope": " ".join(scope_uris) 79 | } 80 | 81 | def generate(self, expires=3600): 82 | """Generate a valid JWT token with an expiration date. 83 | 84 | :param int expires: The token lifetime, in seconds. Defaults to 85 | 1 hour (3600) 86 | 87 | """ 88 | payload = self.payload() 89 | payload['iss'] = self.account_sid 90 | payload['exp'] = int(time.time() + expires) 91 | return jwt.encode(payload, self.auth_token, "HS256") 92 | 93 | def allow_client_outgoing(self, application_sid, **kwargs): 94 | """Allow the user of this token to make outgoing connections. 95 | 96 | Keyword arguments are passed to the application. 97 | 98 | :param string application_sid: Application to contact 99 | """ 100 | scope_params = { 101 | "appSid": application_sid, 102 | } 103 | if kwargs: 104 | scope_params["appParams"] = urllib.urlencode(kwargs, doseq=True) 105 | 106 | self.capabilities["outgoing"] = ScopeURI("client", "outgoing", 107 | scope_params) 108 | 109 | def allow_client_incoming(self, client_name): 110 | """If the user of this token should be allowed to accept incoming 111 | connections then configure the TwilioCapability through this method and 112 | specify the client name. 113 | 114 | :param string client_name: Client name to accept calls from 115 | 116 | """ 117 | self.client_name = client_name 118 | self.capabilities["incoming"] = ScopeURI("client", "incoming", { 119 | 'clientName': client_name 120 | }) 121 | 122 | def allow_event_stream(self, **kwargs): 123 | """Allow the user of this token to access their event stream.""" 124 | scope_params = { 125 | "path": "/2010-04-01/Events", 126 | } 127 | if kwargs: 128 | scope_params['params'] = urllib.urlencode(kwargs, doseq=True) 129 | 130 | self.capabilities["events"] = ScopeURI("stream", "subscribe", 131 | scope_params) 132 | 133 | 134 | class ScopeURI(object): 135 | 136 | def __init__(self, service, privilege, params=None): 137 | self.service = service 138 | self.privilege = privilege 139 | self.params = params 140 | 141 | def __str__(self): 142 | params = urllib.urlencode(self.params) if self.params else None 143 | param_string = "?%s" % params if params else '' 144 | return "scope:%s:%s%s" % (self.service, self.privilege, param_string) 145 | -------------------------------------------------------------------------------- /intercom/gdata/tlslite/integration/TLSAsyncDispatcherMixIn.py: -------------------------------------------------------------------------------- 1 | """TLS Lite + asyncore.""" 2 | 3 | 4 | import asyncore 5 | from gdata.tlslite.TLSConnection import TLSConnection 6 | from AsyncStateMachine import AsyncStateMachine 7 | 8 | 9 | class TLSAsyncDispatcherMixIn(AsyncStateMachine): 10 | """This class can be "mixed in" with an 11 | L{asyncore.dispatcher} to add TLS support. 12 | 13 | This class essentially sits between the dispatcher and the select 14 | loop, intercepting events and only calling the dispatcher when 15 | applicable. 16 | 17 | In the case of handle_read(), a read operation will be activated, 18 | and when it completes, the bytes will be placed in a buffer where 19 | the dispatcher can retrieve them by calling recv(), and the 20 | dispatcher's handle_read() will be called. 21 | 22 | In the case of handle_write(), the dispatcher's handle_write() will 23 | be called, and when it calls send(), a write operation will be 24 | activated. 25 | 26 | To use this class, you must combine it with an asyncore.dispatcher, 27 | and pass in a handshake operation with setServerHandshakeOp(). 28 | 29 | Below is an example of using this class with medusa. This class is 30 | mixed in with http_channel to create http_tls_channel. Note: 31 | 1. the mix-in is listed first in the inheritance list 32 | 33 | 2. the input buffer size must be at least 16K, otherwise the 34 | dispatcher might not read all the bytes from the TLS layer, 35 | leaving some bytes in limbo. 36 | 37 | 3. IE seems to have a problem receiving a whole HTTP response in a 38 | single TLS record, so HTML pages containing '\\r\\n\\r\\n' won't 39 | be displayed on IE. 40 | 41 | Add the following text into 'start_medusa.py', in the 'HTTP Server' 42 | section:: 43 | 44 | from tlslite.api import * 45 | s = open("./serverX509Cert.pem").read() 46 | x509 = X509() 47 | x509.parse(s) 48 | certChain = X509CertChain([x509]) 49 | 50 | s = open("./serverX509Key.pem").read() 51 | privateKey = parsePEMKey(s, private=True) 52 | 53 | class http_tls_channel(TLSAsyncDispatcherMixIn, 54 | http_server.http_channel): 55 | ac_in_buffer_size = 16384 56 | 57 | def __init__ (self, server, conn, addr): 58 | http_server.http_channel.__init__(self, server, conn, addr) 59 | TLSAsyncDispatcherMixIn.__init__(self, conn) 60 | self.tlsConnection.ignoreAbruptClose = True 61 | self.setServerHandshakeOp(certChain=certChain, 62 | privateKey=privateKey) 63 | 64 | hs.channel_class = http_tls_channel 65 | 66 | If the TLS layer raises an exception, the exception will be caught 67 | in asyncore.dispatcher, which will call close() on this class. The 68 | TLS layer always closes the TLS connection before raising an 69 | exception, so the close operation will complete right away, causing 70 | asyncore.dispatcher.close() to be called, which closes the socket 71 | and removes this instance from the asyncore loop. 72 | 73 | """ 74 | 75 | 76 | def __init__(self, sock=None): 77 | AsyncStateMachine.__init__(self) 78 | 79 | if sock: 80 | self.tlsConnection = TLSConnection(sock) 81 | 82 | #Calculate the sibling I'm being mixed in with. 83 | #This is necessary since we override functions 84 | #like readable(), handle_read(), etc., but we 85 | #also want to call the sibling's versions. 86 | for cl in self.__class__.__bases__: 87 | if cl != TLSAsyncDispatcherMixIn and cl != AsyncStateMachine: 88 | self.siblingClass = cl 89 | break 90 | else: 91 | raise AssertionError() 92 | 93 | def readable(self): 94 | result = self.wantsReadEvent() 95 | if result != None: 96 | return result 97 | return self.siblingClass.readable(self) 98 | 99 | def writable(self): 100 | result = self.wantsWriteEvent() 101 | if result != None: 102 | return result 103 | return self.siblingClass.writable(self) 104 | 105 | def handle_read(self): 106 | self.inReadEvent() 107 | 108 | def handle_write(self): 109 | self.inWriteEvent() 110 | 111 | def outConnectEvent(self): 112 | self.siblingClass.handle_connect(self) 113 | 114 | def outCloseEvent(self): 115 | asyncore.dispatcher.close(self) 116 | 117 | def outReadEvent(self, readBuffer): 118 | self.readBuffer = readBuffer 119 | self.siblingClass.handle_read(self) 120 | 121 | def outWriteEvent(self): 122 | self.siblingClass.handle_write(self) 123 | 124 | def recv(self, bufferSize=16384): 125 | if bufferSize < 16384 or self.readBuffer == None: 126 | raise AssertionError() 127 | returnValue = self.readBuffer 128 | self.readBuffer = None 129 | return returnValue 130 | 131 | def send(self, writeBuffer): 132 | self.setWriteOp(writeBuffer) 133 | return len(writeBuffer) 134 | 135 | def close(self): 136 | if hasattr(self, "tlsConnection"): 137 | self.setCloseOp() 138 | else: 139 | asyncore.dispatcher.close(self) 140 | -------------------------------------------------------------------------------- /intercom/gdata/codesearch/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (c) 2007 Benoit Chesneau 4 | # 5 | # Permission to use, copy, modify, and distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | 18 | """Contains extensions to Atom objects used by Google Codesearch""" 19 | 20 | __author__ = 'Benoit Chesneau' 21 | 22 | 23 | import atom 24 | import gdata 25 | 26 | 27 | CODESEARCH_NAMESPACE='http://schemas.google.com/codesearch/2006' 28 | CODESEARCH_TEMPLATE='{http://shema.google.com/codesearch/2006}%s' 29 | 30 | 31 | class Match(atom.AtomBase): 32 | """ The Google Codesearch match element """ 33 | _tag = 'match' 34 | _namespace = CODESEARCH_NAMESPACE 35 | _children = atom.AtomBase._children.copy() 36 | _attributes = atom.AtomBase._attributes.copy() 37 | _attributes['lineNumber'] = 'line_number' 38 | _attributes['type'] = 'type' 39 | 40 | def __init__(self, line_number=None, type=None, extension_elements=None, 41 | extension_attributes=None, text=None): 42 | self.text = text 43 | self.type = type 44 | self.line_number = line_number 45 | self.extension_elements = extension_elements or [] 46 | self.extension_attributes = extension_attributes or {} 47 | 48 | 49 | class File(atom.AtomBase): 50 | """ The Google Codesearch file element""" 51 | _tag = 'file' 52 | _namespace = CODESEARCH_NAMESPACE 53 | _children = atom.AtomBase._children.copy() 54 | _attributes = atom.AtomBase._attributes.copy() 55 | _attributes['name'] = 'name' 56 | 57 | def __init__(self, name=None, extension_elements=None, 58 | extension_attributes=None, text=None): 59 | self.text = text 60 | self.name = name 61 | self.extension_elements = extension_elements or [] 62 | self.extension_attributes = extension_attributes or {} 63 | 64 | 65 | class Package(atom.AtomBase): 66 | """ The Google Codesearch package element""" 67 | _tag = 'package' 68 | _namespace = CODESEARCH_NAMESPACE 69 | _children = atom.AtomBase._children.copy() 70 | _attributes = atom.AtomBase._attributes.copy() 71 | _attributes['name'] = 'name' 72 | _attributes['uri'] = 'uri' 73 | 74 | def __init__(self, name=None, uri=None, extension_elements=None, 75 | extension_attributes=None, text=None): 76 | self.text = text 77 | self.name = name 78 | self.uri = uri 79 | self.extension_elements = extension_elements or [] 80 | self.extension_attributes = extension_attributes or {} 81 | 82 | 83 | class CodesearchEntry(gdata.GDataEntry): 84 | """ Google codesearch atom entry""" 85 | _tag = gdata.GDataEntry._tag 86 | _namespace = gdata.GDataEntry._namespace 87 | _children = gdata.GDataEntry._children.copy() 88 | _attributes = gdata.GDataEntry._attributes.copy() 89 | 90 | _children['{%s}file' % CODESEARCH_NAMESPACE] = ('file', File) 91 | _children['{%s}package' % CODESEARCH_NAMESPACE] = ('package', Package) 92 | _children['{%s}match' % CODESEARCH_NAMESPACE] = ('match', [Match]) 93 | 94 | def __init__(self, author=None, category=None, content=None, 95 | atom_id=None, link=None, published=None, 96 | title=None, updated=None, 97 | match=None, 98 | extension_elements=None, extension_attributes=None, text=None): 99 | 100 | gdata.GDataEntry.__init__(self, author=author, category=category, 101 | content=content, atom_id=atom_id, link=link, 102 | published=published, title=title, 103 | updated=updated, text=None) 104 | 105 | self.match = match or [] 106 | 107 | 108 | def CodesearchEntryFromString(xml_string): 109 | """Converts an XML string into a CodesearchEntry object. 110 | 111 | Args: 112 | xml_string: string The XML describing a Codesearch feed entry. 113 | 114 | Returns: 115 | A CodesearchEntry object corresponding to the given XML. 116 | """ 117 | return atom.CreateClassFromXMLString(CodesearchEntry, xml_string) 118 | 119 | 120 | class CodesearchFeed(gdata.GDataFeed): 121 | """feed containing list of Google codesearch Items""" 122 | _tag = gdata.GDataFeed._tag 123 | _namespace = gdata.GDataFeed._namespace 124 | _children = gdata.GDataFeed._children.copy() 125 | _attributes = gdata.GDataFeed._attributes.copy() 126 | _children['{%s}entry' % atom.ATOM_NAMESPACE] = ('entry', [CodesearchEntry]) 127 | 128 | 129 | def CodesearchFeedFromString(xml_string): 130 | """Converts an XML string into a CodesearchFeed object. 131 | Args: 132 | xml_string: string The XML describing a Codesearch feed. 133 | Returns: 134 | A CodeseartchFeed object corresponding to the given XML. 135 | """ 136 | return atom.CreateClassFromXMLString(CodesearchFeed, xml_string) 137 | --------------------------------------------------------------------------------