Browse Source

moved from https://github.com/epsylon/anontwi

psy 5 years ago
parent
commit
2b8f84af49
41 changed files with 20502 additions and 2 deletions
  1. 57 2
      README.md
  2. 455 0
      anontwi/README.md
  3. 37 0
      anontwi/anontwi
  4. 93 0
      anontwi/config.py
  5. 23 0
      anontwi/core/__init__.py
  6. 3399 0
      anontwi/core/certs/cacert.pem
  7. 169 0
      anontwi/core/encrypt.py
  8. 23 0
      anontwi/core/gtk/__init__.py
  9. 70 0
      anontwi/core/gtk/anontwigtk.py
  10. 30 0
      anontwi/core/gtk/config_gtk.py
  11. 22 0
      anontwi/core/gtk/error.py
  12. 1930 0
      anontwi/core/gtk/main.py
  13. BIN
      anontwi/core/gtk/ui/images/anontwi.png
  14. BIN
      anontwi/core/gtk/ui/images/anontwi_ico.png
  15. BIN
      anontwi/core/gtk/ui/images/anontwi_small.png
  16. BIN
      anontwi/core/gtk/ui/images/gnu.png
  17. BIN
      anontwi/core/gtk/ui/images/identi.ca.png
  18. BIN
      anontwi/core/gtk/ui/images/twitter.png
  19. 348 0
      anontwi/core/gtk/ui/wCongrats.xml
  20. 2652 0
      anontwi/core/gtk/ui/wMain.xml
  21. 123 0
      anontwi/core/gtk/ui/wPin.xml
  22. 178 0
      anontwi/core/gtk/ui/wStart.xml
  23. 560 0
      anontwi/core/gtk/ui/wTokens.xml
  24. 93 0
      anontwi/core/gtk/ui/wWelcome.xml
  25. 23 0
      anontwi/core/irc/__init__.py
  26. 459 0
      anontwi/core/irc/bot.py
  27. 2537 0
      anontwi/core/main.py
  28. 870 0
      anontwi/core/oauth2/__init__.py
  29. 18 0
      anontwi/core/oauth2/_version.py
  30. 0 0
      anontwi/core/oauth2/clients/__init__.py
  31. 40 0
      anontwi/core/oauth2/clients/imap.py
  32. 41 0
      anontwi/core/oauth2/clients/smtp.py
  33. 118 0
      anontwi/core/options.py
  34. 77 0
      anontwi/core/shorter.py
  35. 434 0
      anontwi/core/socks.py
  36. 4828 0
      anontwi/core/twitter.py
  37. 524 0
      anontwi/core/wrapper.py
  38. 7 0
      anontwi/docs/AUTHOR
  39. 209 0
      anontwi/docs/COPYING
  40. 50 0
      anontwi/docs/INSTALL
  41. 5 0
      anontwi/docs/THANKS

+ 57 - 2
README.md

