or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-search.mdindex.mdnotification-system.mdresult-management.mdsite-management.md

notification-system.mddocs/

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

```