0
# Notification System
1
2
Pluggable notification handlers for processing and displaying search results. The notification system provides a flexible architecture for customizing how search results are presented to users, supporting various output formats and interaction patterns.
3
4
## Capabilities
5
6
### Base Notification Class
7
8
Abstract base class that defines the notification interface for handling search results during and after the search process.
9
10
```python { .api }
11
class QueryNotify:
12
"""
13
Base class for query result notifications.
14
15
Defines the interface for notifying callers about query results.
16
Intended to be inherited by specific notification implementations.
17
"""
18
19
def __init__(self, result: QueryResult = None):
20
"""
21
Create Query Notify Object.
22
23
Args:
24
result: QueryResult object containing initial results (optional)
25
"""
26
27
result: QueryResult # Current result being processed
28
29
def start(self, message: str = None):
30
"""
31
Notify start of query process.
32
33
Called once before any queries are performed.
34
Override in subclasses for custom start behavior.
35
36
Args:
37
message: Context message for start of query (optional)
38
"""
39
40
def update(self, result: QueryResult):
41
"""
42
Notify query result update.
43
44
Called for each query result as it becomes available.
45
Override in subclasses for custom result processing.
46
47
Args:
48
result: QueryResult object containing results for this query
49
"""
50
51
def finish(self, message: str = None):
52
"""
53
Notify end of query process.
54
55
Called once after all queries have been performed.
56
Override in subclasses for custom finish behavior.
57
58
Args:
59
message: Context message for end of query (optional)
60
"""
61
62
def __str__(self) -> str:
63
"""
64
Convert object to string representation.
65
66
Returns:
67
String representation of current result
68
"""
69
```
70
71
### Print-Based Notification
72
73
Concrete implementation that outputs search results to the console with colorized formatting and optional web browser integration.
74
75
```python { .api }
76
class QueryNotifyPrint(QueryNotify):
77
"""
78
Query notification implementation that prints results to console.
79
80
Provides colorized output with configurable verbosity and filtering options.
81
"""
82
83
def __init__(
84
self,
85
result: QueryResult = None,
86
verbose: bool = False,
87
print_all: bool = False,
88
browse: bool = False
89
):
90
"""
91
Create Query Notify Print Object.
92
93
Args:
94
result: QueryResult object containing initial results (optional)
95
verbose: Boolean indicating whether to show response times and verbose output
96
print_all: Boolean indicating whether to print all sites including not found
97
browse: Boolean indicating whether to open found sites in web browser
98
"""
99
100
verbose: bool # Show detailed output including response times
101
print_all: bool # Show results for all sites, including failures
102
browse: bool # Open found URLs in web browser
103
104
def start(self, message: str):
105
"""
106
Print query start notification.
107
108
Displays colored header with username being searched.
109
110
Args:
111
message: String containing username that queries are about
112
"""
113
114
def update(self, result: QueryResult):
115
"""
116
Print individual query result.
117
118
Displays result with appropriate coloring based on status:
119
- Green for claimed/found accounts
120
- Red for errors and not found (if print_all enabled)
121
- Includes response time if verbose mode enabled
122
- Opens URLs in browser if browse mode enabled
123
124
Args:
125
result: QueryResult object containing results for this query
126
"""
127
128
def finish(self, message: str = "The processing has been finished."):
129
"""
130
Print completion notification.
131
132
Displays summary with total number of accounts found.
133
134
Args:
135
message: Completion message to display
136
"""
137
138
def countResults(self) -> int:
139
"""
140
Count and return number of results found so far.
141
142
Increments global result counter each time called.
143
144
Returns:
145
Integer count of results processed
146
"""
147
148
def __str__(self) -> str:
149
"""
150
Convert object to string representation.
151
152
Returns:
153
String representation of current result
154
"""
155
```
156
157
### Global Variables
158
159
```python { .api }
160
globvar: int # Global variable to count the number of results
161
```
162
163
## Usage Examples
164
165
### Basic Console Output
166
167
```python
168
from sherlock_project.sherlock import sherlock
169
from sherlock_project.notify import QueryNotifyPrint
170
from sherlock_project.sites import SitesInformation
171
172
# Create basic console notification handler
173
notify = QueryNotifyPrint()
174
175
# Load sites and perform search
176
sites = SitesInformation()
177
results = sherlock("john_doe", sites.sites, notify)
178
179
# Output will automatically be printed during search:
180
# [*] Checking username john_doe on:
181
# [+] GitHub: https://github.com/john_doe
182
# [+] Twitter: https://twitter.com/john_doe
183
# [*] Search completed with 2 results
184
```
185
186
### Verbose Output with Timing
187
188
```python
189
# Enable verbose mode to show response times
190
notify = QueryNotifyPrint(verbose=True)
191
192
results = sherlock("username", sites.sites, notify)
193
194
# Output includes timing information:
195
# [+] [245ms] GitHub: https://github.com/username
196
# [+] [1.2s] Twitter: https://twitter.com/username
197
```
198
199
### Show All Results Including Failures
200
201
```python
202
# Show all sites including those where username was not found
203
notify = QueryNotifyPrint(print_all=True, verbose=True)
204
205
results = sherlock("username", sites.sites, notify)
206
207
# Output shows all attempted sites:
208
# [+] [245ms] GitHub: https://github.com/username
209
# [-] [180ms] Instagram: Not Found!
210
# [-] Facebook: Connection Error
211
# [+] [320ms] Twitter: https://twitter.com/username
212
```
213
214
### Auto-Open Found Accounts in Browser
215
216
```python
217
# Automatically open found profiles in web browser
218
notify = QueryNotifyPrint(browse=True, verbose=True)
219
220
results = sherlock("username", sites.sites, notify)
221
222
# Found URLs will automatically open in default web browser
223
```
224
225
### Custom Notification Handler
226
227
```python
228
from sherlock_project.notify import QueryNotify
229
from sherlock_project.result import QueryStatus
230
import logging
231
232
class QueryNotifyLogger(QueryNotify):
233
"""Custom notification handler that logs results."""
234
235
def __init__(self):
236
super().__init__()
237
logging.basicConfig(level=logging.INFO)
238
self.logger = logging.getLogger('sherlock')
239
self.found_count = 0
240
241
def start(self, message):
242
self.logger.info(f"Starting search for username: {message}")
243
self.found_count = 0
244
245
def update(self, result):
246
if result.status == QueryStatus.CLAIMED:
247
self.found_count += 1
248
self.logger.info(f"FOUND: {result.site_name} - {result.site_url_user}")
249
elif result.status == QueryStatus.UNKNOWN:
250
self.logger.warning(f"ERROR: {result.site_name} - {result.context}")
251
252
def finish(self, message=None):
253
self.logger.info(f"Search completed. Found {self.found_count} accounts.")
254
255
# Use custom handler
256
custom_notify = QueryNotifyLogger()
257
results = sherlock("username", sites.sites, custom_notify)
258
```
259
260
### Silent Notification Handler
261
262
```python
263
class QueryNotifySilent(QueryNotify):
264
"""Notification handler that collects results without output."""
265
266
def __init__(self):
267
super().__init__()
268
self.results = []
269
self.start_time = None
270
271
def start(self, message):
272
import time
273
self.start_time = time.time()
274
self.results = []
275
276
def update(self, result):
277
self.results.append({
278
'site': result.site_name,
279
'username': result.username,
280
'status': result.status.value,
281
'url': result.site_url_user,
282
'response_time': result.query_time,
283
'context': result.context
284
})
285
286
def finish(self, message=None):
287
import time
288
total_time = time.time() - self.start_time
289
claimed = len([r for r in self.results if r['status'] == 'Claimed'])
290
print(f"Silent search completed: {claimed} accounts found in {total_time:.2f}s")
291
292
# Use for batch processing without console spam
293
silent_notify = QueryNotifySilent()
294
results = sherlock("username", sites.sites, silent_notify)
295
296
# Access collected results
297
for result in silent_notify.results:
298
if result['status'] == 'Claimed':
299
print(f"Found: {result['site']} - {result['url']}")
300
```
301
302
### File Export Notification Handler
303
304
```python
305
import json
306
from datetime import datetime
307
308
class QueryNotifyFileExport(QueryNotify):
309
"""Notification handler that exports results to file."""
310
311
def __init__(self, output_file="sherlock_results.json"):
312
super().__init__()
313
self.output_file = output_file
314
self.session_data = {
315
'timestamp': datetime.now().isoformat(),
316
'results': []
317
}
318
319
def start(self, message):
320
self.session_data['username'] = message
321
print(f"Searching for {message}...")
322
323
def update(self, result):
324
self.session_data['results'].append({
325
'site_name': result.site_name,
326
'username': result.username,
327
'url': result.site_url_user,
328
'status': result.status.value,
329
'query_time': result.query_time,
330
'context': result.context
331
})
332
333
# Print only found accounts
334
if result.status == QueryStatus.CLAIMED:
335
print(f"✓ {result.site_name}: {result.site_url_user}")
336
337
def finish(self, message=None):
338
# Save results to file
339
with open(self.output_file, 'w') as f:
340
json.dump(self.session_data, f, indent=2)
341
342
claimed = len([r for r in self.session_data['results'] if r['status'] == 'Claimed'])
343
print(f"Search completed. {claimed} accounts found.")
344
print(f"Results saved to {self.output_file}")
345
346
# Use for automated result collection
347
export_notify = QueryNotifyFileExport("john_doe_results.json")
348
results = sherlock("john_doe", sites.sites, export_notify)
349
```