@@ -1,3 +1,58 @@
-# anontwi
+===============================================
+AnonTwi (http://anontwi.03c8.net)
+===============================================
+
+FIGHT CENSORSHIP!! being more safe on social networking sites...
+
+                .   :   .            
+            '.   .  :  .   .'        
+         ._   '._.-'''-._.'   _.     
+           '-..'         '..-'       
+        --._ /.==.     .==.\ _.--    
+            ;/_o__\   /_o__\;        
+       -----|`     ) (     `|-----   
+           _: \_) (\_/) (_/ ;_       
+        --'  \  '._.=._.'  /  '--    
+          _.-''.  '._.'  .''-._      
+         '    .''-.(_).-''.    '     
+             '   '  :  '   '.        
+                '   :   '            
+                    '                
+
+AnonTwi provides you:
+
+      + AES + HMAC-SHA1 encryption on Tweets and Direct Messages 
+      + Secure Sockets Layer (SSL) to interact with API
+      + Proxy Socks (for example, to connect to the TOR network)
+      + Random HTTP header values
+      + Send long messages splitted automatically
+      + Automatic decryption of tweet's urls or raw inputs
+      + Backup messages to your disk (max: 3200)
+      + Send fake geolocation places
+      + Remove data and close account (suicide!)
+      + View global Trending Topics
+      + UTF-8 + Unicode support (chinese, arabic, symbols, etc)
+      + Multiplatform: GNU/Linux, MacOS, Win32
+      + Detailed colourful output results
+      + Generate tools and modules
+      + GTK+ interface
+      + An IRC bot slave
+      + [...]
+
+===========
+Contribute:
+===========
+
+        To make donations use the following hashes:
+
+	- Bitcoin: 1Q63KtiLGzXiYA8XkWFPnWo7nKPWFr3nrc
+	- Ecoin: 6enjPY7PZVq9gwXeVCxgJB8frsf4YFNzVp
+
+========
+Contact:
+========
+
+	To report bugs, questions and help, for suggestions or new development tasking forces, you welcome on: 
+    
+      - irc.freenode.net (channel: #AnonTwi)
 
 
-Anontwi is a tool for OAuth2 applications (such as: GNUSocial, Twitter) that provides different layers of encryption, privacy methods and proxy features. 

+ 455 - 0
anontwi/README.md

@@ -0,0 +1,455 @@
+===============================================
+AnonTwi (http://anontwi.03c8.net)
+===============================================
+
+FIGHT CENSORSHIP!! being more safe on social networking sites...
+
+                .   :   .            
+            '.   .  :  .   .'        
+         ._   '._.-'''-._.'   _.     
+           '-..'         '..-'       
+        --._ /.==.     .==.\ _.--    
+            ;/_o__\   /_o__\;        
+       -----|`     ) (     `|-----   
+           _: \_) (\_/) (_/ ;_       
+        --'  \  '._.=._.'  /  '--    
+          _.-''.  '._.'  .''-._      
+         '    .''-.(_).-''.    '     
+             '   '  :  '   '.        
+                '   :   '            
+                    '                
+
+AnonTwi provides you:
+
+      + AES + HMAC-SHA1 encryption on Tweets and Direct Messages 
+      + Secure Sockets Layer (SSL) to interact with API
+      + Proxy Socks (for example, to connect to the TOR network)
+      + Random HTTP header values
+      + Send long messages splitted automatically
+      + Automatic decryption of tweet's urls or raw inputs
+      + Backup messages to your disk (max: 3200)
+      + Send fake geolocation places
+      + Remove data and close account (suicide!)
+      + View global Trending Topics
+      + UTF-8 + Unicode support (chinese, arabic, symbols, etc)
+      + Multiplatform: GNU/Linux, MacOS, Win32
+      + Detailed colourful output results
+      + Generate tools and modules
+      + GTK+ interface
+      + An IRC bot slave
+
+And many other features than you can see detailed below:
+
+======
+INDEX:
+======
+
+ 1) How-To Start
+ 2) Examples
+ 3) Contribute
+ 3) Contact
+
+=============
+How-To Start:
+=============
+
+--------
+Install:
+--------
+Code runs on many platforms. It requires Python and the following libraries:
+
+      - python-crypto   - cryptographic algorithms and protocols for Python
+
+      - python-httplib2 - comprehensive HTTP client library written for Python
+
+      - python-pycurl   - python bindings to libcurl
+
+      - python-glade2   - GTK+ bindings: Glade support 
+
+On Debian-based systems (ex: Ubuntu), run:
+
+      - directly:
+
+              sudo apt-get install python-crypto python-httplib2 python-pycurl python-glade2
+
+      - using setup-tools (http://pypi.python.org/pypi/setuptools):
+
+              easy_install <packages>
+
+On Windows systems, is working (tested!) with:
+
+      - python 2.7      - http://www.python.org/getit/
+      - pycrypto 2.3    - http://www.voidspace.org.uk/downloads/pycrypto-2.3.win32-py2.7.zip
+      - httplib2 0.7.4  - http://httplib2.googlecode.com/files/httplib2-0.7.4.zip
+      - pycurl 7.19.5.1 - http://pycurl.sourceforge.net/download/
+      - pygtk 2.24      - http://www.pygtk.org/downloads.html
+
+      - using setup-tools (http://pypi.python.org/pypi/setuptools):
+
+              easy_install.exe <packages>
+
+
+------------------------
+"Consumer" keys:
+------------------------
+   + To use OAuth you need this tokens: 'consumer key' and 'consumer secret'.
+
+   - Create a third party APP on your profile. 
+
+      + GNU/Social:
+         - Login to your account         
+         - Go to: Settings
+         - Click on: "Register an OAuth client application"
+         - Click on: "Register a new application"
+             * <yoursocialnetwork.net>/settings/oauthapps/new
+
+         - Fill form correctly
+             * Icon: You can use AnonTwi website logo
+             * Name: (ex: AnonTwi)            
+             * Description: (ex: Anontwi -GNU/Social edition-)
+             * Source URL: (ex: http://anontwi.03c8.net)
+             * Organization: (ex: AnonTwi)
+             * Homepage: (ex: http://anontwi.03c8.net)
+
+             * Callback URL: (leave this BLANK)
+             * Type of Application: Desktop
+             * Default access for this application: Read-Write
+
+     + Twitter:
+         - Login to your account         
+         - Go to: https://apps.twitter.com/
+         - Click on: "Create New App"
+             * https://apps.twitter.com/app/new
+
+         - Fill form correctly
+             * Name: (ex: AnonTwi)            
+             * Description: (ex: Anontwi -GNU/Social edition-)
+             * Website: (ex: http://anontwi.03c8.net)
+             * Callback URL: (leave this BLANK)
+
+   - Get your OAuth settings: Click on the name of your new APP connector (ex: AnonTwi)
+   - Open "config.py" (THIS FILE!) with a text editor, and enter tokens (below!)
+
+   - Remember:
+             * If you go to use shell mode, you should generate your tokens with command: --tokens 
+             * For connect using TOR add: --proxy "http://127.0.0.1:8118"
+
+   - Run ./anontwi or python anontwi (To use interface: ./anontwi --gtk)
+
+
+---------------------
+"Token" keys:
+---------------------
+   + To use OAuth you need this tokens: 'token key' and 'token secret'.
+     
+      - Launch: ./anontwi --tokens
+      - Follow the link to read your "PinCode"
+      - Enter your PinCode
+      - After a few seconds, you will reviece a response like this:
+               
+                 "Generating and signing request for an access token
+                  Your Twitter Access Token key: xxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+                  Access Token secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+      
+   + With these tokens, you can start to launch -AnonTwi- commands like this:
+
+       ./anontwi [-m 'text' | -r 'ID' | -d @user | -f @nick | -u @nick] [OPTIONS] 'token key' 'token secret'
+
+   + Remember that you can EXPORT tokens like environment variables to your system, to don't use them every time
+     If you did it, you can start to launch -AnonTwi- commands like this:
+
+       ./anontwi [-m 'text' | -r 'ID' | -d @user | -f @nick | -u @nick] [OPTIONS]
+
+
+=========
+Examples:                                 
+=========
+
+   + To remember:
+
+         - Connections to API are using fake headers automatically
+         - To launch TOR, add this command: --proxy "http://127.0.0.1:8118"
+         - Check if you are doing geolocation in your messages (usually is 'off' by default)
+         - You can generate 'token key' and 'token secret' every time that you need
+         - View output results with colours using parameter: --rgb (better with obscure backgrounds)
+         - Use --gen to generate STRONG PIN/keys (ex: --pin '1Geh0RBm9Cfj82NNhuQyIFFHR8F7fI4q7+7d0a3FrAI=')
+         - Try to add encryption to your life :)
+
+-----------------------------------
+Retrieve you API tokens, using TOR:
+-----------------------------------
+
+        ./anontwi --tokens --proxy "http://127.0.0.1:8118"
+
+----------------------------------------------------
+Generate PIN key for encrypting/decrypting messages:
+----------------------------------------------------
+
+        ./anontwi --gen
+
+PIN key: K7DccSf3QPVxvbux85Tx/VIMkkDkcK+tFzi45YZ5E+g= 
+
+Share this key privately with the recipients of your encrypted messages.
+Don't send this key over insecure channels such as email, SMS, IM or Twitter.
+Use the sneakernet! ;)
+
+----------------------
+Launch GTK+ Interface:
+----------------------
+
+        Enjoy visual mode experience ;)
+
+        ./anontwi --gtk
+
+------------------------
+Launch an IRC bot slave:
+------------------------
+
+        Launch it and you will have a bot slave waiting your orders on IRC.
+
+        ./anontwi --irc='nickname@server:port#channel'
+
+        If you don't put a nickname or a channel, AnonTwi will generate randoms for you :)
+ 
+        ./anontwi --irc='irc.freenode.net:6667'
+
+------------------------
+Short an url, using TOR:
+------------------------
+
+        ./anontwi --short "url" --proxy "http://127.0.0.1:8118"
+
+-----------------------------------
+Send a plain-text tweet, using TOR:
+-----------------------------------
+
+        ./anontwi -m "Hello World" --proxy "http://127.0.0.1:8118" 
+
+------------------------
+Send an encrypted tweet:
+------------------------
+
+        ./anontwi -m "Hello World" --enc --pin "K7DccSf3QPVxvbux85Tx/VIMkkDkcK+tFzi45YZ5E+g="
+
+--------------
+Remove a tweet: 
+---------------
+
+        You need the ID of the tweet that you want to remove.
+
+                 - launch "--tu @your_nick 'num'" to see tweets IDs of your timeline.
+
+        ./anontwi --rm-m "ID"
+
+------------------
+Retweet a message:
+------------------
+
+        You need the ID of the tweet that you want to RT. 
+                
+                 - launch "--tu @nick 'num'" to see tweets IDs of a user.
+ 
+        ./anontwi -r "ID"
+
+-------------------------------------------------
+Send a plain-text DM (Direct Message), using TOR:
+-------------------------------------------------
+
+        ./anontwi -m "See you later" -d "@nick" --proxy "http://127.0.0.1:8118"
+
+---------------------
+Send an encrypted DM:
+---------------------
+
+        ./anontwi -m "See you later" -d "@nick" --enc --pin "K7DccSf3QPVxvbux85Tx/VIMkkDkcK+tFzi45YZ5E+g="
+
+---------------
+Remove a DM:
+---------------
+
+        You need the ID of the DM that you want to remove.
+
+                 - launch "--td 'num'" to see Direct Messages IDs of your account.
+
+        ./anontwi --rm-d "ID"
+
+--------------------------------------
+Send a media message, using TOR:
+--------------------------------------
+
+        Twitter will show your media links. For example, if you put a link to an image
+
+        ./anontwi -m "https://host/path/file.jpg" --proxy "http://127.0.0.1:8118"
+
+----------------------------------------
+Send reply in a conversation, using TOR:
+----------------------------------------
+
+        You need the ID of the message of the conversation.
+
+                 - launch "--tu @nick 'num'" to see tweets IDs of a user timeline.
+                 - launch "--tf 'num'" to see tweets IDs of your 'home'.
+
+        Add names of users that participates on conversation at start of your message.
+
+        ./anontwi -m "@user1 @user2 text" --reply "ID" --proxy "http://127.0.0.1:8118"
+
+---------------------------------
+Send a friend request, using TOR:
+---------------------------------
+
+        ./anontwi -f "@nick" --proxy "http://127.0.0.1:8118"
+
+----------------------------------
+Stop to follow a user, using TOR:
+----------------------------------
+
+        ./anontwi -u "@nick" --proxy "http://127.0.0.1:8118"
+
+----------------------------------
+Create a favorite, using TOR:
+----------------------------------
+
+        ./anontwi --fav "ID" --proxy "http://127.0.0.1:8118"
+
+----------------------------------
+Destroy favorite, using TOR:
+----------------------------------
+
+        ./anontwi --unfav "ID" --proxy "http://127.0.0.1:8118"
+
+------------------------
+Block a user, using TOR:
+------------------------
+
+        ./anontwi --block "@nick" --proxy "http://127.0.0.1:8118"
+
+--------------------------
+Unblock a user, using TOR:
+--------------------------
+
+        ./anontwi --unblock "@nick" --proxy "http://127.0.0.1:8118"
+
+-----------------------------------------
+Show a number of recent tweets of a user:
+-----------------------------------------
+
+        You can control number of tweets to be reported. For example, 10 most recent tweets is like this:
+
+        ./anontwi --tu "@nick 10"
+
+-------------------------------------------------------
+Show a number of recent tweets of your 'home' timeline:
+-------------------------------------------------------
+
+        You can control number of tweets to be reported. For example, 10 most recent tweets is like this:
+
+        ./anontwi --tf "10"
+
+-------------------------------------------------------
+Show a number of recent favorites
+-------------------------------------------------------
+
+        You can control number of tweets to be reported. For example, 10 most recent tweets is like this:
+
+        ./anontwi --tfav "@nick 10"
+
+----------------------------------
+Split a long message into "waves":
+----------------------------------
+
+        Very usefull if you want to send long messages. 
+        It uses Twitter restrictions as much efficient as possible. 
+        Encryption is allowed :)
+       
+        ./anontwi -m "this is a very long message with more than 140 characters..." --waves
+
+----------------------------------
+Send fake geolocation coordenates:
+----------------------------------
+
+        If you dont put any (--gps), coordenates will be random :)
+        
+        ./anontwi -m "text" --gps "(-43.5209),146.6015"
+
+-------------------------------------------------
+Show a number of Direct Messages of your account:
+-------------------------------------------------
+
+        You can control number of DMs to be reported. For example, 5 most recent DMs is like this:
+
+        ./anontwi --td "5"
+
+-------------------------------------------
+Returns global Trending Topics, using TOR:
+-------------------------------------------
+
+        ./anontwi --tt --proxy "http://127.0.0.1:8118"
+
+-------------------------------------------
+Returns last mentions about you, using TOR:
+-------------------------------------------
+
+	You can control number of tweets to be reported. For example last recent tweet:
+
+        ./anontwi --me "1" --proxy "http://127.0.0.1:8118"
+
+---------------------------------------------
+Decrypt a tweet directly from URL, using TOR:
+---------------------------------------------
+        
+        Remeber, to decrypt, you need the PIN/Key that another user has used to encrypt the message (symmetric keys)
+        To decrypt you don't need 'token key' and 'token secret' :)
+
+        ./anontwi --dec "http://twitter.com/encrypted_message_path" --pin "K7DccSf3QPVxvbux85Tx/VIMkkDkcK+tFzi45YZ5E+g=" --proxy "http://127.0.0.1:8118" 
+
+----------------------------------------
+Decrypt a tweet directly from raw input:
+----------------------------------------
+
+        Remeber, to decrypt, you need the PIN/Key that another user has used to encrypt the message (symmetric keys)
+        To decrypt you don't need 'token key' and 'token secret' :)
+ 
+        ./anontwi --dec "7asNGpFFDKQl7ku9om9CQfEKDq1ablUW+srgaFiEMa+YK0no8pXsx8pR" --pin "K7DccSf3QPVxvbux85Tx/VIMkkDkcK+tFzi45YZ5E+g="
+
+----------------------------------------------------------
+Save tweets starting from the last (max: 3200), using Tor:
+----------------------------------------------------------
+
+	You can control number of tweets to be reported. For example last 1000 tweets:
+
+	./anontwi --save "1000" --proxy "http://127.0.0.1:8118"
+
+-------------------------------------------------
+Save favorites starting from the last, using Tor:
+-------------------------------------------------
+
+	You can control number of tweets to be reported. For example last 100 tweets:
+
+	./anontwi --sfav "@nick 100" --proxy "http://127.0.0.1:8118"
+
+-------------------
+Suicide, using TOR:
+-------------------
+
+        This will try to delete your tweets, your DMs and if is possible, your account.
+
+        ./anontwi --suicide --proxy "http://127.0.0.1:8118"
+
+===========
+Contribute:
+===========
+
+        To make donations use the following hashes:
+
+	- Bitcoin: 1Q63KtiLGzXiYA8XkWFPnWo7nKPWFr3nrc
+	- Ecoin: 6enjPY7PZVq9gwXeVCxgJB8frsf4YFNzVp
+
+========
+Contact:
+========
+
+	To report bugs, questions and help, for suggestions or new development tasking forces, you welcome on: 
+    
+      - irc.freenode.net (channel: #AnonTwi)
+

+ 37 - 0
anontwi/anontwi

@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-"
+# vim: set expandtab tabstop=4 shiftwidth=4:
+"""
+$Id$
+
+This file is part of the anontwi project, http://anontwi.03c8.net
+
+Copyright (c) 2011/2012/2013/2014/2015 by psy <epsylon@riseup.net>
+
+anontwi is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation version 3 of the License.
+
+anontwi is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+details.
+
+You should have received a copy of the GNU General Public License along
+with anontwi; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+from core.main import anontwi
+
+class NullOutput(object):
+    def write(self, text):
+        pass
+    def flush(self):
+        pass
+
+if __name__ == "__main__":
+    app = anontwi()
+    options = app.create_options()
+    if options:
+        app.set_options(options)
+        app.run()

+ 93 - 0
anontwi/config.py

@@ -0,0 +1,93 @@
+#!/usr/bin/env python 
+"""
+$Id$
+
+This file is part of the anontwi project, http://anontwi.03c8.net
+
+Copyright (c) 2012/2013/2014/2015 by psy <epsylon@riseup.net>
+
+anontwi is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation version 3 of the License.
+
+anontwi is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+details.
+
+You should have received a copy of the GNU General Public License along
+with anontwi; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+# This file contains your API tokens and secrets for AnonTwi
+# Remember that you can bridge data across different social networking sites to evade tracking.
+
+# ex: HOME->Tor->IRC->GNUSocial->Twitter->Facebook..
+
+#   - Create a third party APP on your profile. 
+
+#      + GNU/Social:
+#         - Login to your account         
+#         - Go to: Settings
+#         - Click on: "Register an OAuth client application"
+#         - Click on: "Register a new application"
+#             * <yoursocialnetwork.net>/settings/oauthapps/new
+
+#         - Fill form correctly
+#             * Icon: You can use AnonTwi website logo
+#             * Name: (ex: AnonTwi)            
+#             * Description: (ex: Anontwi -GNU/Social edition-)
+#             * Source URL: (ex: http://anontwi.03c8.net)
+#             * Organization: (ex: AnonTwi)
+#             * Homepage: (ex: http://anontwi.03c8.net)
+
+#             * Callback URL: (leave this BLANK)
+#             * Type of Application: Desktop
+#             * Default access for this application: Read-Write
+
+#      + Twitter:
+#         - Login to your account         
+#         - Go to: https://apps.twitter.com/
+#         - Click on: "Create New App"
+#             * https://apps.twitter.com/app/new
+
+#         - Fill form correctly
+#             * Name: (ex: AnonTwi)            
+#             * Description: (ex: Anontwi -GNU/Social edition-)
+#             * Website: (ex: http://anontwi.03c8.net)
+#             * Callback URL: (leave this BLANK)
+
+#   - Get your OAuth settings: Click on the name of your new APP connector (ex: AnonTwi)
+#   - Open "config.py" (THIS FILE!) with a text editor, and enter tokens (below!)
+
+#   - Remember:
+#             * If you go to use shell mode, you should generate your tokens with command: --tokens 
+#             * For connect using TOR add: --proxy "http://127.0.0.1:8118"
+
+#   - Run ./anontwi or python anontwi (To use interface: ./anontwi --gtk)
+
+from core.gtk.config_gtk import *
+
+#"""GTK Environment"""
+try:
+    token = open(DIR_TOKENS + FILE_CONS_TKN).readlines()
+        
+    APItokens = [{'consumer_key': token[0].strip(),
+                      'consumer_secret' : token[1].strip()}]
+
+    api = open(DIR_TOKENS + FILE_SOURCE_API).readlines()
+    APIsources = [{'source_api' : api[0].strip()}]
+
+except:
+    """Non GTK"""
+    APItokens = [
+		{
+                  'consumer_key'    : "", # enter your consumer_key
+                  'consumer_secret' : "", # enter your consumer_secret
+		}
+	    ]
+    APIsources = [
+                {
+                  'source_api' : "", # enter your source API: <yoursocialnetwork.net>/api
+                }
+            ]

+ 23 - 0
anontwi/core/__init__.py

@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-"
+# vim: set expandtab tabstop=4 shiftwidth=4:
+"""
+$Id$
+
+This file is part of the anontwi project, http://anontwi.03c8.net
+
+Copyright (c) 2012/2013/2014/2015 by psy <epsylon@riseup.net>
+
+anontwi is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation version 3 of the License.
+
+anontwi is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+details.
+
+You should have received a copy of the GNU General Public License along
+with anontwi; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""

File diff suppressed because it is too large
+ 3399 - 0
anontwi/core/certs/cacert.pem


+ 169 - 0
anontwi/core/encrypt.py

@@ -0,0 +1,169 @@
+#!/usr/bin/env python
+# -*- coding: iso-8859-15 -*-
+"""
+$Id$
+
+This file is part of the anontwi project, http://anontwi.03c8.net
+
+Copyright (c) 2012/2013/2014/2015 by psy <epsylon@riseup.net>
+
+anontwi is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation version 3 of the License.
+
+anontwi is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+details.
+
+You should have received a copy of the GNU General Public License along
+with anontwi; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""
+################################################################### 
+# See https://en.wikipedia.org/wiki/HMAC#Implementation
+# Example written by: michael@briarproject.org
+###################################################################
+
+# Constants for AES256 and HMAC-SHA1
+KEY_SIZE = 32
+BLOCK_SIZE = 16
+MAC_SIZE = 20
+
+from os import urandom
+from hashlib import sha1, sha256
+from Crypto.Cipher import AES
+from base64 import b64encode, b64decode
+
+trans_5C = "".join([chr (x ^ 0x5c) for x in xrange(256)])
+trans_36 = "".join([chr (x ^ 0x36) for x in xrange(256)])
+
+def hmac_sha1(key, msg):
+    if len(key) > 20:
+        key = sha1(key).digest()
+    key += chr(0) * (20 - len(key))
+    o_key_pad = key.translate(trans_5C)
+    i_key_pad = key.translate(trans_36)
+    return sha1(o_key_pad + sha1(i_key_pad + msg).digest()).digest()
+
+def derive_keys(key):
+    h = sha256()
+    h.update(key)
+    h.update('cipher')
+    cipher_key = h.digest()
+    h = sha256()
+    h.update(key)
+    h.update('mac')
+    mac_key = h.digest()
+    return (cipher_key, mac_key)
+
+def generate_key():
+    return b64encode(urandom(KEY_SIZE))
+
+class Cipher(object):
+    """
+    Cipher class
+    """
+    def __init__(self, key="", text=""):
+        """
+        Init 
+        """
+        self.block_size = 16
+        self.mac_size = 20
+        self.key = self.set_key(key)
+        self.text = self.set_text(text)
+        self.mode = AES.MODE_CFB
+  
+    def set_key(self, key):
+        """
+        Set key
+        """
+        # Base64 decode the key
+        try:
+            key = b64decode(key)
+        except TypeError:
+            raise ValueError
+        # The key must be the expected length
+        if len(key) != KEY_SIZE:
+            raise ValueError
+        self.key = key
+        return self.key
+
+    def set_text(self, text):
+        """
+        Set text
+        """
+        self.text = text 
+        return self.text
+
+    def encrypt(self):
+        """
+        Encrypt text
+        """
+        # The IV, ciphertext and MAC can't be more than 105 bytes
+        if BLOCK_SIZE + len(self.text) + MAC_SIZE > 105:
+            self.text = self.text[:105 - BLOCK_SIZE - MAC_SIZE]
+        # Derive the cipher and MAC keys
+        (cipher_key, mac_key) = derive_keys(self.key)
+        # Generate a random IV
+        iv = urandom(BLOCK_SIZE)
+	# Encrypt the plaintext
+        aes = AES.new(cipher_key, self.mode, iv)
+        ciphertext = aes.encrypt(self.text)
+        # Calculate the MAC over the IV and the ciphertext
+        mac = hmac_sha1(mac_key, iv + ciphertext)
+        # Base64 encode the IV, ciphertext and MAC
+        return b64encode(iv + ciphertext + mac)
+
+    def decrypt(self):
+        """
+        Decrypt text
+        """
+        # Base64 decode
+        try:
+            iv_ciphertext_mac = b64decode(self.text)
+        except TypeError:
+            return None
+        # Separate the IV, ciphertext and MAC
+        iv = iv_ciphertext_mac[:BLOCK_SIZE]
+        ciphertext = iv_ciphertext_mac[BLOCK_SIZE:-MAC_SIZE]
+        mac = iv_ciphertext_mac[-MAC_SIZE:]
+        # Derive the cipher and MAC keys
+        (cipher_key, mac_key) = derive_keys(self.key)
+        # Calculate the expected MAC
+        expected_mac = hmac_sha1(mac_key, iv + ciphertext)
+        # Check the MAC
+        if mac != expected_mac:
+            return None
+        # Decrypt the ciphertext
+        aes = AES.new(cipher_key, self.mode, iv)
+        return aes.decrypt(ciphertext)
+
+if __name__ == "__main__":
+    key = generate_key()
+    print 'Key:', key
+    # Encrypt and decrypt a short message
+    text = 'Hello world!'
+    c = Cipher(key, text)
+    msg = c.encrypt()
+    c.set_text(msg)
+    print '\nCiphertext:', msg
+    print 'Length:', len(msg)
+    print 'Plaintext:', c.decrypt()
+    # Encrypt and decrypt a long message
+    text = 'Gosh this is a long message, far too long to fit in a tweet I dare say, especially when you consider the encryption overhead'
+    c = Cipher(key, text)
+    msg = c.encrypt()
+    c.set_text(msg)
+    print '\nCiphertext:', msg
+    print 'Length:', len(msg)
+    print 'Plaintext:', c.decrypt()
+    # Check that modifying the message invalidates the MAC
+    text = 'Hello world!'
+    c = Cipher(key, text)
+    msg = c.encrypt()
+    msg = msg[:16] + msg[17] + msg[16] + msg[18:]
+    c.set_text(msg)
+    print '\nCiphertext:', msg
+    print 'Length:', len(msg)
+    print 'Plaintext:', c.decrypt()

+ 23 - 0
anontwi/core/gtk/__init__.py

@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-"
+# vim: set expandtab tabstop=4 shiftwidth=4:
+"""
+$Id$
+
+This file is part of the anontwi project, http://anontwi.03c8.net
+
+Copyright (c) 2012/2013/2014/2015 by psy <epsylon@riseup.net>
+
+cintruder is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation version 3 of the License.
+
+cintruder is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+details.
+
+You should have received a copy of the GNU General Public License along
+with cintruder; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""

+ 70 - 0
anontwi/core/gtk/anontwigtk.py

@@ -0,0 +1,70 @@
+#!/usr/bin/python
+# -*- coding: utf8 -*-
+"""
+Copyright (C) 2012 Jhonny5 <jhonny5@riseup.net>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+#import os, sys
+#import shutil #for remove directory tree
+import logging
+
+#from optparse import OptionParser
+
+from core.gtk.main import GuiWelcome, GuiUtils, GuiStarter
+from core.wrapper import WrapperAnontwi
+from core.gtk.config_gtk import *
+""" 
+for windows:
+if sys.platform == 'win32':
+   os.environ['PATH'] += ";lib;"
+else:
+"""
+#gtk libraries import
+try:
+    import pygtk
+    pygtk.require("2.0")
+except:
+    print ("PyGkt not found.")
+try:
+    import gtk, gtk.glade
+except:
+    print ("Gkt / Glade  not found")
+    #sys.exit(1)
+#print ("Gtk / GLade found.")
+
+#LOG_LEVEL = logging.DEBUG
+LOG_LEVEL = logging.INFO
+
+class AnontwiGTK():
+    @staticmethod
+    def run():
+        logging.basicConfig(level=LOG_LEVEL) 
+        logging.debug('Running Program')
+        log = logging.getLogger('GTK') 
+        
+        wrapper = WrapperAnontwi()
+
+        # is first time that program runs ? show assistant : run MainWindow
+        if not wrapper.get_consumer_tokens() \
+            or not wrapper.get_access_tokens():
+            log.debug('Running Assistant')
+            GuiWelcome()
+            gtk.main()         
+
+        log.debug('Running Starter GUI')
+        GuiStarter()
+        gtk.main()
+
+

+ 30 - 0
anontwi/core/gtk/config_gtk.py

@@ -0,0 +1,30 @@
+#!/usr/bin/python
+# -*- coding: utf8 -*-
+"""
+Copyright (C) 2012 Jhonny5 <jhonny5@riseup.net>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+import os, sys
+
+PATH_APP = os.path.dirname(os.path.abspath(__file__))
+DIR_GTK = '/ui/'
+DIR_GTK_IMG = '/ui/images/'
+
+DIR_HOME_ANON = os.getenv('HOME') + '/.anontwi-gtk'
+DIR_TOKENS = DIR_HOME_ANON + '/tokens/'
+FILE_CONS_TKN = 'cons_tokens.key'
+FILE_ACC_TKN = 'acc_tokens.key'	
+FILE_SOURCE_API = 'source_api'
+sys.path.append(PATH_APP + '/anontwi/')

+ 22 - 0
anontwi/core/gtk/error.py

@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+# -*- coding: utf8 -*-
+"""
+Copyright (C) 2012 Jhonny5 <jhonny5@riseup.net>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+class AnontwiError(Exception):
+    @property
+    def message(self):
+        return self.arg[0]

File diff suppressed because it is too large
+ 1930 - 0
anontwi/core/gtk/main.py


BIN
anontwi/core/gtk/ui/images/anontwi.png


BIN
anontwi/core/gtk/ui/images/anontwi_ico.png


BIN
anontwi/core/gtk/ui/images/anontwi_small.png


BIN
anontwi/core/gtk/ui/images/gnu.png


BIN
anontwi/core/gtk/ui/images/identi.ca.png


BIN
anontwi/core/gtk/ui/images/twitter.png


+ 348 - 0
anontwi/core/gtk/ui/wCongrats.xml

@@ -0,0 +1,348 @@
+<?xml version="1.0"?>
+<interface>
+  <!-- glade-interface-naming-policy project-wide -->
+  <object class="GtkWindow" id="wCongrats">
+    <property name="window_position">center</property>
+    <property name="default_width">1024</property>
+    <property name="default_height">768</property>
+    <child>
+      <object class="GtkVBox" id="vbox1">
+        <property name="visible">True</property>
+        <child>
+          <object class="GtkImage" id="iAnontwi">
+            <property name="visible">True</property>
+            <property name="pixbuf">images/anontwi_small.png</property>
+          </object>
+          <packing>
+            <property name="padding">27</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label1">
+            <property name="visible">True</property>
+            <property name="label" translatable="yes">Congratulations! 
+Your Anontwi is ready!
+
+Find your keys here:</property>
+            <attributes>
+              <attribute name="weight" value="bold"/>
+            </attributes>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkVBox" id="vbox2">
+            <property name="visible">True</property>
+            <child>
+              <object class="GtkLabel" id="lPathTokens">
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkVBox" id="vbox3">
+                <child>
+                  <object class="GtkLabel" id="label4">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">You may encrypt your tokens with GPG. Then, Anontwi will ask you
+for the password every time you start the glade-interface.
+
+If so, insert here two times your password, and click Encrypt.
+
+If not, keep safe your files! Tokens will be stored as plain text!!</property>
+                  </object>
+                  <packing>
+                    <property name="padding">10</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHBox" id="hbox3">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkFixed" id="fixed5">
+                        <property name="visible">True</property>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkHBox" id="hbox4">
+                        <property name="visible">True</property>
+                        <child>
+                          <object class="GtkVBox" id="vbox4">
+                            <property name="visible">True</property>
+                            <child>
+                              <object class="GtkHBox" id="hbox5">
+                                <property name="visible">True</property>
+                                <child>
+                                  <object class="GtkLabel" id="label5">
+                                    <property name="width_request">128</property>
+                                    <property name="visible">True</property>
+                                    <property name="label" translatable="yes">Password</property>
+                                  </object>
+                                  <packing>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkEntry" id="tbPass1">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="invisible_char">&#x25CF;</property>
+                                    <property name="invisible_char_set">True</property>
+                                    <property name="primary_icon_sensitive">True</property>
+                                    <property name="secondary_icon_sensitive">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkHBox" id="hbox6">
+                                <property name="visible">True</property>
+                                <child>
+                                  <object class="GtkLabel" id="label6">
+                                    <property name="visible">True</property>
+                                    <property name="label" translatable="yes">Re-enter Password</property>
+                                  </object>
+                                  <packing>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkEntry" id="tbPass2">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="invisible_char">&#x25CF;</property>
+                                    <property name="invisible_char_set">True</property>
+                                    <property name="primary_icon_sensitive">True</property>
+                                    <property name="secondary_icon_sensitive">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkVBox" id="vbox5">
+                            <property name="visible">True</property>
+                            <child>
+                              <object class="GtkFixed" id="fixed4">
+                                <property name="visible">True</property>
+                              </object>
+                              <packing>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkButton" id="bEncrypt">
+                                <property name="label" translatable="yes">Encrypt!</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                              </object>
+                              <packing>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="padding">9</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkFixed" id="fixed6">
+                        <property name="visible">True</property>
+                      </object>
+                      <packing>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkVBox" id="vbox6">
+                <property name="visible">True</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkLabel" id="label7">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">To finish the configuration process and begin your visual experience you MUST RESTART AnonTwi using: --gtk</property>
+                  </object>
+                  <packing>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="padding">30</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkFixed" id="fixed3">
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="padding">64</property>
+                <property name="position">3</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label2">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Please report feedback or bugs to:</property>
+              </object>
+              <packing>
+                <property name="position">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHBox" id="hbox7">
+                <property name="visible">True</property>
+                <child>
+                  <object class="GtkFixed" id="fixed7">
+                    <property name="visible">True</property>
+                  </object>
+                  <packing>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLinkButton" id="linkbutton1">
+                    <property name="label" translatable="yes">#Anontwi - Freenode IRC</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="relief">none</property>
+                    <property name="uri">http://webchat.freenode.net/?channels=#anontwi</property>
+                  </object>
+                  <packing>
+                    <property name="padding">6</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkFixed" id="fixed8">
+                    <property name="visible">True</property>
+                  </object>
+                  <packing>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="position">5</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHBox" id="hbox2">
+                <property name="visible">True</property>
+                <child>
+                  <object class="GtkFixed" id="fixed2">
+                    <property name="visible">True</property>
+                  </object>
+                  <packing>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkFixed" id="fixed1">
+                    <property name="width_request">209</property>
+                    <property name="visible">True</property>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label3">
+                    <property name="visible">True</property>
+                    <property name="xalign">0.80000001192092896</property>
+                    <property name="label" translatable="yes">Anontwi-GTK+ Core: v1.1b GPLv3 
+</property>
+                    <attributes>
+                      <attribute name="foreground" value="#400040004000"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="position">6</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkHBox" id="hbox1">
+            <property name="visible">True</property>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <object class="GtkButton" id="bFinish">
+                <property name="label" translatable="yes">Finish</property>
+                <property name="width_request">615</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+              </object>
+              <packing>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">3</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>

File diff suppressed because it is too large
+ 2652 - 0
anontwi/core/gtk/ui/wMain.xml


+ 123 - 0
anontwi/core/gtk/ui/wPin.xml

@@ -0,0 +1,123 @@
+<?xml version="1.0"?>
+<interface>
+  <!-- glade-interface-naming-policy project-wide -->
+  <object class="GtkWindow" id="wPin">
+    <property name="window_position">center</property>
+    <property name="default_width">1024</property>
+    <property name="default_height">768</property>
+    <child>
+      <object class="GtkVBox" id="vbox1">
+        <property name="visible">True</property>
+        <child>
+          <object class="GtkImage" id="image1">
+            <property name="visible">True</property>
+            <property name="pixbuf">images/anontwi_small.png</property>
+          </object>
+          <packing>
+            <property name="padding">20</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkVBox" id="vbox2">
+            <property name="height_request">219</property>
+            <property name="visible">True</property>
+            <child>
+              <object class="GtkLabel" id="label1">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Now, follow this link to read your "PinCode" and insert it bellow.</property>
+              </object>
+              <packing>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLinkButton" id="lbPin">
+                <property name="label" translatable="yes">button</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="has_tooltip">True</property>
+                <property name="relief">none</property>
+                <property name="yalign">0.56999999284744263</property>
+                <property name="uri">http://glade.gnome.org</property>
+              </object>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHBox" id="hbox1">
+                <property name="visible">True</property>
+                <child>
+                  <object class="GtkLabel" id="label2">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">PinCode:</property>
+                  </object>
+                  <packing>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEntry" id="tbPin">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="invisible_char">&#x2022;</property>
+                    <property name="primary_icon_sensitive">True</property>
+                    <property name="secondary_icon_sensitive">True</property>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkFixed" id="fixed2">
+                    <property name="visible">True</property>
+                  </object>
+                  <packing>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="padding">2</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkHBox" id="hbox2">
+            <property name="visible">True</property>
+            <child>
+              <object class="GtkFixed" id="fixed1">
+                <property name="width_request">327</property>
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="bFinish">
+                <property name="label" translatable="yes">Finish</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+              </object>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">2</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>

+ 178 - 0
anontwi/core/gtk/ui/wStart.xml

@@ -0,0 +1,178 @@
+<?xml version="1.0"?>
+<interface>
+  <!-- glade-interface-naming-policy project-wide -->
+  <object class="GtkWindow" id="wStart">
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="window_position">center</property>
+    <child>
+      <object class="GtkVBox" id="vbox1">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkImage" id="iAnontwi">
+            <property name="visible">True</property>
+            <property name="tooltip_text" translatable="yes">http://anontwi.03c8.net</property>
+            <property name="stock">gtk-missing-image</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="padding">5</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkHBox" id="hbox3">
+            <property name="visible">True</property>
+            <child>
+              <object class="GtkCheckButton" id="cProxy">
+                <property name="label" translatable="yes">Use Proxy</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="tooltip_text" translatable="yes">Use a proxy. By default, tor.</property>
+                <property name="draw_indicator">True</property>
+                <signal handler="on_cProxy_toggled" name="toggled"/>
+              </object>
+              <packing>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="padding">5</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkHBox" id="hProxy">
+            <property name="homogeneous">True</property>
+            <child>
+              <object class="GtkVBox" id="vbox3">
+                <property name="visible">True</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkHBox" id="hbox5">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkLabel" id="label2">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Server:</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="padding">5</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkEntry" id="eServer">
+                        <property name="width_request">140</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="invisible_char">&#x25CF;</property>
+                        <property name="text" translatable="yes">http://127.0.0.1</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="padding">5</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="padding">5</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHBox" id="hbox6">
+                    <property name="visible">True</property>
+                    <property name="homogeneous">True</property>
+                    <child>
+                      <object class="GtkLabel" id="label3">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Port:</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="padding">5</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkEntry" id="ePort">
+                        <property name="width_request">93</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="invisible_char">&#x25CF;</property>
+                        <property name="text" translatable="yes">8118</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="padding">5</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="padding">5</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="padding">5</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkHBox" id="hbox4">
+            <property name="visible">True</property>
+            <child>
+              <object class="GtkButton" id="bConnect">
+                <property name="label" translatable="yes">Connect!</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+              </object>
+              <packing>
+                <property name="fill">False</property>
+                <property name="padding">5</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="padding">10</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+  <object class="GtkTextBuffer" id="textbuffer1"/>
+  <object class="GtkAction" id="action1"/>
+</interface>

+ 560 - 0
anontwi/core/gtk/ui/wTokens.xml

@@ -0,0 +1,560 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy toplevel-contextual -->
+  <object class="GtkWindow" id="wTokens">
+    <property name="window_position">center</property>
+    <property name="default_width">1024</property>
+    <property name="default_height">768</property>
+    <child>
+      <object class="GtkVBox" id="vbox1">
+        <property name="visible">True</property>
+        <child>
+          <object class="GtkLabel" id="label1">
+            <property name="visible">True</property>
+            <property name="label" translatable="yes">
+
+First of all, you need to create a third party APP in your social network account.
+
+  * To remember:
+
+     - You can use a proxy (tor: http://127.0.0.1:8118).
+     - You must change Access properties to: Read, Write and Access direct messages.</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="padding">6</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkVBox" id="vbox2">
+            <property name="visible">True</property>
+            <property name="orientation">vertical</property>
+            <child>
+              <object class="GtkHSeparator" id="hseparator1">
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="padding">5</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHBox" id="hbox10">
+                <property name="visible">True</property>
+                <child>
+                  <object class="GtkVBox" id="vbox5">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <object class="GtkHBox" id="hbox11">
+                        <property name="visible">True</property>
+                        <property name="orientation">vertical</property>
+                        <property name="homogeneous">True</property>
+                        <child>
+                          <object class="GtkImage" id="image2">
+                            <property name="visible">True</property>
+                            <property name="pixbuf">images/twitter.png</property>
+                          </object>
+                          <packing>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkRadioButton" id="rTwitter">
+                            <property name="label" translatable="yes">Twitter</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="tooltip_text" translatable="yes">Connect to https://twitter.com</property>
+                            <property name="draw_indicator">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLinkButton" id="linkbutton1">
+                        <property name="label" translatable="yes">https://dev.twitter.com/apps/new</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="relief">half</property>
+                        <property name="focus_on_click">False</property>
+                        <property name="uri">https://dev.twitter.com/apps/new</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkVBox" id="vbox6">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <object class="GtkHBox" id="hbox12">
+                        <property name="visible">True</property>
+                        <property name="orientation">vertical</property>
+                        <property name="homogeneous">True</property>
+                        <child>
+                          <object class="GtkImage" id="image1">
+                            <property name="visible">True</property>
+                            <property name="pixbuf">images/gnu.png</property>
+                          </object>
+                          <packing>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkRadioButton" id="rGNU">
+                            <property name="label" translatable="yes">GNUSocial</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="tooltip_text" translatable="yes">Connect to GNUSocial based net</property>
+                            <property name="active">True</property>
+                            <property name="draw_indicator">True</property>
+                            <property name="group">rTwitter</property>
+                            <signal name="toggled" handler="on_rGNU_toggled"/>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkEntry" id="tbGNUurl">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="invisible_char">&#x25CF;</property>
+                            <property name="text" translatable="yes">your server name</property>
+                          </object>
+                          <packing>
+                            <property name="position">2</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <placeholder/>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLinkButton" id="lbGNU">
+                        <property name="label" translatable="yes">http://yourserver/settings/oauthconnections</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="relief">half</property>
+                        <property name="focus_on_click">False</property>
+                        <property name="uri">http://yourservername/settings/oauthconnections</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkVBox" id="vbox7">
+                <property name="visible">True</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkHBox" id="hbox1">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkLabel" id="label3">
+                        <property name="width_request">200</property>
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Consumer Key:</property>
+                        <property name="justify">right</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="padding">10</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkEntry" id="tbConsumerKey">
+                        <property name="width_request">200</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="invisible_char">&#x25CF;</property>
+                        <property name="primary_icon_sensitive">True</property>
+                        <property name="secondary_icon_sensitive">True</property>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="padding">5</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHBox" id="hbox2">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkLabel" id="label4">
+                        <property name="width_request">200</property>
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Consumer Secret:</property>
+                        <property name="justify">right</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="padding">10</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkEntry" id="tbConsumerSecret">
+                        <property name="width_request">200</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="invisible_char">&#x25CF;</property>
+                        <property name="primary_icon_sensitive">True</property>
+                        <property name="secondary_icon_sensitive">True</property>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="padding">5</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <object class="GtkHBox" id="hbox6">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkLabel" id="label6">
+                        <property name="width_request">200</property>
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Access Token:</property>
+                        <property name="justify">right</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="padding">10</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkEntry" id="tbAccessToken">
+                        <property name="width_request">200</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="editable">False</property>
+                        <property name="invisible_char">&#x25CF;</property>
+                        <property name="primary_icon_sensitive">True</property>
+                        <property name="secondary_icon_sensitive">True</property>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="padding">5</property>
+                    <property name="position">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHBox" id="hbox7">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkLabel" id="label7">
+                        <property name="width_request">200</property>
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Access Token Secret:</property>
+                        <property name="justify">right</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="padding">10</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkEntry" id="tbSecretToken">
+                        <property name="width_request">200</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="editable">False</property>
+                        <property name="invisible_char">&#x25CF;</property>
+                        <property name="primary_icon_sensitive">True</property>
+                        <property name="secondary_icon_sensitive">True</property>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="padding">5</property>
+                    <property name="position">4</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHBox" id="hbox9">
+                    <property name="visible">True</property>
+                    <property name="homogeneous">True</property>
+                    <child>
+                      <object class="GtkCheckButton" id="chkTor">
+                        <property name="label" translatable="yes">Active proxy (default: tor):</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="xalign">0</property>
+                        <property name="draw_indicator">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="padding">10</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkHBox" id="hbTor">
+                        <property name="visible">True</property>
+                        <child>
+                          <object class="GtkLabel" id="label9">
+                            <property name="visible">True</property>
+                            <property name="label" translatable="yes">IP Address</property>
+                          </object>
+                          <packing>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkEntry" id="tbIPAddress">
+                            <property name="width_request">160</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="invisible_char">&#x2022;</property>
+                            <property name="text" translatable="yes">http://127.0.0.1</property>
+                            <property name="invisible_char_set">True</property>
+                            <property name="primary_icon_sensitive">True</property>
+                            <property name="secondary_icon_sensitive">True</property>
+                          </object>
+                          <packing>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="label10">
+                            <property name="visible">True</property>
+                            <property name="label" translatable="yes">Port</property>
+                          </object>
+                          <packing>
+                            <property name="position">2</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkEntry" id="tbPort">
+                            <property name="width_request">100</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="invisible_char">&#x2022;</property>
+                            <property name="text" translatable="yes">8118</property>
+                            <property name="invisible_char_set">True</property>
+                            <property name="primary_icon_sensitive">True</property>
+                            <property name="secondary_icon_sensitive">True</property>
+                          </object>
+                          <packing>
+                            <property name="position">3</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="position">5</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHSeparator" id="hseparator2">
+                    <property name="visible">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="padding">10</property>
+                    <property name="position">6</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHBox" id="hbox5">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkLinkButton" id="lkbUrl">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="relief">none</property>
+                        <property name="yalign">0.56000000238418579</property>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="bGetUrl">
+                        <property name="label" translatable="yes">Get Url</property>
+                        <property name="height_request">75</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="padding">10</property>
+                    <property name="position">7</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkVBox" id="vbox8">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <object class="GtkHBox" id="hbox4">
+                        <property name="visible">True</property>
+                        <child>
+                          <object class="GtkLabel" id="label5">
+                            <property name="visible">True</property>
+                            <property name="label" translatable="yes">PinCode:</property>
+                          </object>
+                          <packing>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkEntry" id="tbPin">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="invisible_char">&#x25CF;</property>
+                            <property name="primary_icon_sensitive">True</property>
+                            <property name="secondary_icon_sensitive">True</property>
+                          </object>
+                          <packing>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkButton" id="bInsertPin">
+                            <property name="label" translatable="yes">Insert PinCode</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">True</property>
+                            <signal name="clicked" handler="on_bInsertPin_clicked"/>
+                          </object>
+                          <packing>
+                            <property name="padding">16</property>
+                            <property name="position">2</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="padding">8</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkHSeparator" id="hseparator3">
+                        <property name="visible">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="padding">10</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="position">8</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="padding">15</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton" id="bNext">
+            <property name="label" translatable="yes">Next</property>
+            <property name="height_request">100</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkHBox" id="hbox3">
+            <property name="visible">True</property>
+          </object>
+          <packing>
+            <property name="position">3</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>

+ 93 - 0
anontwi/core/gtk/ui/wWelcome.xml

@@ -0,0 +1,93 @@
+<?xml version="1.0"?>
+<interface>
+  <!-- glade-interface-naming-policy project-wide -->
+  <object class="GtkAction" id="action1"/>
+  <object class="GtkWindow" id="wWelcome">
+    <property name="window_position">center</property>
+    <property name="default_width">1024</property>
+    <property name="default_height">768</property>
+    <child>
+      <object class="GtkVBox" id="vbox1">
+        <property name="visible">True</property>
+        <child>
+          <object class="GtkImage" id="iAnontwi">
+            <property name="visible">True</property>
+            <property name="pixbuf">images/anontwi_small.png</property>
+          </object>
+          <packing>
+            <property name="padding">10</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label2">
+            <property name="visible">True</property>
+            <property name="label" translatable="yes">Welcome to AnonTwi GTK+ Interface!
+
+Is time to configure it...</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLinkButton" id="linkbutton1">
+            <property name="label" translatable="yes">http://anontwi.03c8.net</property>
+            <property name="width_request">100</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <property name="has_tooltip">True</property>
+            <property name="relief">half</property>
+            <property name="uri">http://anontwi.03c8.net</property>
+          </object>
+          <packing>
+            <property name="fill">False</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label1">
+            <property name="visible">True</property>
+            <property name="label" translatable="yes">Features working:
+                                                                                 
+      + AES + HMAC-SHA1 encryption on Public/Private Messages
+      + Secure Sockets Layer (SSL) to interact with API
+      + Proxy Socks (for example, to connect to the TOR network)
+      + Random HTTP header values
+      + Send long messages splitted automatically
+      + Automatic decryption of tweet's urls or raw inputs
+      + Backup messages to your disk
+      + Send fake geolocation places
+      + Remove data and close account (suicide)
+      + View global Trending Topics
+      + UTF-8 + Unicode support (chinese, arabic, symbols, etc)
+      + Multiplatform: GNU/Linux, MacOS, Win32
+      + [....]
+
+Enjoy your new private network! :D</property>
+          </object>
+          <packing>
+            <property name="position">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton" id="bNext">
+            <property name="label" translatable="yes">Next</property>
+            <property name="height_request">100</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">4</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>

+ 23 - 0
anontwi/core/irc/__init__.py

@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-"
+# vim: set expandtab tabstop=4 shiftwidth=4:
+"""
+$Id$
+
+This file is part of the anontwi project, http://anontwi.03c8.net
+
+Copyright (c) 2012/2013/2014/2015 by psy <epsylon@riseup.net>
+
+cintruder is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation version 3 of the License.
+
+cintruder is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+details.
+
+You should have received a copy of the GNU General Public License along
+with cintruder; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+"""

File diff suppressed because it is too large
+ 459 - 0
anontwi/core/irc/bot.py


File diff suppressed because it is too large
+ 2537 - 0
anontwi/core/main.py


+ 870 - 0
anontwi/core/oauth2/__init__.py

@@ -0,0 +1,870 @@
+"""
+The MIT License
+
+Copyright (c) 2007-2010 Leah Culver, Joe Stump, Mark Paschal, Vic Fryzel
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+"""
+
+import base64
+import urllib
+import time
+import random
+import urlparse
+import hmac
+import binascii
+import httplib2
+
+try:
+    from urlparse import parse_qs
+    parse_qs # placate pyflakes
+except ImportError:
+    # fall back for Python 2.5
+    from cgi import parse_qs
+
+try:
+    from hashlib import sha1
+    sha = sha1
+except ImportError:
+    # hashlib was added in Python 2.5
+    import sha
+
+import _version
+
+__version__ = _version.__version__
+
+OAUTH_VERSION = '1.0'  # Hi Blaine!
+HTTP_METHOD = 'GET'
+SIGNATURE_METHOD = 'PLAINTEXT'
+
+
+class Error(RuntimeError):
+    """Generic exception class."""
+
+    def __init__(self, message='OAuth error occurred.'):
+        self._message = message
+
+    @property
+    def message(self):
+        """A hack to get around the deprecation errors in 2.6."""
+        return self._message
+
+    def __str__(self):
+        return self._message
+
+
+class MissingSignature(Error):
+    pass
+
+
+def build_authenticate_header(realm=''):
+    """Optional WWW-Authenticate header (401 error)"""
+    return {'WWW-Authenticate': 'OAuth realm="%s"' % realm}
+
+
+def build_xoauth_string(url, consumer, token=None):
+    """Build an XOAUTH string for use in SMTP/IMPA authentication."""
+    request = Request.from_consumer_and_token(consumer, token,
+        "GET", url)
+
+    signing_method = SignatureMethod_HMAC_SHA1()
+    request.sign_request(signing_method, consumer, token)
+
+    params = []
+    for k, v in sorted(request.iteritems()):
+        if v is not None:
+            params.append('%s="%s"' % (k, escape(v)))
+
+    return "%s %s %s" % ("GET", url, ','.join(params))
+
+
+def to_unicode(s):
+    """ Convert to unicode, raise exception with instructive error
+    message if s is not unicode, ascii, or utf-8. """
+    if not isinstance(s, unicode):
+        if not isinstance(s, str):
+            raise TypeError('You are required to pass either unicode or string here, not: %r (%s)' % (type(s), s))
+        try:
+            s = s.decode('utf-8')
+        except UnicodeDecodeError, le:
+            raise TypeError('You are required to pass either a unicode object or a utf-8 string here. You passed a Python string object which contained non-utf-8: %r. The UnicodeDecodeError that resulted from attempting to interpret it as utf-8 was: %s' % (s, le,))
+    return s
+
+def to_utf8(s):
+    return to_unicode(s).encode('utf-8')
+
+def to_unicode_if_string(s):
+    if isinstance(s, basestring):
+        return to_unicode(s)
+    else:
+        return s
+
+def to_utf8_if_string(s):
+    if isinstance(s, basestring):
+        return to_utf8(s)
+    else:
+        return s
+
+def to_unicode_optional_iterator(x):
+    """
+    Raise TypeError if x is a str containing non-utf8 bytes or if x is
+    an iterable which contains such a str.
+    """
+    if isinstance(x, basestring):
+        return to_unicode(x)
+
+    try:
+        l = list(x)
+    except TypeError, e:
+        assert 'is not iterable' in str(e)
+        return x
+    else:
+        return [ to_unicode(e) for e in l ]
+
+def to_utf8_optional_iterator(x):
+    """
+    Raise TypeError if x is a str or if x is an iterable which
+    contains a str.
+    """
+    if isinstance(x, basestring):
+        return to_utf8(x)
+
+    try:
+        l = list(x)
+    except TypeError, e:
+        assert 'is not iterable' in str(e)
+        return x
+    else:
+        return [ to_utf8_if_string(e) for e in l ]
+
+def escape(s):
+    """Escape a URL including any /."""
+    return urllib.quote(s.encode('utf-8'), safe='~')
+
+def generate_timestamp():
+    """Get seconds since epoch (UTC)."""
+    return int(time.time())
+
+
+def generate_nonce(length=8):
+    """Generate pseudorandom number."""
+    return ''.join([str(random.randint(0, 9)) for i in range(length)])
+
+
+def generate_verifier(length=8):
+    """Generate pseudorandom number."""
+    return ''.join([str(random.randint(0, 9)) for i in range(length)])
+
+
+class Consumer(object):
+    """A consumer of OAuth-protected services.
+ 
+    The OAuth consumer is a "third-party" service that wants to access
+    protected resources from an OAuth service provider on behalf of an end
+    user. It's kind of the OAuth client.
+ 
+    Usually a consumer must be registered with the service provider by the
+    developer of the consumer software. As part of that process, the service
+    provider gives the consumer a *key* and a *secret* with which the consumer
+    software can identify itself to the service. The consumer will include its
+    key in each request to identify itself, but will use its secret only when
+    signing requests, to prove that the request is from that particular
+    registered consumer.
+ 
+    Once registered, the consumer can then use its consumer credentials to ask
+    the service provider for a request token, kicking off the OAuth
+    authorization process.
+    """
+
+    key = None
+    secret = None
+
+    def __init__(self, key, secret):
+        self.key = key
+        self.secret = secret
+
+        if self.key is None or self.secret is None:
+            raise ValueError("Key and secret must be set.")
+
+    def __str__(self):
+        data = {'oauth_consumer_key': self.key,
+            'oauth_consumer_secret': self.secret}
+
+        return urllib.urlencode(data)
+
+
+class Token(object):
+    """An OAuth credential used to request authorization or a protected
+    resource.
+ 
+    Tokens in OAuth comprise a *key* and a *secret*. The key is included in
+    requests to identify the token being used, but the secret is used only in
+    the signature, to prove that the requester is who the server gave the
+    token to.
+ 
+    When first negotiating the authorization, the consumer asks for a *request
+    token* that the live user authorizes with the service provider. The
+    consumer then exchanges the request token for an *access token* that can
+    be used to access protected resources.
+    """
+
+    key = None
+    secret = None
+    callback = None
+    callback_confirmed = None
+    verifier = None
+
+    def __init__(self, key, secret):
+        self.key = key
+        self.secret = secret
+
+        if self.key is None or self.secret is None:
+            raise ValueError("Key and secret must be set.")
+
+    def set_callback(self, callback):
+        self.callback = callback
+        self.callback_confirmed = 'true'
+
+    def set_verifier(self, verifier=None):
+        if verifier is not None:
+            self.verifier = verifier
+        else:
+            self.verifier = generate_verifier()
+
+    def get_callback_url(self):
+        if self.callback and self.verifier:
+            # Append the oauth_verifier.
+            parts = urlparse.urlparse(self.callback)
+            scheme, netloc, path, params, query, fragment = parts[:6]
+            if query:
+                query = '%s&oauth_verifier=%s' % (query, self.verifier)
+            else:
+                query = 'oauth_verifier=%s' % self.verifier
+            return urlparse.urlunparse((scheme, netloc, path, params,
+                query, fragment))
+        return self.callback
+
+    def to_string(self):
+        """Returns this token as a plain string, suitable for storage.
+ 
+        The resulting string includes the token's secret, so you should never
+        send or store this string where a third party can read it.
+        """
+
+        data = {
+            'oauth_token': self.key,
+            'oauth_token_secret': self.secret,
+        }
+
+        if self.callback_confirmed is not None:
+            data['oauth_callback_confirmed'] = self.callback_confirmed
+        return urllib.urlencode(data)
+ 
+    @staticmethod
+    def from_string(s):
+        """Deserializes a token from a string like one returned by
+        `to_string()`."""
+
+        if not len(s):
+            raise ValueError("Invalid parameter string.")
+
+        params = parse_qs(s, keep_blank_values=False)
+        if not len(params):
+            raise ValueError("Invalid parameter string.")
+
+        try:
+            key = params['oauth_token'][0]
+        except Exception:
+            raise ValueError("'oauth_token' not found in OAuth request.")
+
+        try:
+            secret = params['oauth_token_secret'][0]
+        except Exception:
+            raise ValueError("'oauth_token_secret' not found in " 
+                "OAuth request.")
+
+        token = Token(key, secret)
+        try:
+            token.callback_confirmed = params['oauth_callback_confirmed'][0]
+        except KeyError:
+            pass  # 1.0, no callback confirmed.
+        return token
+
+    def __str__(self):
+        return self.to_string()
+
+
+def setter(attr):
+    name = attr.__name__
+ 
+    def getter(self):
+        try:
+            return self.__dict__[name]
+        except KeyError:
+            raise AttributeError(name)
+ 
+    def deleter(self):
+        del self.__dict__[name]
+ 
+    return property(getter, attr, deleter)
+
+
+class Request(dict):
+ 
+    """The parameters and information for an HTTP request, suitable for
+    authorizing with OAuth credentials.
+ 
+    When a consumer wants to access a service's protected resources, it does
+    so using a signed HTTP request identifying itself (the consumer) with its
+    key, and providing an access token authorized by the end user to access
+    those resources.
+ 
+    """
+ 
+    version = OAUTH_VERSION
+
+    def __init__(self, method=HTTP_METHOD, url=None, parameters=None,
+                 body='', is_form_encoded=False):
+        if url is not None:
+            self.url = to_unicode(url)
+        self.method = method
+        if parameters is not None:
+            for k, v in parameters.iteritems():
+                k = to_unicode(k)
+                v = to_unicode_optional_iterator(v)
+                self[k] = v
+        self.body = body
+        self.is_form_encoded = is_form_encoded
+
+
+    @setter
+    def url(self, value):
+        self.__dict__['url'] = value
+        if value is not None:
+            scheme, netloc, path, params, query, fragment = urlparse.urlparse(value)
+
+            # Exclude default port numbers.
+            if scheme == 'http' and netloc[-3:] == ':80':
+                netloc = netloc[:-3]
+            elif scheme == 'https' and netloc[-4:] == ':443':
+                netloc = netloc[:-4]
+            if scheme not in ('http', 'https'):
+                raise ValueError("Unsupported URL %s (%s)." % (value, scheme))
+
+            # Normalized URL excludes params, query, and fragment.
+            self.normalized_url = urlparse.urlunparse((scheme, netloc, path, None, None, None))
+        else:
+            self.normalized_url = None
+            self.__dict__['url'] = None
+ 
+    @setter
+    def method(self, value):
+        self.__dict__['method'] = value.upper()
+ 
+    def _get_timestamp_nonce(self):
+        return self['oauth_timestamp'], self['oauth_nonce']
+ 
+    def get_nonoauth_parameters(self):
+        """Get any non-OAuth parameters."""
+        return dict([(k, v) for k, v in self.iteritems() 
+                    if not k.startswith('oauth_')])
+ 
+    def to_header(self, realm=''):
+        """Serialize as a header for an HTTPAuth request."""
+        oauth_params = ((k, v) for k, v in self.items() 
+                            if k.startswith('oauth_'))
+        stringy_params = ((k, escape(str(v))) for k, v in oauth_params)
+        header_params = ('%s="%s"' % (k, v) for k, v in stringy_params)
+        params_header = ', '.join(header_params)
+ 
+        auth_header = 'OAuth realm="%s"' % realm
+        if params_header:
+            auth_header = "%s, %s" % (auth_header, params_header)
+ 
+        return {'Authorization': auth_header}
+ 
+    def to_postdata(self):
+        """Serialize as post data for a POST request."""
+        d = {}
+        for k, v in self.iteritems():
+            d[k.encode('utf-8')] = to_utf8_optional_iterator(v)
+
+        # tell urlencode to deal with sequence values and map them correctly
+        # to resulting querystring. for example self["k"] = ["v1", "v2"] will
+        # result in 'k=v1&k=v2' and not k=%5B%27v1%27%2C+%27v2%27%5D
+        return urllib.urlencode(d, True).replace('+', '%20')
+ 
+    def to_url(self):
+        """Serialize as a URL for a GET request."""
+        base_url = urlparse.urlparse(self.url)
+        try:
+            query = base_url.query
+        except AttributeError:
+            # must be python <2.5
+            query = base_url[4]
+        query = parse_qs(query)
+        for k, v in self.items():
+            query.setdefault(k, []).append(v)
+        
+        try:
+            scheme = base_url.scheme
+            netloc = base_url.netloc
+            path = base_url.path
+            params = base_url.params
+            fragment = base_url.fragment
+        except AttributeError:
+            # must be python <2.5
+            scheme = base_url[0]
+            netloc = base_url[1]
+            path = base_url[2]
+            params = base_url[3]
+            fragment = base_url[5]
+        
+        url = (scheme, netloc, path, params,
+               urllib.urlencode(query, True), fragment)
+        return urlparse.urlunparse(url)
+
+    def get_parameter(self, parameter):
+        ret = self.get(parameter)
+        if ret is None:
+            raise Error('Parameter not found: %s' % parameter)
+
+        return ret
+
+    def get_normalized_parameters(self):
+        """Return a string that contains the parameters that must be signed."""
+        items = []
+        for key, value in self.iteritems():
+            if key == 'oauth_signature':
+                continue
+            # 1.0a/9.1.1 states that kvp must be sorted by key, then by value,
+            # so we unpack sequence values into multiple items for sorting.
+            if isinstance(value, basestring):
+                items.append((to_utf8_if_string(key), to_utf8(value)))
+            else:
+                try:
+                    value = list(value)
+                except TypeError, e:
+                    assert 'is not iterable' in str(e)
+                    items.append((to_utf8_if_string(key), to_utf8_if_string(value)))
+                else:
+                    items.extend((to_utf8_if_string(key), to_utf8_if_string(item)) for item in value)
+
+        # Include any query string parameters from the provided URL
+        query = urlparse.urlparse(self.url)[4]
+
+        url_items = self._split_url_string(query).items()
+        url_items = [(to_utf8(k), to_utf8(v)) for k, v in url_items if k != 'oauth_signature' ]
+        items.extend(url_items)
+
+        items.sort()
+        encoded_str = urllib.urlencode(items)
+        # Encode signature parameters per Oauth Core 1.0 protocol
+        # spec draft 7, section 3.6
+        # (http://tools.ietf.org/html/draft-hammer-oauth-07#section-3.6)
+        # Spaces must be encoded with "%20" instead of "+"
+        return encoded_str.replace('+', '%20').replace('%7E', '~')
+
+    def sign_request(self, signature_method, consumer, token):
+        """Set the signature parameter to the result of sign."""
+
+        if not self.is_form_encoded:
+            # according to
+            # http://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/oauth-bodyhash.html
+            # section 4.1.1 "OAuth Consumers MUST NOT include an
+            # oauth_body_hash parameter on requests with form-encoded
+            # request bodies."
+            self['oauth_body_hash'] = base64.b64encode(sha(self.body).digest())
+
+        if 'oauth_consumer_key' not in self:
+            self['oauth_consumer_key'] = consumer.key
+
+        if token and 'oauth_token' not in self:
+            self['oauth_token'] = token.key
+
+        self['oauth_signature_method'] = signature_method.name
+        self['oauth_signature'] = signature_method.sign(self, consumer, token)
+ 
+    @classmethod
+    def make_timestamp(cls):
+        """Get seconds since epoch (UTC)."""
+        return str(int(time.time()))
+ 
+    @classmethod
+    def make_nonce(cls):
+        """Generate pseudorandom number."""
+        return str(random.randint(0, 100000000))
+ 
+    @classmethod
+    def from_request(cls, http_method, http_url, headers=None, parameters=None,
+            query_string=None):
+        """Combines multiple parameter sources."""
+        if parameters is None:
+            parameters = {}
+ 
+        # Headers
+        if headers and 'Authorization' in headers:
+            auth_header = headers['Authorization']
+            # Check that the authorization header is OAuth.
+            if auth_header[:6] == 'OAuth ':
+                auth_header = auth_header[6:]
+                try:
+                    # Get the parameters from the header.
+                    header_params = cls._split_header(auth_header)
+                    parameters.update(header_params)
+                except:
+                    raise Error('Unable to parse OAuth parameters from '
+                        'Authorization header.')
+ 
+        # GET or POST query string.
+        if query_string:
+            query_params = cls._split_url_string(query_string)
+            parameters.update(query_params)
+ 
+        # URL parameters.
+        param_str = urlparse.urlparse(http_url)[4] # query
+        url_params = cls._split_url_string(param_str)
+        parameters.update(url_params)
+ 
+        if parameters:
+            return cls(http_method, http_url, parameters)
+ 
+        return None
+ 
+    @classmethod
+    def from_consumer_and_token(cls, consumer, token=None,
+            http_method=HTTP_METHOD, http_url=None, parameters=None,
+            body='', is_form_encoded=False):
+        if not parameters:
+            parameters = {}
+ 
+        defaults = {
+            'oauth_consumer_key': consumer.key,
+            'oauth_timestamp': cls.make_timestamp(),
+            'oauth_nonce': cls.make_nonce(),
+            'oauth_version': cls.version,
+        }
+ 
+        defaults.update(parameters)
+        parameters = defaults
+ 
+        if token:
+            parameters['oauth_token'] = token.key
+            if token.verifier:
+                parameters['oauth_verifier'] = token.verifier
+ 
+        return Request(http_method, http_url, parameters, body=body, 
+                       is_form_encoded=is_form_encoded)
+ 
+    @classmethod
+    def from_token_and_callback(cls, token, callback=None, 
+        http_method=HTTP_METHOD, http_url=None, parameters=None):
+
+        if not parameters:
+            parameters = {}
+ 
+        parameters['oauth_token'] = token.key
+ 
+        if callback:
+            parameters['oauth_callback'] = callback
+ 
+        return cls(http_method, http_url, parameters)
+ 
+    @staticmethod
+    def _split_header(header):
+        """Turn Authorization: header into parameters."""
+        params = {}
+        parts = header.split(',')
+        for param in parts:
+            # Ignore realm parameter.
+            if param.find('realm') > -1:
+                continue
+            # Remove whitespace.
+            param = param.strip()
+            # Split key-value.
+            param_parts = param.split('=', 1)
+            # Remove quotes and unescape the value.
+            params[param_parts[0]] = urllib.unquote(param_parts[1].strip('\"'))
+        return params
+ 
+    @staticmethod
+    def _split_url_string(param_str):
+        """Turn URL string into parameters."""
+        parameters = parse_qs(param_str.encode('utf-8'), keep_blank_values=True)
+        for k, v in parameters.iteritems():
+            parameters[k] = urllib.unquote(v[0])
+        return parameters
+
+
+class Client(httplib2.Http):
+    """OAuthClient is a worker to attempt to execute a request."""
+
+    def __init__(self, consumer, token=None, cache=None, timeout=None,
+        proxy_info=None):
+
+        if consumer is not None and not isinstance(consumer, Consumer):
+            raise ValueError("Invalid consumer.")
+
+        if token is not None and not isinstance(token, Token):
+            raise ValueError("Invalid token.")
+
+        self.consumer = consumer
+        self.token = token
+        self.method = SignatureMethod_HMAC_SHA1()
+
+        httplib2.Http.__init__(self, cache=cache, timeout=timeout, proxy_info=proxy_info)
+
+    def set_signature_method(self, method):
+        if not isinstance(method, SignatureMethod):
+            raise ValueError("Invalid signature method.")
+
+        self.method = method
+
+    def request(self, uri, method="GET", body='', headers=None, 
+        redirections=httplib2.DEFAULT_MAX_REDIRECTS, connection_type=None):
+        DEFAULT_POST_CONTENT_TYPE = 'application/x-www-form-urlencoded'
+
+        if not isinstance(headers, dict):
+            headers = {}
+
+        if method == "POST":
+            headers['Content-Type'] = headers.get('Content-Type', 
+                DEFAULT_POST_CONTENT_TYPE)
+
+        is_form_encoded = \
+            headers.get('Content-Type') == 'application/x-www-form-urlencoded'
+
+        if is_form_encoded and body:
+            parameters = parse_qs(body)
+        else:
+            parameters = None
+
+        req = Request.from_consumer_and_token(self.consumer, 
+            token=self.token, http_method=method, http_url=uri, 
+            parameters=parameters, body=body, is_form_encoded=is_form_encoded)
+
+        req.sign_request(self.method, self.consumer, self.token)
+
+        schema, rest = urllib.splittype(uri)
+        if rest.startswith('//'):
+            hierpart = '//'
+        else:
+            hierpart = ''
+        host, rest = urllib.splithost(rest)
+
+        realm = schema + ':' + hierpart + host
+
+        if is_form_encoded:
+            body = req.to_postdata()
+        elif method == "GET":
+            uri = req.to_url()
+        else:
+            headers.update(req.to_header(realm=realm))
+        try:
+            return httplib2.Http.request(self, uri, method=method, body=body,
+            headers=headers, redirections=redirections,
+            connection_type=connection_type)
+
+        except Exception as e:
+            if (type(e[0]) is unicode or type(e[0]) is str) and e[0][0:53] == "Server presented certificate that does not match host":
+                httplib2.Http.disable_ssl_certificate_validation = True
+                return httplib2.Http.request(self, uri, method=method, body=body,
+                    headers=headers, redirections=redirections,
+                    connection_type=connection_type)
+            else:
+                raise Error(e[0])
+
+
+
+class Server(object):
+    """A skeletal implementation of a service provider, providing protected
+    resources to requests from authorized consumers.
+ 
+    This class implements the logic to check requests for authorization. You
+    can use it with your web server or web framework to protect certain
+    resources with OAuth.
+    """
+
+    timestamp_threshold = 300 # In seconds, five minutes.
+    version = OAUTH_VERSION
+    signature_methods = None
+
+    def __init__(self, signature_methods=None):
+        self.signature_methods = signature_methods or {}
+
+    def add_signature_method(self, signature_method):
+        self.signature_methods[signature_method.name] = signature_method
+        return self.signature_methods
+
+    def verify_request(self, request, consumer, token):
+        """Verifies an api call and checks all the parameters."""
+
+        self._check_version(request)
+        self._check_signature(request, consumer, token)
+        parameters = request.get_nonoauth_parameters()
+        return parameters
+
+    def build_authenticate_header(self, realm=''):
+        """Optional support for the authenticate header."""
+        return {'WWW-Authenticate': 'OAuth realm="%s"' % realm}
+
+    def _check_version(self, request):
+        """Verify the correct version of the request for this server."""
+        version = self._get_version(request)
+        if version and version != self.version:
+            raise Error('OAuth version %s not supported.' % str(version))
+
+    def _get_version(self, request):
+        """Return the version of the request for this server."""
+        try:
+            version = request.get_parameter('oauth_version')
+        except:
+            version = OAUTH_VERSION
+
+        return version
+
+    def _get_signature_method(self, request):
+        """Figure out the signature with some defaults."""
+        try:
+            signature_method = request.get_parameter('oauth_signature_method')
+        except:
+            signature_method = SIGNATURE_METHOD
+
+        try:
+            # Get the signature method object.
+            signature_method = self.signature_methods[signature_method]
+        except:
+            signature_method_names = ', '.join(self.signature_methods.keys())
+            raise Error('Signature method %s not supported try one of the following: %s' % (signature_method, signature_method_names))
+
+        return signature_method
+
+    def _get_verifier(self, request):
+        return request.get_parameter('oauth_verifier')
+
+    def _check_signature(self, request, consumer, token):
+        timestamp, nonce = request._get_timestamp_nonce()
+        self._check_timestamp(timestamp)
+        signature_method = self._get_signature_method(request)
+
+        try:
+            signature = request.get_parameter('oauth_signature')
+        except:
+            raise MissingSignature('Missing oauth_signature.')
+
+        # Validate the signature.
+        valid = signature_method.check(request, consumer, token, signature)
+
+        if not valid:
+            key, base = signature_method.signing_base(request, consumer, token)
+
+            raise Error('Invalid signature. Expected signature base ' 
+                'string: %s' % base)
+
+    def _check_timestamp(self, timestamp):
+        """Verify that timestamp is recentish."""
+        timestamp = int(timestamp)
+        now = int(time.time())
+        lapsed = now - timestamp
+        if lapsed > self.timestamp_threshold:
+            raise Error('Expired timestamp: given %d and now %s has a '
+                'greater difference than threshold %d' % (timestamp, now, 
+                    self.timestamp_threshold))
+
+
+class SignatureMethod(object):
+    """A way of signing requests.
+ 
+    The OAuth protocol lets consumers and service providers pick a way to sign
+    requests. This interface shows the methods expected by the other `oauth`
+    modules for signing requests. Subclass it and implement its methods to
+    provide a new way to sign requests.
+    """
+
+    def signing_base(self, request, consumer, token):
+        """Calculates the string that needs to be signed.
+
+        This method returns a 2-tuple containing the starting key for the
+        signing and the message to be signed. The latter may be used in error
+        messages to help clients debug their software.
+
+        """
+        raise NotImplementedError
+
+    def sign(self, request, consumer, token):
+        """Returns the signature for the given request, based on the consumer
+        and token also provided.
+
+        You should use your implementation of `signing_base()` to build the
+        message to sign. Otherwise it may be less useful for debugging.
+
+        """
+        raise NotImplementedError
+
+    def check(self, request, consumer, token, signature):
+        """Returns whether the given signature is the correct signature for
+        the given consumer and token signing the given request."""
+        built = self.sign(request, consumer, token)
+        return built == signature
+
+
+class SignatureMethod_HMAC_SHA1(SignatureMethod):
+    name = 'HMAC-SHA1'
+
+    def signing_base(self, request, consumer, token):
+        if not hasattr(request, 'normalized_url') or request.normalized_url is None:
+            raise ValueError("Base URL for request is not set.")
+
+        sig = (
+            escape(request.method),
+            escape(request.normalized_url),
+            escape(request.get_normalized_parameters()),
+        )
+
+        key = '%s&' % escape(consumer.secret)
+        if token:
+            key += escape(token.secret)
+        raw = '&'.join(sig)
+        return key, raw
+
+    def sign(self, request, consumer, token):
+        """Builds the base signature string."""
+        key, raw = self.signing_base(request, consumer, token)
+
+        hashed = hmac.new(key, raw, sha)
+
+        # Calculate the digest base 64.
+        return binascii.b2a_base64(hashed.digest())[:-1]
+
+
+class SignatureMethod_PLAINTEXT(SignatureMethod):
+
+    name = 'PLAINTEXT'
+
+    def signing_base(self, request, consumer, token):
+        """Concatenates the consumer key and secret with the token's
+        secret."""
+        sig = '%s&' % escape(consumer.secret)
+        if token:
+            sig = sig + escape(token.secret)
+        return sig, sig
+
+    def sign(self, request, consumer, token):
+        key, raw = self.signing_base(request, consumer, token)
+        return raw

+ 18 - 0
anontwi/core/oauth2/_version.py

@@ -0,0 +1,18 @@
+# This is the version of this source code.
+
+manual_verstr = "1.5"
+
+
+
+auto_build_num = "211"
+
+
+
+verstr = manual_verstr + "." + auto_build_num
+try:
+    from pyutil.version_class import Version as pyutil_Version
+    __version__ = pyutil_Version(verstr)
+except (ImportError, ValueError):
+    # Maybe there is no pyutil installed.
+    from distutils.version import LooseVersion as distutils_Version
+    __version__ = distutils_Version(verstr)

+ 0 - 0
anontwi/core/oauth2/clients/__init__.py


+ 40 - 0
anontwi/core/oauth2/clients/imap.py

@@ -0,0 +1,40 @@
+"""
+The MIT License
+
+Copyright (c) 2007-2010 Leah Culver, Joe Stump, Mark Paschal, Vic Fryzel
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+"""
+
+import oauth2
+import imaplib
+
+
+class IMAP4_SSL(imaplib.IMAP4_SSL):
+    """IMAP wrapper for imaplib.IMAP4_SSL that implements XOAUTH."""
+
+    def authenticate(self, url, consumer, token):
+        if consumer is not None and not isinstance(consumer, oauth2.Consumer):
+            raise ValueError("Invalid consumer.")
+
+        if token is not None and not isinstance(token, oauth2.Token):
+            raise ValueError("Invalid token.")
+
+        imaplib.IMAP4_SSL.authenticate(self, 'XOAUTH',
+            lambda x: oauth2.build_xoauth_string(url, consumer, token))

+ 41 - 0
anontwi/core/oauth2/clients/smtp.py

@@ -0,0 +1,41 @@
+"""
+The MIT License
+
+Copyright (c) 2007-2010 Leah Culver, Joe Stump, Mark Paschal, Vic Fryzel
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+"""
+
+import oauth2
+import smtplib
+import base64
+
+
+class SMTP(smtplib.SMTP):
+    """SMTP wrapper for smtplib.SMTP that implements XOAUTH."""
+
+    def authenticate(self, url, consumer, token):
+        if consumer is not None and not isinstance(consumer, oauth2.Consumer):
+            raise ValueError("Invalid consumer.")
+
+        if token is not None and not isinstance(token, oauth2.Token):
+            raise ValueError("Invalid token.")
+
+        self.docmd('AUTH', 'XOAUTH %s' % \
+            base64.b64encode(oauth2.build_xoauth_string(url, consumer, token)))

File diff suppressed because it is too large
+ 118 - 0
anontwi/core/options.py


+ 77 - 0
anontwi/core/shorter.py

@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+# -*- coding: iso-8859-15 -*-
+"""
+$Id$
+
+This file is part of the anontwi project, http://anontwi.03c8.net
+
+Copyright (c) 2012/2013/2014/2015 by psy <epsylon@riseup.net>
+
+anontwi is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation version 3 of the License.
+
+anontwi is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+details.
+
+You should have received a copy of the GNU General Public License along
+with anontwi; if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+x90.es - nopcode.org secure short links (allies)
+"""
+import urllib, sys
+import pycurl
+from cStringIO import StringIO
+
+class ShortURLReservations(object):
+    def __init__(self, service='x90.es'):
+        self._service = service
+        self._parse_shortener()
+        self._extra = {}
+
+    def _parse_shortener(self):
+        """
+	List of valid links shorterers 
+	"""
+        if self._service == 'x90.es' or not self._service:
+            self._url = 'http://x90.es/api.php'
+            self._par = 'url'
+            self._method = 'post'
+	
+    def process_url(self, url, proxy):
+        dest = urllib.urlencode({self._par: url})
+        dest = dest + "&action=shorturl" # see x90.es API features
+        # add some fake user-agent and referer
+        user_agent = 'Mozilla/5.0 (Linux; U; Android 0.5; en-us)'
+        referer = '' 
+        out = StringIO()
+        c = pycurl.Curl()
+        if self._method == 'post':
+            c.setopt(c.POST, 1)
+            c.setopt(c.POSTFIELDS, dest)
+            #c.setopt(c.VERBOSE, True)
+            target = self._url
+        c.setopt(c.URL, target)
+        c.setopt(c.FOLLOWLOCATION, 1)
+        c.setopt(c.REFERER, referer)
+        c.setopt(c.USERAGENT, user_agent)
+        # try connection with proxy
+        if proxy is None:
+            pass
+        else:
+	    c.setopt(c.PROXY, proxy)
+        c.setopt(c.WRITEFUNCTION, out.write)
+        try:
+            c.perform()
+        except Exception as e:
+            if proxy is None:
+                print "\n[Error] Something wrong connecting to short url service provider:", self._service, '[', e[1], '].' , "Aborting!...\n"
+            else:
+                print "\n[Error] Something wrong connecting to short url service provider:", self._service, "[ Couldn't connect to proxy ]." , "Aborting!...\n"
+            sys.exit(2)
+        shorturl = out.getvalue()
+        return shorturl
+        c.close()

+ 434 - 0
anontwi/core/socks.py

@@ -0,0 +1,434 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-"
+# vim: set expandtab tabstop=4 shiftwidth=4:
+"""SocksiPy - Python SOCKS module.
+Version 1.00
+
+Copyright 2006 Dan-Haim. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+3. Neither the name of Dan Haim nor the names of his contributors may be used
+   to endorse or promote products derived from this software without specific
+   prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY DAN HAIM "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL DAN HAIM OR HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMANGE.
+This module provides a standard socket-like interface for Python
+for tunneling connections through SOCKS proxies.
+"""
+"""
+Minor modifications made by Christopher Gilbert (http://motomastyle.com/)
+for use in PyLoris (http://pyloris.sourceforge.net/)
+
+Minor modifications made by Mario Vilas (http://breakingcode.wordpress.com/)
+mainly to merge bug fixes found in Sourceforge
+"""
+import base64
+import socket
+import struct
+import sys
+
+if getattr(socket, 'socket', None) is None:
+    raise ImportError('socket.socket missing, proxy support unusable')
+
+PROXY_TYPE_SOCKS4 = 1
+PROXY_TYPE_SOCKS5 = 2
+PROXY_TYPE_HTTP = 3
+PROXY_TYPE_HTTP_NO_TUNNEL = 4
+
+_defaultproxy = None
+_orgsocket = socket.socket
+
+class ProxyError(Exception): pass
+class GeneralProxyError(ProxyError): pass
+class Socks5AuthError(ProxyError): pass
+class Socks5Error(ProxyError): pass
+class Socks4Error(ProxyError): pass
+class HTTPError(ProxyError): pass
+
+_generalerrors = ("success",
+    "invalid data",
+    "not connected",
+    "not available",
+    "bad proxy type",
+    "bad input")
+
+_socks5errors = ("succeeded",
+    "general SOCKS server failure",
+    "connection not allowed by ruleset",
+    "Network unreachable",
+    "Host unreachable",
+    "Connection refused",
+    "TTL expired",
+    "Command not supported",
+    "Address type not supported",
+    "Unknown error")
+
+_socks5autherrors = ("succeeded",
+    "authentication is required",
+    "all offered authentication methods were rejected",
+    "unknown username or invalid password",
+    "unknown error")
+
+_socks4errors = ("request granted",
+    "request rejected or failed",
+    "request rejected because SOCKS server cannot connect to identd on the client",
+    "request rejected because the client program and identd report different user-ids",
+    "unknown error")
+
+def setdefaultproxy(proxytype=None, addr=None, port=None, rdns=True, username=None, password=None):
+    """setdefaultproxy(proxytype, addr[, port[, rdns[, username[, password]]]])
+    Sets a default proxy which all further socksocket objects will use,
+    unless explicitly changed.
+    """
+    global _defaultproxy
+    _defaultproxy = (proxytype, addr, port, rdns, username, password)
+
+def wrapmodule(module):
+    """wrapmodule(module)
+    Attempts to replace a module's socket library with a SOCKS socket. Must set
+    a default proxy using setdefaultproxy(...) first.
+    This will only work on modules that import socket directly into the namespace;
+    most of the Python Standard Library falls into this category.
+    """
+    if _defaultproxy != None:
+        module.socket.socket = socksocket
+    else:
+        raise GeneralProxyError((4, "no proxy specified"))
+
+class socksocket(socket.socket):
+    """socksocket([family[, type[, proto]]]) -> socket object
+    Open a SOCKS enabled socket. The parameters are the same as
+    those of the standard socket init. In order for SOCKS to work,
+    you must specify family=AF_INET, type=SOCK_STREAM and proto=0.
+    """
+
+    def __init__(self, family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, _sock=None):
+        _orgsocket.__init__(self, family, type, proto, _sock)
+        if _defaultproxy != None:
+            self.__proxy = _defaultproxy
+        else:
+            self.__proxy = (None, None, None, None, None, None)
+        self.__proxysockname = None
+        self.__proxypeername = None
+        self.__httptunnel = True
+
+    def __recvall(self, count):
+        """__recvall(count) -> data
+        Receive EXACTLY the number of bytes requested from the socket.
+        Blocks until the required number of bytes have been received.
+        """
+        data = self.recv(count)
+        while len(data) < count:
+            d = self.recv(count-len(data))
+            if not d: raise GeneralProxyError((0, "connection closed unexpectedly"))
+            data = data + d
+        return data
+
+    def sendall(self, content, *args):
+        """ override socket.socket.sendall method to rewrite the header
+        for non-tunneling proxies if needed
+        """
+        if not self.__httptunnel:
+            content = self.__rewriteproxy(content)
+        return super(socksocket, self).sendall(content, *args)
+
+    def __rewriteproxy(self, header):
+        """ rewrite HTTP request headers to support non-tunneling proxies
+        (i.e. those which do not support the CONNECT method).
+        This only works for HTTP (not HTTPS) since HTTPS requires tunneling.
+        """
+        host, endpt = None, None
+        hdrs = header.split("\r\n")
+        for hdr in hdrs:
+            if hdr.lower().startswith("host:"):
+                host = hdr
+            elif hdr.lower().startswith("get") or hdr.lower().startswith("post"):
+                endpt = hdr
+        if host and endpt:
+            hdrs.remove(host)
+            hdrs.remove(endpt)
+            host = host.split(" ")[1]
+            endpt = endpt.split(" ")
+            if (self.__proxy[4] != None and self.__proxy[5] != None):
+                hdrs.insert(0, self.__getauthheader())
+            hdrs.insert(0, "Host: %s" % host)
+            hdrs.insert(0, "%s http://%s%s %s" % (endpt[0], host, endpt[1], endpt[2]))
+        return "\r\n".join(hdrs)
+
+    def __getauthheader(self):
+        auth = self.__proxy[4] + ":" + self.__proxy[5]
+        return "Proxy-Authorization: Basic " + base64.b64encode(auth)
+
+    def setproxy(self, proxytype=None, addr=None, port=None, rdns=True, username=None, password=None):
+        """setproxy(proxytype, addr[, port[, rdns[, username[, password]]]])
+        Sets the proxy to be used.
+        proxytype -    The type of the proxy to be used. Three types
+                are supported: PROXY_TYPE_SOCKS4 (including socks4a),
+                PROXY_TYPE_SOCKS5 and PROXY_TYPE_HTTP
+        addr -        The address of the server (IP or DNS).
+        port -        The port of the server. Defaults to 1080 for SOCKS
+                servers and 8080 for HTTP proxy servers.
+        rdns -        Should DNS queries be preformed on the remote side
+                (rather than the local side). The default is True.
+                Note: This has no effect with SOCKS4 servers.
+        username -    Username to authenticate with to the server.
+                The default is no authentication.
+        password -    Password to authenticate with to the server.
+                Only relevant when username is also provided.
+        """
+        self.__proxy = (proxytype, addr, port, rdns, username, password)
+
+    def __negotiatesocks5(self, destaddr, destport):
+        """__negotiatesocks5(self,destaddr,destport)
+        Negotiates a connection through a SOCKS5 server.
+        """
+        # First we'll send the authentication packages we support.
+        if (self.__proxy[4]!=None) and (self.__proxy[5]!=None):
+            # The username/password details were supplied to the
+            # setproxy method so we support the USERNAME/PASSWORD
+            # authentication (in addition to the standard none).
+            self.sendall(struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02))
+        else:
+            # No username/password were entered, therefore we
+            # only support connections with no authentication.
+            self.sendall(struct.pack('BBB', 0x05, 0x01, 0x00))
+        # We'll receive the server's response to determine which
+        # method was selected
+        chosenauth = self.__recvall(2)
+        if chosenauth[0:1] != chr(0x05).encode():
+            self.close()
+            raise GeneralProxyError((1, _generalerrors[1]))
+        # Check the chosen authentication method
+        if chosenauth[1:2] == chr(0x00).encode():
+            # No authentication is required
+            pass
+        elif chosenauth[1:2] == chr(0x02).encode():
+            # Okay, we need to perform a basic username/password
+            # authentication.
+            self.sendall(chr(0x01).encode() + chr(len(self.__proxy[4])) + self.__proxy[4] + chr(len(self.__proxy[5])) + self.__proxy[5])
+            authstat = self.__recvall(2)
+            if authstat[0:1] != chr(0x01).encode():
+                # Bad response
+                self.close()
+                raise GeneralProxyError((1, _generalerrors[1]))
+            if authstat[1:2] != chr(0x00).encode():
+                # Authentication failed
+                self.close()
+                raise Socks5AuthError((3, _socks5autherrors[3]))
+            # Authentication succeeded
+        else:
+            # Reaching here is always bad
+            self.close()
+            if chosenauth[1] == chr(0xFF).encode():
+                raise Socks5AuthError((2, _socks5autherrors[2]))
+            else:
+                raise GeneralProxyError((1, _generalerrors[1]))
+        # Now we can request the actual connection
+        req = struct.pack('BBB', 0x05, 0x01, 0x00)
+        # If the given destination address is an IP address, we'll
+        # use the IPv4 address request even if remote resolving was specified.
+        try:
+            ipaddr = socket.inet_aton(destaddr)
+            req = req + chr(0x01).encode() + ipaddr
+        except socket.error:
+            # Well it's not an IP number,  so it's probably a DNS name.
+            if self.__proxy[3]:
+                # Resolve remotely
+                ipaddr = None
+                req = req + chr(0x03).encode() + chr(len(destaddr)).encode() + destaddr
+            else:
+                # Resolve locally
+                ipaddr = socket.inet_aton(socket.gethostbyname(destaddr))
+                req = req + chr(0x01).encode() + ipaddr
+        req = req + struct.pack(">H", destport)
+        self.sendall(req)
+        # Get the response
+        resp = self.__recvall(4)
+        if resp[0:1] != chr(0x05).encode():
+            self.close()
+            raise GeneralProxyError((1, _generalerrors[1]))
+        elif resp[1:2] != chr(0x00).encode():
+            # Connection failed
+            self.close()
+            if ord(resp[1:2])<=8:
+                raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])]))
+            else:
+                raise Socks5Error((9, _socks5errors[9]))
+        # Get the bound address/port
+        elif resp[3:4] == chr(0x01).encode():
+            boundaddr = self.__recvall(4)
+        elif resp[3:4] == chr(0x03).encode():
+            resp = resp + self.recv(1)
+            boundaddr = self.__recvall(ord(resp[4:5]))
+        else:
+            self.close()
+            raise GeneralProxyError((1,_generalerrors[1]))
+        boundport = struct.unpack(">H", self.__recvall(2))[0]
+        self.__proxysockname = (boundaddr, boundport)
+        if ipaddr != None:
+            self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
+        else:
+            self.__proxypeername = (destaddr, destport)
+
+    def getproxysockname(self):
+        """getsockname() -> address info
+        Returns the bound IP address and port number at the proxy.
+        """
+        return self.__proxysockname
+
+    def getproxypeername(self):
+        """getproxypeername() -> address info
+        Returns the IP and port number of the proxy.
+        """
+        return _orgsocket.getpeername(self)
+
+    def getpeername(self):
+        """getpeername() -> address info
+        Returns the IP address and port number of the destination
+        machine (note: getproxypeername returns the proxy)
+        """
+        return self.__proxypeername
+
+    def __negotiatesocks4(self,destaddr,destport):
+        """__negotiatesocks4(self,destaddr,destport)
+        Negotiates a connection through a SOCKS4 server.
+        """
+        # Check if the destination address provided is an IP address
+        rmtrslv = False
+        try:
+            ipaddr = socket.inet_aton(destaddr)
+        except socket.error:
+            # It's a DNS name. Check where it should be resolved.
+            if self.__proxy[3]:
+                ipaddr = struct.pack("BBBB", 0x00, 0x00, 0x00, 0x01)
+                rmtrslv = True
+            else:
+                ipaddr = socket.inet_aton(socket.gethostbyname(destaddr))
+        # Construct the request packet
+        req = struct.pack(">BBH", 0x04, 0x01, destport) + ipaddr
+        # The username parameter is considered userid for SOCKS4
+        if self.__proxy[4] != None:
+            req = req + self.__proxy[4]
+        req = req + chr(0x00).encode()
+        # DNS name if remote resolving is required
+        # NOTE: This is actually an extension to the SOCKS4 protocol
+        # called SOCKS4A and may not be supported in all cases.
+        if rmtrslv:
+            req = req + destaddr + chr(0x00).encode()
+        self.sendall(req)
+        # Get the response from the server
+        resp = self.__recvall(8)
+        if resp[0:1] != chr(0x00).encode():
+            # Bad data
+            self.close()
+            raise GeneralProxyError((1,_generalerrors[1]))
+        if resp[1:2] != chr(0x5A).encode():
+            # Server returned an error
+            self.close()
+            if ord(resp[1:2]) in (91, 92, 93):
+                self.close()
+                raise Socks4Error((ord(resp[1:2]), _socks4errors[ord(resp[1:2]) - 90]))
+            else:
+                raise Socks4Error((94, _socks4errors[4]))
+        # Get the bound address/port
+        self.__proxysockname = (socket.inet_ntoa(resp[4:]), struct.unpack(">H", resp[2:4])[0])
+        if rmtrslv != None:
+            self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
+        else:
+            self.__proxypeername = (destaddr, destport)
+
+    def __negotiatehttp(self, destaddr, destport):
+        """__negotiatehttp(self,destaddr,destport)
+        Negotiates a connection through an HTTP server.
+        """
+        # If we need to resolve locally, we do this now
+        if not self.__proxy[3]:
+            addr = socket.gethostbyname(destaddr)
+        else:
+            addr = destaddr
+        headers =  ["CONNECT ", addr, ":", str(destport), " HTTP/1.1\r\n"]
+        headers += ["Host: ", destaddr, "\r\n"]
+        if (self.__proxy[4] != None and self.__proxy[5] != None):
+                headers += [self.__getauthheader(), "\r\n"]
+        headers.append("\r\n")
+        self.sendall("".join(headers).encode())
+        # We read the response until we get the string "\r\n\r\n"
+        resp = self.recv(1)
+        while resp.find("\r\n\r\n".encode()) == -1:
+            resp = resp + self.recv(1)
+        # We just need the first line to check if the connection
+        # was successful
+        statusline = resp.splitlines()[0].split(" ".encode(), 2)
+        if statusline[0] not in ("HTTP/1.0".encode(), "HTTP/1.1".encode()):
+            self.close()
+            raise GeneralProxyError((1, _generalerrors[1]))
+        try:
+            statuscode = int(statusline[1])
+        except ValueError:
+            self.close()
+            raise GeneralProxyError((1, _generalerrors[1]))
+        if statuscode != 200:
+            self.close()
+            raise HTTPError((statuscode, statusline[2]))
+        self.__proxysockname = ("0.0.0.0", 0)
+        self.__proxypeername = (addr, destport)
+
+    def connect(self, destpair):
+        """connect(self, despair)
+        Connects to the specified destination through a proxy.
+        destpar - A tuple of the IP/DNS address and the port number.
+        (identical to socket's connect).
+        To select the proxy server use setproxy().
+        """
+        # Do a minimal input check first
+        if (not type(destpair) in (list,tuple)) or (len(destpair) < 2) or (not isinstance(destpair[0], basestring)) or (type(destpair[1]) != int):
+            raise GeneralProxyError((5, _generalerrors[5]))
+        if self.__proxy[0] == PROXY_TYPE_SOCKS5:
+            if self.__proxy[2] != None:
+                portnum = self.__proxy[2]
+            else:
+                portnum = 1080
+            _orgsocket.connect(self, (self.__proxy[1], portnum))
+            self.__negotiatesocks5(destpair[0], destpair[1])
+        elif self.__proxy[0] == PROXY_TYPE_SOCKS4:
+            if self.__proxy[2] != None:
+                portnum = self.__proxy[2]
+            else:
+                portnum = 1080
+            _orgsocket.connect(self,(self.__proxy[1], portnum))
+            self.__negotiatesocks4(destpair[0], destpair[1])
+        elif self.__proxy[0] == PROXY_TYPE_HTTP:
+            if self.__proxy[2] != None:
+                portnum = self.__proxy[2]
+            else:
+                portnum = 8080
+            _orgsocket.connect(self,(self.__proxy[1], portnum))
+            self.__negotiatehttp(destpair[0], destpair[1])
+        elif self.__proxy[0] == PROXY_TYPE_HTTP_NO_TUNNEL:
+            if self.__proxy[2] != None:
+                portnum = self.__proxy[2]
+            else:
+                portnum = 8080
+            _orgsocket.connect(self,(self.__proxy[1],portnum))
+            if destpair[1] == 443:
+                self.__negotiatehttp(destpair[0],destpair[1])
+            else:
+                self.__httptunnel = False
+        elif self.__proxy[0] == None:
+            _orgsocket.connect(self, (destpair[0], destpair[1]))
+        else:
+            raise GeneralProxyError((4, _generalerrors[4]))

