├── wsgi.py
├── static
├── twitter-icon.png
└── picard-facepalm.jpg
├── twintelligence.ini
├── deployment
├── nginx
│ └── twintelligence
└── systemd
│ └── twintelligence.service
├── .gitignore
├── LICENSE.md
├── templates
├── contact.html
├── fail.html
├── about.html
├── index.html
└── report.html
├── README.md
└── twintelligence.py
/wsgi.py:
--------------------------------------------------------------------------------
1 | from twintelligence import app
2 |
3 | if __name__ == "__main__":
4 | app.run()
5 |
--------------------------------------------------------------------------------
/static/twitter-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jipegit/Twintelligence/HEAD/static/twitter-icon.png
--------------------------------------------------------------------------------
/static/picard-facepalm.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jipegit/Twintelligence/HEAD/static/picard-facepalm.jpg
--------------------------------------------------------------------------------
/twintelligence.ini:
--------------------------------------------------------------------------------
1 | [uwsgi]
2 | module = wsgi:app
3 |
4 | master = true
5 | processes = 5
6 |
7 | socket = twintelligence.sock
8 | chmod-socket = 660
9 | vacuum = true
10 |
11 | die-on-term = true
12 |
--------------------------------------------------------------------------------
/deployment/nginx/twintelligence:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80;
3 | server_name twintelligence.io;
4 |
5 | location / {
6 | include uwsgi_params;
7 | uwsgi_pass unix:/home/dev/Twintelligence/twintelligence.sock;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/deployment/systemd/twintelligence.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=uWSGI instance to serve Twintelligence
3 | After=network.target
4 |
5 | [Service]
6 | User=dev
7 | Group=www-data
8 | WorkingDirectory=/home/dev/Twintelligence
9 | Environment="PATH=/home/dev/twintelligence-env/bin"
10 | ExecStart=/home/dev/twintelligence-env/bin/uwsgi --ini twintelligence.ini
11 |
12 | [Install]
13 | WantedBy=multi-user.target
14 |
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.py[cod]
2 |
3 | # C extensions
4 | *.so
5 |
6 | # Packages
7 | *.egg
8 | *.egg-info
9 | dist
10 | build
11 | eggs
12 | parts
13 | bin
14 | var
15 | sdist
16 | develop-eggs
17 | .installed.cfg
18 | lib
19 | lib64
20 | __pycache__
21 |
22 | # Installer logs
23 | pip-log.txt
24 |
25 | # Unit test / coverage reports
26 | .coverage
27 | .tox
28 | nosetests.xml
29 | *.txt
30 | #*.html
31 | *.token
32 | # Translations
33 | *.mo
34 |
35 | # Mr Developer
36 | .mr.developer.cfg
37 | .project
38 | .pydevproject
39 |
40 |
41 | # folders
42 | env-*
43 | libs
44 |
45 |
46 | # MAC OS X stuff
47 | .DS_Store
48 | .DS_Store?
49 | ._*
50 | .Spotlight-V100
51 | .Trashes
52 | Icon?
53 | ehthumbs.db
54 | Thumbs.db
55 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Twintelligence
2 | Copyright (C) 2013 Jean-Philippe Teissier
3 |
4 | This program is free software: you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation, either version 3 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | You should have received a copy of the GNU General Public License
15 | along with this program. If not, see .
--------------------------------------------------------------------------------
/templates/contact.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Twintelligence
5 |
6 |
7 |
8 |
9 |
10 |
11 |
22 |
23 |
24 |
25 |
33 |
34 |
Contact
35 |
@Jipe_
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/templates/fail.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Twintelligence
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
23 |
24 |
25 |
26 |
29 |
30 |
Oops!
31 |
32 | {{ error }}
33 |
34 |
 }})
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/templates/about.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Twintelligence
5 |
6 |
7 |
8 |
9 |
10 |
11 |
23 |
24 |
25 |
26 |
34 |
35 |
About
36 |
Twintelligence is an OSINT tool. Beware of the traces you leave on the Internet. This is an alpha software.
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Twintelligence
5 |
6 |
7 |
8 |
9 |
10 |
11 |
23 |
24 |
25 |
26 |
34 |
35 |
Twintelligence Report
36 |
Enter a Twitter @UserName to generate the report.
37 | This is an alpha software, don't push it to hard ;)
38 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Twintelligence
2 |
3 | Twintelligence is a free Twitter OSINT tool
4 |
5 | 
6 | 
7 |
8 | ## Author
9 |
10 | Jean-Philippe Teissier - @Jipe_
11 |
12 | ## Development status
13 |
14 | **Twintelligence is no longer maintained**
15 |
16 | ## How to install
17 |
18 | Copy all files from Github
19 |
20 | ## Dependencies
21 |
22 | * pip install python-twitter
23 | * pip install flask
24 |
25 | If you want to run it with Nginx and uwsgi
26 |
27 | * apt-get install nginx uwsgi uwsgi-plugin-python
28 |
29 | ## Setup
30 |
31 | 1. Create an application. See https://dev.twitter.com/
32 |
33 | 2. Go to your application's settings -> OAuth settings and copy/paste your "Consumer key" and your "Consumer key" to the YOUR_APP_CONSUMER_KEY and YOUR_APP_CONSUMER_SECRET variables in the source code
34 |
35 | 3. Go to your application's settings -> Application Type, and change the Access parameter to "Read, Write and Access direct messages". Update the settings
36 |
37 | 3. Go back to your application's details and click on "Recreate my access token". Copy/paste your "Access token" and your "Access token secret" to the YOUR_ACCESS_TOKEN_SECRET and YOUR_ACCESS_TOKEN in the source code. Alternatively you can pass them as arguments with -k/--accesstokenkey and -s/accesstokensecret
38 |
39 | ## How to run
40 |
41 | python twintelligence.py
42 |
43 | ## Changelog
44 |
45 | ### 0.2
46 | * python-twitter & API model update
47 |
48 | ### 0.1
49 | * Initial alpha release
50 |
51 | ## License
52 |
53 | Twintelligence
54 | Copyright (C) 2013-2016 Jean-Philippe Teissier
55 |
56 | This program is free software: you can redistribute it and/or modify
57 | it under the terms of the GNU General Public License as published by
58 | the Free Software Foundation, either version 3 of the License, or
59 | (at your option) any later version.
60 |
61 | This program is distributed in the hope that it will be useful,
62 | but WITHOUT ANY WARRANTY; without even the implied warranty of
63 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
64 | GNU General Public License for more details.
65 |
66 | You should have received a copy of the GNU General Public License
67 | along with this program. If not, see .
68 |
--------------------------------------------------------------------------------
/twintelligence.py:
--------------------------------------------------------------------------------
1 | #
2 | # Twintelligence
3 | #
4 | # Twintelligence is a free Twitter OSINT tool
5 | #
6 | # Author: @Jipe_
7 | #
8 |
9 | import twitter
10 | from datetime import *
11 | from flask import Flask, render_template, redirect, request
12 |
13 | YOUR_APP_CONSUMER_KEY = ""
14 | YOUR_APP_CONSUMER_SECRET = ""
15 |
16 | YOUR_ACCESS_TOKEN = ""
17 | YOUR_ACCESS_TOKEN_SECRET = ""
18 |
19 | app = Flask(__name__)
20 |
21 |
22 | class Data(object):
23 |
24 | def __init__(self, g, l, h):
25 | self.g = g
26 | self.l = l
27 | self.h = h
28 |
29 |
30 | def getstatuses(twapi, userid, twnumber):
31 | """ Get the list of Tweets"""
32 |
33 | totalitems = 0
34 | items = None
35 | gpscoordinates = []
36 | langs = {}
37 | hours = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
38 | maxid = 0
39 |
40 | print("[D] Retrieving the list of tweets (it might take a while...)")
41 |
42 | try:
43 | items = twapi.GetUserTimeline(user_id=userid, count=200) # Can't request more than 200 items at a time
44 | except twitter.TwitterError as e:
45 | print(u"[-] ERROR: (" + e[0] + ")")
46 | return(Data(0, 0, 0))
47 |
48 | while len(items) > 0 and totalitems < twnumber:
49 | if maxid == items[-1].id:
50 | break
51 | maxid = items[-1].id
52 | for item in items:
53 | if totalitems >= twnumber:
54 | break
55 |
56 | if item.coordinates:
57 | gpscoordinates.append({'created_at' : item.created_at, 'lat' : item.coordinates['coordinates'][1], 'lng' : item.coordinates['coordinates'][0]})
58 |
59 | if item.lang in langs:
60 | langs[item.lang] += 1
61 | else:
62 | langs[item.lang] = 1
63 |
64 | hours[datetime.strptime(item.created_at, "%a %b %d %H:%M:%S +0000 %Y").hour] += 1
65 |
66 | totalitems += 1
67 | print("[D] [" + str(totalitems) + "] - "+ str(item.id) + " (" + item.created_at + ") - lang: " + item.lang + " added")
68 | # print(item)
69 |
70 | try:
71 | items = twapi.GetUserTimeline(user_id=userid, count=200, max_id=maxid)
72 | except twitter.TwitterError as e:
73 | print(u"[-] ERROR: (" + e[0] + ")")
74 | return(Data(0, 0, 0))
75 |
76 | print("[D] Got " + str(totalitems) + " tweets")
77 |
78 | print gpscoordinates
79 |
80 | langscountries = []
81 | langsnumbers = []
82 | langsdata = []
83 |
84 | for key in langs.keys():
85 | langscountries.append(key)
86 | langsnumbers.append(langs[key])
87 |
88 | langsdata.append(langscountries)
89 | langsdata.append(langsnumbers)
90 |
91 | return(Data(gpscoordinates, langsdata, hours))
92 |
93 |
94 | @app.route("/")
95 | def index():
96 | return render_template("index.html")
97 |
98 |
99 | @app.route("/contact")
100 | def contact():
101 | return render_template("contact.html")
102 |
103 |
104 | @app.route("/about")
105 | def about():
106 | return render_template("about.html")
107 |
108 |
109 | @app.route("/fail")
110 | def fail():
111 | return render_template("fail.html")
112 |
113 |
114 | @app.route("/report", methods=['GET', 'POST'])
115 | def report():
116 | try:
117 | if request.method == 'POST':
118 | twapi = twitter.Api(consumer_key=YOUR_APP_CONSUMER_KEY,
119 | consumer_secret=YOUR_APP_CONSUMER_SECRET,
120 | access_token_key=YOUR_ACCESS_TOKEN,
121 | access_token_secret=YOUR_ACCESS_TOKEN_SECRET)
122 |
123 | target_user = twapi.GetUser(screen_name=request.form['screen_name'])
124 | userid = target_user.id
125 |
126 | if request.form['nbtweets'] != "":
127 | nbtweets = int(request.form['nbtweets'])
128 | if nbtweets > 2000:
129 | nbtweets = 2000
130 | else:
131 | nbtweets = 1000
132 |
133 | print('[D] Trying to get [' + str(nbtweets) + '] tweets')
134 |
135 | userdetails = {}
136 | userdetails['screen_name'] = target_user.screen_name
137 | userdetails['name'] = target_user.name
138 | userdetails['created_at'] = target_user.created_at
139 | userdetails['location'] = target_user.location
140 | userdetails['utcoffset'] = str(target_user.utc_offset)
141 | userdetails['tz'] = target_user.time_zone
142 | userdetails['lang'] = target_user.lang
143 | userdetails['nbtweets'] = nbtweets
144 |
145 | firstfollowers = []
146 | firstfriends = []
147 |
148 | print('[D] Trying to get the followers')
149 | followersid = twapi.GetFollowerIDs(user_id=userid)
150 | if len(followersid) <= 20:
151 | firstfollowersid = followersid
152 | else:
153 | firstfollowersid = followersid[-21:-1]
154 |
155 | #print('[D] Got ' + str(len(followers)) + ' followers')
156 |
157 | print('[D] Trying to get the friends')
158 |
159 | friendsid = twapi.GetFriendIDs(user_id=userid)
160 | if len(friendsid) <= 20:
161 | firstfriendsid = friendsid
162 | else:
163 | firstfriendsid = friendsid[-21:-1]
164 |
165 | if firstfollowersid:
166 | firstfollowers = twapi.UsersLookup(user_id=firstfollowersid)
167 |
168 | if firstfriendsid:
169 | firstfriends = twapi.UsersLookup(user_id=firstfriendsid)
170 |
171 | userdetails['firstfollowers'] = reversed([x.screen_name for x in firstfollowers])
172 | userdetails['firstfriends'] = reversed([x.screen_name for x in firstfriends])
173 |
174 | # print userdetails['firstfollowers']
175 | # print userdetails['firstfriends']
176 |
177 | # print('[D] Joined Friends/Followers')
178 | # for f in fff:
179 | # print('[D] ' + f.screen_name)
180 |
181 | print('[D] Trying to get [' + str(nbtweets) + '] tweets')
182 | returneddata = getstatuses(twapi, userid, nbtweets)
183 |
184 | return render_template("report.html",
185 | userdetails = userdetails,
186 | gpsdata = returneddata.g,
187 | langsbarchartdata = returneddata.l,
188 | hoursbarchartdata = returneddata.h)
189 | else:
190 | return redirect("/")
191 | except twitter.TwitterError as e:
192 | print e # [0]["message"]
193 | return render_template("fail.html",
194 | error = e[0])
195 |
196 |
197 | if __name__ == "__main__":
198 | app.run()
199 |
--------------------------------------------------------------------------------
/templates/report.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Twintelligence Report {{ userdetails.screen_name }}
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
20 |
89 |
106 |
107 |
108 |
116 |
117 |
118 | {{ userdetails.screen_name }} - {{ userdetails.name }}
119 | Created at {{ userdetails.created_at }}
120 | Location: {{ userdetails.location }} - Language: {{ userdetails.lang }}
121 | UTC Offset: {{ userdetails.utcoffset }} - TimeZone: {{ userdetails.tz }}
122 | {{ userdetails.nbtweets }} tweets analyzed. The above information is declarative.
123 |
124 |
125 |
128 |
129 |
130 |
131 |
138 |
139 |
140 | {% for gps_position in gpsdata %} {{ gps_position.created_at }}: {{ gps_position.lat }}, {{ gps_position.lng }}
{% endfor %}
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
158 |
159 |
160 |
161 |
162 |
163 |
164 | | First followers (Top 20) |
165 |
166 |
167 |
168 | {% for follower in userdetails.firstfollowers %} | @{{ follower }} |
{% endfor %}
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 | | First friends (Top 20) |
179 |
180 |
181 |
182 | {% for friend in userdetails.firstfriends %} | @{{ friend }} |
{% endfor %}
183 |
184 |
185 |
186 |
187 |
188 |
189 |
--------------------------------------------------------------------------------