gitrecon
Version:
This CLI tool is designed to retrieve exposed email addresses from a GitHub user’s public activity and to identify a GitHub username associated with a given email address. It is intended strictly for educational use and ethical security research. Please u
182 lines (155 loc) • 6.82 kB
JavaScript
// GitHub API specific functions
const ApiUtils = require('../../utils/apiUtils');
const ColorUtils = require('../../utils/colors');
const { API_URL } = require('../../config/constants');
const { Repository } = require('../../config/settings');
// Function to retrieve user's repositories - orijinal koddan
const getRepositories = async (username) => {
const repositoriesSeen = new Set();
const repositories = [];
let pageCounter = 1;
while (true) {
let continueLoop = true;
// Construct the URL for fetching repositories
const url = `${API_URL}/users/${username}/repos?per_page=100&page=${pageCounter}`;
const result = await ApiUtils.call(url); if ('message' in result || result.error || !Array.isArray(result)) {
if (result.message && result.message.includes('API rate limit exceeded for ')) {
console.warn('API rate limit exceeded - not all repos were fetched');
break;
}
if (result.message === 'Not Found') {
console.warn(`There is no user with the username "${username}"`);
break;
}
// If there's any other error, break the loop
console.warn(ColorUtils.yellow(`Error fetching repositories: ${result.message || 'Unknown error'}`));
break;
}
// Process each repository in the result
if (Array.isArray(result)) {
for (const repository of result) {
const repoName = repository.name;
if (repositoriesSeen.has(repoName)) {
continueLoop = false;
break;
} else {
repositories.push(Repository(repoName, repository.fork));
repositoriesSeen.add(repoName);
}
}
} else {
// If result is not an array, we can't process it
break;
}
if (continueLoop && Array.isArray(result) && result.length === 100) {
pageCounter += 1;
} else {
break;
}
}
return repositories;
};
// Function to retrieve email addresses from a repository's commits
const getEmails = async (username, repoName) => {
const emailsToName = new Map();
const seenCommits = new Set();
let pageCounter = 1;
let commitCounter = 1;
while (true) {
let continueLoop = true;
const url = `${API_URL}/repos/${username}/${repoName}/commits?per_page=100&page=${pageCounter}`;
const result = await ApiUtils.call(url); if ('message' in result || result.error || !Array.isArray(result)) {
if (result.message === 'Git Repository is empty.' || result.message === 'No commit found') {
console.info(ColorUtils.yellow(`Repository ${repoName} is empty - skipping`));
return emailsToName;
}
if (result.message && result.message.includes('API rate limit exceeded for ')) {
console.warn('API rate limit exceeded');
return emailsToName;
}
if (result.message === 'Not Found') {
console.warn(`Repository Not Found: "${repoName}"`);
return emailsToName;
}
// If there's any other error, return what we have
console.warn(ColorUtils.yellow(`Error fetching commits for ${repoName}: ${result.message || 'Unknown error'}`));
return emailsToName;
}
// Process each commit in the result
if (Array.isArray(result)) {
for (const commit of result) {
const sha = commit.sha;
if (seenCommits.has(sha)) {
continueLoop = false;
break;
}
seenCommits.add(sha);
// console.info(`Scanning commit -> ${commitCounter}`);
commitCounter += 1;
if (!commit.author) {
continue;
}
const user = commit.author.login;
if (user.toLowerCase() === username.toLowerCase()) {
const { author, committer } = commit.commit;
const authorName = author.name;
const authorEmail = author.email;
const committerName = committer.name;
const committerEmail = committer.email;
if (authorEmail) {
if (!emailsToName.has(authorEmail)) {
emailsToName.set(authorEmail, new Set());
}
emailsToName.get(authorEmail).add(authorName);
}
if (committerEmail) {
if (!emailsToName.has(committerEmail)) {
emailsToName.set(committerEmail, new Set());
}
emailsToName.get(committerEmail).add(committerName);
}
}
}
} else {
// If result is not an array, we can't process it
break;
}
if (continueLoop && Array.isArray(result) && result.length === 100) {
pageCounter += 1;
} else {
break;
}
}
return emailsToName;
};
class GitHubApi {
static getRepositories = getRepositories;
static getEmails = getEmails;
// User profile methods
static async getUserProfile(username) {
return await ApiUtils.call(`${API_URL}/users/${username}`);
}
static async getUserOrganizations(username) {
return await ApiUtils.call(`${API_URL}/users/${username}/orgs`);
}
static async getUserKeys(username) {
return await ApiUtils.call(`${API_URL}/users/${username}/keys`);
}
static async getRateLimit() {
return await ApiUtils.call(`${API_URL}/rate_limit`);
}
// Organization methods
static async getOrganization(orgName) {
return await ApiUtils.call(`${API_URL}/orgs/${orgName}`);
}
static async getOrganizationMembers(orgName) {
return await ApiUtils.call(`${API_URL}/orgs/${orgName}/members?per_page=100`);
}
static async getOrganizationRepos(orgName) {
return await ApiUtils.call(`${API_URL}/orgs/${orgName}/repos?per_page=100`);
}
static async getRepoCommits(orgName, repoName, page = 1) {
return await ApiUtils.call(`${API_URL}/repos/${orgName}/${repoName}/commits?per_page=100&page=${page}`);
}
}
module.exports = GitHubApi;