├── .github
└── dependabot.yml
├── LICENSE
├── README.md
├── logo.jpg
├── requirements.txt
└── ya_seeker.py
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "pip" # See documentation for possible values
4 | directory: "/" # Location of package manifests
5 | schedule:
6 | interval: "daily"
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Soxoj
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # YaSeeker
2 |
3 |
4 |
5 |
6 |
7 | ## Description
8 |
9 | YaSeeker - an OSINT tool to get info about any Yandex account using email or login.
10 |
11 | It can find:
12 | - Fullname
13 | - Photo
14 | - Gender
15 | - Yandex UID
16 | - Yandex Public ID
17 | - Linked social accounts
18 | - Activity (count of reviews, comments; subscribers and subscriptions)
19 | - Account features (is it verified, banned, deleted, etc.)
20 |
21 | Checked Yandex services: Music, Collections, Bugbounty, Reviews, Q (Znatoki), O (Classified), Zen, Market, Messenger.
22 |
23 | ## Installation
24 |
25 | Python 3.6+ and pip are required.
26 |
27 | pip3 install -r requirements.txt
28 |
29 | ## Usage
30 |
31 | ```bash
32 | $ python3 ya_seeker.py login
33 | [*] Get info by username `login`...
34 |
35 | [+] Yandex.Collections
36 | URL: https://yandex.ru/collections/user/login/
37 | Yandex_public_id: c48fhxw0qppa50289r5c9ku4k4
38 | Fullname: haxxor elite
39 | Image: https://avatars.mds.yandex.net/get-yapic/24700/enc-0f504b0d68d5f6fb0d336e2157b44e88ef2225aff6a621016f4dccad990b5d3e/islands-200
40 | Likes: 0
41 | Cards: 0
42 | Boards: 0
43 | Is_passport: True
44 | Is_restricted: False
45 | Is_forbid: False
46 | Is_km: False
47 | Is_business: False
48 |
49 | [+] Yandex.Music
50 | URL: https://music.yandex.ru/users/login/playlists
51 | Yandex_uid: 266797119
52 | Username: login
53 | ...
54 |
55 | $ python3 ya_seeker.py c48fhxw0qppa50289r5c9ku4k4 yandex_public_id
56 | [*] Get info by yandex_public_id `c48fhxw0qppa50289r5c9ku4k4`...
57 |
58 | [+] Yandex.Collections API
59 | URL: https://yandex.ru/collections/user/c48fhxw0qppa50289r5c9ku4k4/
60 | Yandex_public_id: c48fhxw0qppa50289r5c9ku4k4
61 | Fullname: haxxor elite
62 | Image: https://avatars.mds.yandex.net/get-yapic/24700/enc-0f504b0d68d5f6fb0d336e2157b44e88ef2225aff6a621016f4dccad990b5d3e/islands-200
63 | Likes: 0
64 | Cards: 0
65 | Boards: 0
66 | Is_passport: True
67 | Is_restricted: False
68 | Is_forbid: False
69 | Is_km: False
70 | Is_business: False
71 |
72 | [+] Yandex.Reviews
73 | URL: https://reviews.yandex.ru/user/c48fhxw0qppa50289r5c9ku4k4
74 | Yandex_public_id: c48fhxw0qppa50289r5c9ku4k4
75 | ...
76 | ```
77 |
78 | ## Cookies
79 |
80 | Some services are required cookies for API requests. Follow next steps to use your cookies for YaSeeker:
81 | 1. Login into Yandex through your browser.
82 | 1. Install any extension to download all the Ya cookies in Netscape format aka cookies.txt ([Chrome](https://chrome.google.com/webstore/detail/get-cookiestxt/bgaddhkoddajcdgocldbbfleckgcbcid), [Firefox](https://addons.mozilla.org/en-US/firefox/addon/cookies-txt/)).
83 | 1. Save it to the directory of YaSeeker in file `cookies.txt`.
84 | 1. Run script and enjoy!
--------------------------------------------------------------------------------
/logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HowToFind-bot/YaSeeker/fd2ff602288cfedfe0706922c0811bba5f630918/logo.jpg
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | socid-extractor>=0.0.8
2 |
--------------------------------------------------------------------------------
/ya_seeker.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | import json
3 | import os
4 | import sys
5 | from http.cookiejar import MozillaCookieJar
6 |
7 | import requests
8 | from socid_extractor import extract
9 |
10 | HEADERS = {
11 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36',
12 | }
13 |
14 | COOKIES_FILENAME = 'cookies.txt'
15 |
16 |
17 | def load_cookies(filename):
18 | cookies = {}
19 | if os.path.exists(filename):
20 | cookies_obj = MozillaCookieJar(filename)
21 | cookies_obj.load(ignore_discard=False, ignore_expires=False)
22 |
23 | for domain in cookies_obj._cookies.values():
24 | for cookie_dict in list(domain.values()):
25 | for _, cookie in cookie_dict.items():
26 | cookies[cookie.name] = cookie.value
27 |
28 | return cookies
29 |
30 |
31 | class IdTypeInfoAggregator:
32 | acceptable_fields = ()
33 |
34 | def __init__(self, identifier: str, cookies: dict):
35 | self.identifier = identifier
36 | self.cookies = cookies
37 | self.info = {}
38 | self.sites_results = {}
39 |
40 | @classmethod
41 | def validate_id(cls, name, identifier):
42 | return name in cls.acceptable_fields
43 |
44 | def aggregate(self, info: dict):
45 | for k, v in info.items():
46 | if k in self.info:
47 | if isinstance(self.info[k], set):
48 | self.info[k].add(v)
49 | else:
50 | self.info[k] = {self.info[k], v}
51 | else:
52 | self.info[k] = v
53 |
54 | def simple_get_info_request(self, url: str, headers_updates: dict = None, orig_url: str = None) -> dict:
55 | headers = dict(HEADERS)
56 | headers.update(headers_updates if headers_updates else {})
57 | r = requests.get(url, headers=headers, cookies=self.cookies)
58 |
59 | if 'enter_captcha_value' in r.text:
60 | info = {'Error': 'Captcha detected'}
61 | else:
62 | try:
63 | info = extract(r.text)
64 | except Exception as e:
65 | print(f'Error for URL {url}: {e}\n')
66 | info = {}
67 |
68 | if info:
69 | info['URL'] = orig_url or url
70 | return info
71 |
72 | def collect(self):
73 | for f in self.__dir__():
74 | if f.startswith('get_'):
75 | info = getattr(self, f)()
76 | name = ' '.join(f.split('_')[1:-1])
77 | self.sites_results[name] = info
78 | self.aggregate(info)
79 |
80 | def print(self):
81 | for sitename, data in self.sites_results.items():
82 | print('[+] Yandex.' + sitename[0].upper() + sitename[1:])
83 | if not data:
84 | print('\tNot found.\n')
85 | continue
86 |
87 | if 'URL' in data:
88 | print(f'\tURL: {data.get("URL")}')
89 | for k, v in data.items():
90 | if k != 'URL':
91 | print('\t' + k.capitalize() + ': ' + v)
92 | print()
93 |
94 |
95 | class YaUsername(IdTypeInfoAggregator):
96 | acceptable_fields = ('username',)
97 |
98 | def get_collections_API_info(self) -> dict:
99 | return self.simple_get_info_request(
100 | url=f'https://yandex.ru/collections/api/users/{self.identifier}',
101 | orig_url=f'https://yandex.ru/collections/user/{self.identifier}/'
102 | )
103 |
104 | def get_music_info(self) -> dict:
105 | orig_url = f'https://music.yandex.ru/users/{self.identifier}/playlists'
106 | referer = {'referer': orig_url}
107 | return self.simple_get_info_request(
108 | url=f'https://music.yandex.ru/handlers/library.jsx?owner={self.identifier}',
109 | orig_url=orig_url,
110 | headers_updates=referer,
111 | )
112 |
113 | def get_bugbounty_info(self) -> dict:
114 | return self.simple_get_info_request(f'https://yandex.ru/bugbounty/researchers/{self.identifier}/')
115 |
116 | def get_messenger_search_info(self) -> dict:
117 | url = 'https://yandex.ru/messenger/api/registry/api/'
118 | data = {"method": "search",
119 | "params": {"query": self.identifier, "limit": 10, "entities": ["messages", "users_and_chats"]}}
120 | r = requests.post(url, headers=HEADERS, cookies=self.cookies, files={'request': (None, json.dumps(data))})
121 | info = extract(r.text)
122 | if info and info.get('yandex_messenger_guid'):
123 | info['URL'] = f'https://yandex.ru/chat#/user/{info["yandex_messenger_guid"]}'
124 | return info
125 |
126 | def get_music_API_info(self) -> dict:
127 | return self.simple_get_info_request(f'https://api.music.yandex.net/users/{self.identifier}')
128 |
129 |
130 | class YaPublicUserId(IdTypeInfoAggregator):
131 | acceptable_fields = ('yandex_public_id', 'id',)
132 |
133 | @classmethod
134 | def validate_id(cls, name, identifier):
135 | return len(identifier) == 26 and name in cls.acceptable_fields
136 |
137 | def get_collections_API_info(self) -> dict:
138 | return self.simple_get_info_request(
139 | url=f'https://yandex.ru/collections/api/users/{self.identifier}',
140 | orig_url=f'https://yandex.ru/collections/user/{self.identifier}/'
141 | )
142 |
143 | def get_reviews_info(self) -> dict:
144 | return self.simple_get_info_request(f'https://reviews.yandex.ru/user/{self.identifier}')
145 |
146 | def get_znatoki_info(self) -> dict:
147 | return self.simple_get_info_request(f'https://yandex.ru/q/profile/{self.identifier}/')
148 |
149 | def get_zen_info(self) -> dict:
150 | return self.simple_get_info_request(f'https://zen.yandex.ru/user/{self.identifier}')
151 |
152 | def get_market_info(self) -> dict:
153 | return self.simple_get_info_request(f'https://market.yandex.ru/user/{self.identifier}/reviews')
154 |
155 | def get_o_info(self) -> dict:
156 | return self.simple_get_info_request(f'http://o.yandex.ru/profile/{self.identifier}/')
157 |
158 |
159 | class YaMessengerGuid(IdTypeInfoAggregator):
160 | acceptable_fields = ('yandex_messenger_guid',)
161 |
162 | @classmethod
163 | def validate_id(cls, name, identifier):
164 | return len(identifier) == 36 and '-' in identifier and name in cls.acceptable_fields
165 |
166 | def get_messenger_info(self) -> dict:
167 | url = 'https://yandex.ru/messenger/api/registry/api/'
168 | data = {"method": "get_users_data", "params": {"guids": [self.identifier]}}
169 | r = requests.post(url, headers=HEADERS, cookies=self.cookies, files={'request': (None, json.dumps(data))})
170 | info = extract(r.text)
171 | if info:
172 | info['URL'] = f'https://yandex.ru/chat#/user/{self.identifier}'
173 | return info
174 |
175 |
176 | def crawl(user_data: dict, cookies: dict = None, checked_values: list = None):
177 | entities = (YaUsername, YaPublicUserId, YaMessengerGuid)
178 | if cookies is None:
179 | cookies = {}
180 | if checked_values is None:
181 | checked_values = []
182 | for k, v in user_data.items():
183 | values = list(v) if isinstance(v, set) else [v]
184 | for value in values:
185 | if value in checked_values:
186 | continue
187 |
188 | for e in entities:
189 | if not e.validate_id(k, value):
190 | continue
191 |
192 | checked_values.append(value)
193 |
194 | print(f'[*] Get info by {k} `{value}`...\n')
195 | entity_obj = e(value, cookies)
196 | entity_obj.collect()
197 | entity_obj.print()
198 |
199 | crawl(entity_obj.info, cookies, checked_values)
200 |
201 |
202 | def main():
203 | identifier_type = 'username'
204 |
205 | if len(sys.argv) > 1:
206 | identifier = sys.argv[1]
207 | if len(sys.argv) > 2:
208 | identifier_type = sys.argv[2]
209 | else:
210 | identifier = input('Enter Yandex username / login / email: ')
211 |
212 | cookies = load_cookies(COOKIES_FILENAME)
213 | if not cookies:
214 | print(f'Cookies not found, but are required for some sites. See README to learn how to use cookies.')
215 |
216 | user_data = {identifier_type: identifier.split('@')[0]}
217 |
218 | crawl(user_data, cookies)
219 |
220 |
221 | if __name__ == '__main__':
222 | main()
223 |
--------------------------------------------------------------------------------