File diff suppressed because it is too large
+ 4828 - 0
anontwi/core/twitter.py


+ 524 - 0
anontwi/core/wrapper.py

@@ -0,0 +1,524 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-"
+# vim: set expandtab tabstop=4 shiftwidth=4:
+"""
+Copyright (C) 2012 Jhonny5 <jhonny5@riseup.net> + psy <epsylon@riseup.net>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+import os, sys
+import logging
+
+from core.gtk.config_gtk import * 
+from core.gtk.error import AnontwiError
+from core.main import anontwi
+from core.encrypt import generate_key
+
+class IOManager(object):
+    def __init__(self):
+        self.backup = ''
+    
+    def CaptureOutput(self):
+        from cStringIO import StringIO
+
+        self.backup = sys.stdout
+        sys.stdout = StringIO()
+
+    def GetOutput(self):
+        return sys.stdout.getvalue()
+
+    def RestoreOutput(self):
+        sys.stdout.close()
+        sys.stdout = self.backup
+
+class WrapperAnontwi():
+    """Wrapper Anontwi class."""
+    
+    """ PRIVATE """
+    def __init__(self):
+        self.log = logging.getLogger('Anontwi-Wrapper')
+        self.app = anontwi()
+        self.options = '' 
+
+    def _create_options(self, cmd):
+        access = self.get_access_tokens()
+        if access:
+            self.log.debug('Access Token: ' + access['access_token'])   
+            self.log.debug('Secret Token: ' + access['secret_token'])
+            cmd.append(access['access_token'])
+            cmd.append(access['secret_token'])
+
+        self.log.debug('[_create_options] cmd: ' + str(cmd))
+
+        self.options = self.app.create_options(cmd)
+        self.app.set_options(self.options)
+
+    def _run(self, cmd):
+        self.log.debug('Running Anontwi with commands: ' + str(cmd))
+        self.app.run(cmd[1:])
+
+    def get_app(self):
+        return self.app
+    
+    """ ANONTWI GTK """
+    def get_access_tokens(self):
+        """Get AccessTokens from file.
+            Returns: 
+                Dict with: {'access_token' : 'Access Token',
+                            'secret_token' : 'Secret Token'}
+        """
+        file_path = DIR_TOKENS + FILE_ACC_TKN
+        try:
+            lines = open(file_path).readlines()
+            return {'access_token' : lines[0].strip(), 
+                    'secret_token' : lines[1].strip() }
+        except: 
+            self.log.info("Access tokens NOT found, path: %s" % file_path)
+            return {}
+
+    def get_consumer_tokens(self):
+        """Get ConsumerTokens from file.
+            Returns: 
+                ToDo
+        """
+        file_path = DIR_TOKENS + FILE_CONS_TKN
+        try:
+            lines = open(file_path).readlines()
+            self.log.debug('[get_consumer_tokens]')
+            self.log.debug('Path: ' + file_path)
+            self.log.debug('- consumer_key: ' + lines[0].strip())
+            self.log.debug('- consumer_secret: ' + lines[1].strip())
+
+            return {'consumer_key' : lines[0].strip(), 
+                    'consumer_secret' : lines[1].strip() }
+        except: 
+            self.log.info("Consumer tokens NOT found, path: %s" % file_path)
+            return {}
+
+    def get_source_api(self):
+        """Get SourceApi from file.
+            Returns: 
+                ToDo
+        """
+        file_path = DIR_TOKENS + FILE_SOURCE_API
+        try:
+            lines = open(file_path).readlines()
+            self.log.debug('[get_source_api]')
+            self.log.debug('Path: ' + file_path)
+            self.log.debug('Source API: ' + lines[0].strip())
+
+            return {'source_api' : lines[0].strip()}
+        except: 
+            self.log.info("Source API NOT found, path: %s" % file_path)
+            return {}
+   
+    def write_tokens(self, access, consumer, source_api):
+        self.log.info('Writing tokens')
+        # check directories
+        if not os.path.exists(DIR_HOME_ANON):
+            self.log.info(DIR_HOME_ANON + " created.")
+            os.makedirs(DIR_HOME_ANON)
+        if not os.path.exists(DIR_TOKENS):
+            self.log.info(DIR_TOKENS + " created.")
+            os.makedirs(DIR_TOKENS)
+
+        if access:
+            open(DIR_TOKENS + FILE_ACC_TKN, 'w').write(access['access_token'] + '\n' + access['secret_token'])
+        if consumer:
+            open(DIR_TOKENS + FILE_CONS_TKN, 'w').write(consumer['consumer_key'] + '\n' + consumer['consumer_secret'])
+        if source_api:
+            if source_api == "api.twitter.com":
+                open(DIR_TOKENS + FILE_SOURCE_API, 'w').write(source_api)
+            else:
+                open(DIR_TOKENS + FILE_SOURCE_API, 'w').write(source_api)
+
+    """ ANONTWI CORE """
+    def send_tweet(self, tweet, 
+                        pm = None,
+                        gps = None,
+                        wave = None,
+                        enc = None,
+                        proxy = None):
+        """Send tweet.
+            Args: 
+                tweet: text message to send.
+                pm:    {'pm' : 'bool value - is a pm message?,
+                        'user' : 'name of the user recipient'} 
+                enc:   {'enc' : 'bool value - encrypt the message?,
+                        'pin : 'pin key for encrypted msg.' }
+                proxy: {'proxy' : 'bool value - is proxy enable?',
+                        'ip_address' : 'ip addres for proxy',
+                        'port' : 'port for proxy'}
+        """
+        if os.path.isfile ('anontwi'):
+            cmd = ['./anontwi']
+        else:
+            cmd = ['anontwi']
+        if pm['pm'] is False:
+            cmd.append('-m ' + tweet.strip() )
+        else:
+            cmd.append('-m ' + tweet.strip() )
+            cmd.append('-d ' + pm['user'])
+        if enc and enc['enc']:
+            cmd.append('--enc')
+            cmd.append('--pin=' + enc['pin'])
+        if gps:
+            cmd.append('--gps')
+            app = self.get_app()
+            cmd.append(app.geoposition)
+        if wave:
+            cmd.append('--waves')
+        if proxy and proxy['proxy']:
+            cmd.append('--proxy=' + proxy['ip_address'] + ':' + proxy['port'])
+        try: 
+            print "CMD ", cmd
+            self._create_options(cmd)
+            return self._run(cmd)
+        except:
+            return False
+
+    def encrypt(self, message, key):
+        cmd = ['anontwi']
+        cmd.append('--enc')
+        cmd.append('--pin=' + key)
+        self._create_options(cmd)
+        app = self.get_app()
+        m_encrypt = app.encrypt(message, key)
+        self.log.debug('[encrypt] Msg encrypted: ' + str(m_encrypt))
+        return m_encrypt
+    
+    def decrypt(self, messages, key):
+        cmd = ['anontwi']
+        cmd.append('--dec=' + messages)
+        cmd.append('--pin=' + key)
+        self._create_options(cmd)
+        app = self.get_app()
+        msg = app.decrypt(messages, key)
+        self.log.debug('[decrypt] Msg decrypted: ' + str(msg))
+        return msg
+
+    def get_user_info(self, proxy):
+        
+        try:
+            self.log.debug('[get_user_info] loading info...')
+            info=False
+            app = self.get_app()
+            consumer = self.get_consumer_tokens()
+            access = self.get_access_tokens()
+
+            if not consumer or not access:
+                self.log.critical('Tokens not found! Could not retrieve user information.')
+            else:
+                info = app.get_user_info(consumer['consumer_key'],
+                                         consumer['consumer_secret'],
+                                         access['access_token'],
+                                         access['secret_token'],
+                                         proxy)
+        except:
+            self.log.critical('Could not retrieve user information.')
+        return info
+
+    def get_url(self, access, consumer, source_api, proxy):
+        data = ''
+        cmd = ['anontwi']
+        cmd.append('--tokens')
+
+        if proxy is not None and proxy['proxy'] is True:
+            cmd.append('--proxy=' + proxy['ip_address'] + ':' + proxy['port'])
+ 
+        self.log.debug("GetUrl cmd: " + str(cmd))
+        try:
+            self.write_tokens(access, consumer, source_api)
+            self._create_options(cmd)
+            app = self.get_app()
+
+            app = self.get_app()
+            app.source_api = source_api
+            app.set_oauth_urls()
+            
+            data = app.request_url(consumer['consumer_key'], 
+                                   consumer['consumer_secret'],
+                                   source_api = source_api,
+                                   gtk = True)
+            self.log.debug("Sucesfull GetUrl")
+            return data
+        except:
+            self.log.debug("Error GetUrl")
+            return ''
+
+    def insert_pincode(self, pin, oauth_token, oauth_token_secret, 
+                       consumer, source_api, proxy=None):
+        cmd = ["anontwi"]
+        cmd.append("--tokens")
+        if proxy:
+            cmd.append('--proxy=' + proxy)
+        self._create_options(cmd)
+        app = self.get_app()
+        consumer = self.get_consumer_tokens()
+        try:
+            self.log.debug("Inserting pincode.")
+            return app.insert_pincode(oauth_token,
+                               oauth_token_secret,
+                               consumer['consumer_key'],
+                               consumer['consumer_secret'],
+                               source_api,
+                               pin, gtk = True)
+        except:
+            self.log.debug("Fail to insert pincode.")
+            raise
+    
+    def get_reply_user(self, id):
+        status = self.app.get_status(id)
+        user = status.user.screen_name
+        return user
+    
+    def reply(self, ID, msg, gps = None, enc = None, proxy = None):
+        user = self.get_reply_user(ID)
+        cmd = ['anontwi']
+        cmd.append('-m ' + '@' + user + ' ' + msg )
+        cmd.append('--reply=' + ID)
+        if enc['enc'] is True:
+            cmd.append('--enc')
+            cmd.append('--pin=' + enc['pin'] +'')
+        if gps:
+            cmd.append('--gps')
+            app = self.get_app()
+            cmd.append(app.geoposition)
+        if proxy['proxy'] is True:
+            cmd.append('--proxy=' + proxy['ip_address'] + ':' + proxy['port'])
+        self._create_options(cmd)
+        self._run(cmd)
+    
+    def retweet_tweet(self, ID, proxy=None):
+        cmd = ['anontwi']
+        cmd.append('-r')
+        cmd.append(ID)
+        if proxy:
+            cmd.append('--proxy=' + proxy['ip_address'] + ':' + proxy['port'])
+        self._create_options(cmd)
+        app = self.get_app()
+        topics = app.send_retweet()    
+
+    def save_messages(self, user, num_ocurrences, proxy=None):
+        cmd = ["anontwi"]
+        cmd.append('--save')
+        cmd.append(user + " " + num_ocurrences)
+        if proxy:
+            cmd.append('--proxy=' + proxy['ip_address'] + ':' + proxy['port'])
+        self.log.debug('[Backup] CMD: ' + str(cmd)) 
+        self._create_options(cmd)
+        app = self.get_app()
+        self.log.debug('[Backup] Creating app: OK')
+        saves = app.save_timeline()
+        self.log.debug('[Backup] Return lines: ' + str(saves))
+        return saves
+    
+    def favorite(self, ID, proxy=None):
+        cmd = ['anontwi']
+        cmd.append('--fav=' + ID)
+        if proxy:
+            cmd.append('--proxy=' + proxy['ip_address'] + ':' + proxy['port'])
+        self._create_options(cmd)
+        self._run(cmd)
+
+    def unfavorite(self, ID, proxy=None):
+        cmd = ['anontwi']
+        cmd.append('--unfav=' + ID)
+        if proxy:
+            cmd.append('--proxy=' + proxy['ip_address'] + ':' + proxy['port'])
+        self._create_options(cmd)
+        self._run(cmd)
+
+    def delete_tweet(self, ID, proxy=None):
+        cmd = ['anontwi']
+        cmd.append('--rm-m=' + ID)
+        if proxy:
+            cmd.append('--proxy=' + proxy['ip_address'] + ':' + proxy['port'])
+        self._create_options(cmd)
+        self._run(cmd)
+
+    def delete_private(self, ID, proxy=None):
+        cmd = ['anontwi']
+        cmd.append('--rm-d=' + ID)
+        if proxy:
+            cmd.append('--proxy=' + proxy['ip_address'] + ':' + proxy['port'])
+        self._create_options(cmd)
+        self._run(cmd)
+
+    def search_messages(self, textsearch, 
+                        num_ocurrences, proxy=None):
+        cmd = ["anontwi"]
+        cmd.append('--ts=' + textsearch + " " + num_ocurrences)
+        if proxy:
+            cmd.append('--proxy=' + proxy['ip_address'] + ':' + proxy['port'])
+        self._create_options(cmd)
+        app = self.get_app()
+        messages = app.search_messages()
+        return messages
+
+    def generate_key(self):
+        key = generate_key()
+        return key
+
+    def search_topics(self, proxy=None):
+        cmd = ["anontwi"]
+        cmd.append('--tt')
+        if proxy:
+            cmd.append('--proxy=' + proxy['ip_address'] + ':' + proxy['port'])
+        self._create_options(cmd)
+        app = self.get_app()
+        topics = app.search_topics()
+        trendingtopics = ""
+        for t in topics:
+            self.topic = t.name
+            trendingtopics = trendingtopics + self.topic + '\n'
+        return trendingtopics
+
+    def home_timeline(self, user, num_ocurrences, proxy=None):
+        cmd = ["anontwi"]
+        cmd.append('--tu=' + user + " " + str(num_ocurrences))
+        if proxy:
+            cmd.append('--proxy=' + proxy)
+        self.log.debug('[Public] CMD: ' + str(cmd))
+        self._create_options(cmd)
+        app = self.get_app()
+        self.log.debug('[Public] Creating app: OK')
+        tweets = app.show_timeline()
+        self.log.debug('[Public] Return lines: ' + str(tweets))
+        return tweets, len(tweets)
+
+    def search_favorite(self, user, num_ocurrences, proxy=None):
+        cmd = ["anontwi"]
+        cmd.append('--tfav=' + user + " " + num_ocurrences)
+        if proxy:
+            cmd.append('--proxy=' + proxy['ip_address'] + ':' + proxy['port'])
+        self.log.debug('[Favorites] CMD: ' + str(cmd)) 
+        self._create_options(cmd)
+        app = self.get_app()
+        self.log.debug('[Favorites] Creating app: OK')
+        favorites = app.show_favorites()
+        self.log.debug('[Favorites] Return lines: ' + str(favorites))
+        return favorites
+
+    def mentions(self, num_ocurrences, proxy=None):
+        cmd = ["anontwi"]
+        cmd.append("--me=" + num_ocurrences)
+        if proxy:
+            cmd.append('--proxy=' + proxy['ip_address'] + ':' + proxy['port'])
+        self.log.debug('[Mentions] CMD: ' + str(cmd))
+        self._create_options(cmd)
+        app = self.get_app()
+        self.log.debug('[Mentions] Creating app: OK')
+        (mentions,num) = app.show_mentions()
+        self.log.debug('[Mentions] Return lines: ' + str(mentions))
+        return mentions, num
+
+    def show_private(self, num_ocurrences, proxy=None):
+        cmd = ["anontwi"]
+        cmd.append('--td=' + num_ocurrences)
+        if proxy:
+            cmd.append('--proxy=' + proxy['ip_address'] + ':' + proxy['port'])
+        self.log.debug('[Private] CMD: ' + str(cmd))
+        self._create_options(cmd)
+        app = self.get_app()
+        dms = app.show_timelinedm()
+        self.log.debug('[Private] Creating app: OK')
+        self.log.debug('[Private] Return lines: ' + str(dms))
+        return dms
+
+    def show_public(self, num_ocurrences, proxy=None):
+        cmd = ["anontwi"]
+        cmd.append("--tf=" + str(num_ocurrences))
+        if proxy:
+            cmd.append('--proxy=' + proxy)
+        self.log.debug('[Home] CMD: ' + str(cmd))
+        self._create_options(cmd)
+        app = self.get_app()
+        self.log.debug('[Home] Creating app: OK')
+        (timelines, num_ocurrences) = app.show_timeline_friends()
+        self.log.debug('[Home] Return lines: ' + str(timelines))
+        return timelines, num_ocurrences
+
+    def short_url(self, url, proxy=None):
+        cmd = ['anontwi']
+        cmd.append('--short=' + url) 
+        if proxy:
+            cmd.append('--proxy=' + proxy['ip_address'] + ':' + proxy['port'])
+        print "CMD ", cmd
+        self._create_options(cmd)
+        app = self.get_app()
+        short_url = app.short_url()
+        self.log.debug('[Shorten URL] Shorten URL: ' + str(short_url))
+        return short_url
+
+    def suicide(self, proxy=None):
+        cmd = ['anontwi']
+        cmd.append('--suicide')
+        if proxy:
+            cmd.append('--proxy=' + proxy['ip_address'] + ':' + proxy['port'])
+        self._create_options(cmd)
+        app = self.get_app()
+        topics = app.suicide(self)
+        self.log.debug('[Suicide]')
+
+    def follow(self, user, proxy=None):
+        cmd = ['anontwi']
+        cmd.append('-f')
+        cmd.append(user)
+        if proxy:
+            cmd.append('--proxy=' + proxy['ip_address'] + ':' + proxy['port'])
+        self._create_options(cmd)
+        app = self.get_app()
+        status = app.set_friend()
+        self.log.debug('[Follow]' + str(user))
+        return status
+
+    def unfollow(self, user, proxy=None):
+        cmd = ['anontwi']
+        cmd.append('-u')
+        cmd.append(user)
+        if proxy:
+            cmd.append('--proxy=' + proxy['ip_address'] + ':' + proxy['port'])
+        self._create_options(cmd)
+        app = self.get_app()
+        status = app.remove_friend()
+        self.log.debug('[Unfollow]' + str(user))
+        return status
+
+    def block(self, user, proxy=None):
+        cmd = ['anontwi']
+        cmd.append('--block=' + user)
+        if proxy:
+            cmd.append('--proxy=' + proxy['ip_address'] + ':' + proxy['port'])
+        self._create_options(cmd)
+        app = self.get_app()
+        status = app.set_friend()
+        self.log.debug('[Block]' + str(user))
+        return status
+
+    def unblock(self, user, proxy=None):
+        cmd = ['anontwi']
+        cmd.append('--unblock=' + user)
+        if proxy:
+            cmd.append('--proxy=' + proxy['ip_address'] + ':' + proxy['port'])
+        self._create_options(cmd)
+        app = self.get_app()
+        status = app.remove_friend()
+        self.log.debug('[Unblock]' + str(user))
+        return status
+
+    def IRCdeploy(self, user, host, port, chan):
+        app = self.get_app()
+        AnonBot = app.IRCdeploy(user, host, port, chan)
+        return AnonBot

+ 7 - 0
anontwi/docs/AUTHOR

@@ -0,0 +1,7 @@
+========================
+psy (epsylon@riseup.net)
+========================
+http://03c8.net
+========================
+@psytzsche
+========================

File diff suppressed because it is too large
+ 209 - 0
anontwi/docs/COPYING


+ 50 - 0
anontwi/docs/INSTALL

@@ -0,0 +1,50 @@
+============================================
+AnonTwi - [anontwi.03c8.net] - 2015
+============================================
+
+FIGHT CENSORSHIP!! being more safe on social networking sites...
+
+===================
+How-to INSTALL:
+===================
+
+Code runs on many platforms. It requires Python and the following libraries:
+
+      - python-crypto   - cryptographic algorithms and protocols for Python
+
+      - python-httplib2 - comprehensive HTTP client library written for Python
+
+      - python-pycurl   - python bindings to libcurl
+
+      - python-glade2   - GTK+ bindings: Glade support
+
+On Debian-based systems (ex: Ubuntu), run:
+
+      - directly:
+
+              sudo apt-get install python-crypto python-httplib2 python-pycurl python-glade2
+
+      - using setup-tools (http://pypi.python.org/pypi/setuptools):
+
+              easy_install <packages>
+
+On Windows systems, is working (tested!) with:
+
+      - python 2.7      - http://www.python.org/getit/
+      - pycrypto 2.3    - http://www.voidspace.org.uk/downloads/pycrypto-2.3.win32-py2.7.zip
+      - httplib2 0.7.4  - http://httplib2.googlecode.com/files/httplib2-0.7.4.zip
+      - pycurl 7.19.5.1 - http://pycurl.sourceforge.net/download/
+      - pygtk 2.24      - http://www.pygtk.org/downloads.html
+
+      - using setup-tools (http://pypi.python.org/pypi/setuptools):
+
+              easy_install.exe 'packages'
+
+=========
+More info: 
+=========
+
+    - http://anontwi.03c8.net/
+
+    - irc.feenode.net / channel #anontwi
+

+ 5 - 0
anontwi/docs/THANKS

@@ -0,0 +1,5 @@
+pancake
+orange_fanta
+jhonny5
+ikujam
+ox