Skip to content

Commit

Permalink
implement hibp, alter auth, diff pkg structure
Browse files Browse the repository at this point in the history
  • Loading branch information
ax-i-om committed Oct 11, 2023
1 parent e0cf625 commit b0e9394
Show file tree
Hide file tree
Showing 41 changed files with 1,105 additions and 1,523 deletions.
3 changes: 0 additions & 3 deletions .env

This file was deleted.

84 changes: 17 additions & 67 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
<a><img src="./images/bitcrook.png" width=180 height="180"></a>
<h1 align="center">Bitcrook</h1>
<p align="center">
<a href="https://pkg.go.dev/github.com/ax-i-om/bitcrook"><img src="https://pkg.go.dev/badge/github.com/ax-i-om/tempest.svg" alt="Documentation"></a>
<a href="https://goreportcard.com/report/github.com/ax-i-om/bitcrook"><img src="https://goreportcard.com/badge/github.com/ax-i-om/bitcrook" alt="Go Report Card"></a>
<a><img src="https://img.shields.io/badge/tests-nil&#47;nil-orange.svg" alt="Tests"></a>
<a><img src="https://img.shields.io/badge/version-1.0.0-blue.svg" alt="v1.0.0"></a><br>
<a><img src="https://img.shields.io/badge/tests-8&#47;8-green.svg" alt="Tests"></a>
<a><img src="https://img.shields.io/badge/version-2.0.0-blue.svg" alt="v2.0.0"></a><br>
<a href="https://app.deepsource.com/gh/ax-i-om/bitcrook/" target="_blank"><img alt="DeepSource" title="DeepSource" src="https://app.deepsource.com/gh/ax-i-om/bitcrook.svg/?label=active+issues&show_trend=true"/></a><br>
Centralize and expedite OSINT investigations<br>
<a href="https://github.com/users/ax-i-om/projects/1">View the roadmap</a><br>
</a>
Expand All @@ -25,14 +27,6 @@
- [GUI](#gui)
- [Docker](#docker)
- [Authentication](#authentication)
- [Package Types](#package-types) *a-z*
- [Court Cases](#court-cases)
- [Discord](#discord)
- [IP Address](#ip-address)
- [Multi-Use](#multi-use)
- [Tax ID](#tax-id)
- [Username](#username)
- [Vehicle](#vehicle)

## Information

Expand All @@ -46,15 +40,15 @@ It is the end user's responsibility to obey all applicable local, state, and fed

### Changelog

Bitcrook v1.0.0 has been released as of October 10, 2023! Here are some of the highlights:
Bitcrook v2.0.0 has been released as of October 11, 2023, only one day after v1.0.0 due to some significant changes to project structure.

- Switch web framework from Fiber to Go (enabled Bitcrook to be more lightweight)
- Completely revamped the CLI output scheme
- Switched secret configuration from .json to .env
- Enabled API key support in web app
- Fixed CORS error when accessing web app over LAN
- Proper docker implementation
- Binary release to support `go install`
- Username lookup command now only displays valid results
- Packages now grouped based on field type rather than authentication type
- Added HaveIBeenPwned breach check to email and domain lookup commands
- Altered .env support, see [Authentication](#authentication)
- Fixed tests and some documentation
- Bug fixes and general optimizations
- Removed Caselaw package due to instability, will replace

Although this release hasn't changed much of the foundations of Bitcrook, it does illuminate
a path of where it will be taken next.
Expand Down Expand Up @@ -103,58 +97,14 @@ You can also host the Bitcrook webapp via docker:

### Authentication

Some packages require an API key. Bitcrook will run without specifying any API keys; however, if you would like to implement these functionalites, create a file named `.env` in the Bitcrook root directory and format it like so:
Some packages require an API key. Bitcrook will run without specifying any API keys; however, if you would like to implement these functionalites, create a file named `.env` and format it like so:

``` conf
BITCROOK_MLSA=UNSPECIFIED # Melissa API key
BITCROOK_HIBP=UNSPECIFIED # HaveIBeenPwned API key
BITCROOK_IPTL=UNSPECIFIED # IP2Location API key
BITCROOK_MLSA=UNSPECIFIED
BITCROOK_HIBP=UNSPECIFIED
BITCROOK_IPTL=UNSPECIFIED
```

Replace the instances of `UNSPECIFIED` with the corresponding API key.

## Package-Types

### Court Cases

| Package | Description | Auth | Location | Status |
| :-----------------: | -------------------------------------------- | :------: | -------- | :----: |
| CaseLaw | Court Case Search | `none` | US | Functioning |

### Discord

| Package | Description | Auth | Location | Status |
| :----------------------------: | -------------------------------------------- | :------: | -------- | :----: |
| Discord Token Lookup | Returns information regarding the passed token. | `none` | Global | Functioning |

### IP Address

| Package | Description | Auth | Location | Status |
| :---------------------: | -------------------------------------------- | :------: | -------- | :----: |
| IPV4 Address Lookup | IPV4 Address Lookup | `none` | Global | Functioning |

### Multi-Use

| Package | Description | Auth | Location | Status |
| :----------------------------: | -------------------------------------------- | :------: | -------- | :----: |
| Have I Been Pwned | Email and Password Vulnerability - (Breaches)| `paid` | Global | Functioning |
| Melissa | Lookups - Email, Phone Number, IP Address | `free` | US | Functioning |
| IP2LOCATION | Whois Lookup, IP Lookup | `free` | - | Functioning |

### Tax ID

| Package | Description | Auth | Location | Status |
| :------------: | -------------------------------------------- | :------: | -------- | :----: |
| Tax ID Lookup | Returns public information regarding a Russian INN. | `none` | Russia | Functioning |

### Username

| Package | Description | Auth | Location | Status |
| :-------------: | -------------------------------------------- | :------: | -------- | :----: |
| Username Lookup | Username Lookup - (Comparable to Sherlock) | `none` | Global | Functioning |

### Vehicle

| Package | Description | Auth | Location | Status |
| :--------------: | -------------------------------------------- | :------: | -------- | :----: |
| VIN Lookup | Vehicle Identification Number Lookup | `none` | - | Functioning |
From top to bottom, these environment variables should correspond with the API keys for the services Melissa, HaveIBeenPwned, and IP2Location. Insure that the environnment variables are passed/exported after making any changes. For Docker, append `--env-file .env` to the arguments. In Linux, run the command: `export $(xargs <.env)`. Results may vary depending on your operating system/shell.
20 changes: 10 additions & 10 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ import (
"os"

"github.com/TwiN/go-color"
"github.com/ax-i-om/bitcrook/pkg/authfree/ip2location"
"github.com/ax-i-om/bitcrook/pkg/noauth/discord"
"github.com/ax-i-om/bitcrook/pkg/noauth/ip"
"github.com/ax-i-om/bitcrook/pkg/noauth/tin"
"github.com/ax-i-om/bitcrook/pkg/noauth/userlookup"
"github.com/ax-i-om/bitcrook/pkg/noauth/vin"
"github.com/ax-i-om/bitcrook/pkg/discord"
"github.com/ax-i-om/bitcrook/pkg/domain"
"github.com/ax-i-om/bitcrook/pkg/ip"
"github.com/ax-i-om/bitcrook/pkg/tin"
"github.com/ax-i-om/bitcrook/pkg/userlookup"
"github.com/ax-i-om/bitcrook/pkg/vin"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
Expand All @@ -42,7 +42,7 @@ func StartServer() {
e.Use(middleware.Static("./api/static"))

e.GET("/ip/:ip", func(c echo.Context) error {
ipInfo, err := ip.IPLookup(c.Param("ip"))
ipInfo, err := ip.IPAPILookup(c.Param("ip"))
if err != nil {
return c.JSON(http.StatusInternalServerError, err)
}
Expand All @@ -54,23 +54,23 @@ func StartServer() {
})

e.GET("/vin/:vin", func(c echo.Context) error {
vinInfo, err := vin.VinLookup(c.Param("vin"))
vinInfo, err := vin.VFCLookup(c.Param("vin"))
if err != nil {
return c.JSON(http.StatusInternalServerError, err)
}
return c.JSON(http.StatusOK, vinInfo)
})

e.GET("/discord/:discord", func(c echo.Context) error {
discordInfo, err := discord.TokenLookup((c.Param("discord")))
discordInfo, err := discord.TokenLookup(c.Param("discord"))
if err != nil {
return c.JSON(http.StatusInternalServerError, err)
}
return c.JSON(http.StatusOK, discordInfo)
})

e.GET("/domain/:domain", func(c echo.Context) error {
domainInfo, err := ip2location.DomainLookup(os.Getenv("BITCROOK_IPTL"), c.Param("domain"))
domainInfo, err := domain.IPTLLookup(os.Getenv("BITCROOK_IPTL"), c.Param("domain"))
if err != nil {
return c.JSON(http.StatusInternalServerError, err)
}
Expand Down
95 changes: 62 additions & 33 deletions api/static/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,34 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/**
* Function to add a row of information with a light background to a results table
* @param table The result table where the row will be added
* @param key The key to be used
* @param value The value to be used
* @returns Nothing
*/
function addLight(table, key, value) {
table.innerHTML += "<span style='background-color: #4b4b4b; display:flex; padding: 5px; justify-content: center'>" + "<strong>" + key + ":&nbsp;</strong>" + value + "</span>";
table.innerHTML += `<span style='background-color: #4b4b4b; display:flex; padding: 5px; justify-content: center'><strong>${key}:&nbsp;</strong>${value}</span>`;
}

/**
* Function to add a row of information with a dark background to a results table
* @param table The result table where the row will be added
* @param key The key to be used
* @param value The value to be used
* @returns Nothing
*/
function addDark(table, key, value) {
table.innerHTML += "<span style='display:flex; padding: 5px; justify-content: center'>" + "<strong>" + key + ":&nbsp;</strong>" + value + "</span>";
table.innerHTML += `<span style='display:flex; padding: 5px; justify-content: center'><strong>${key}:&nbsp;</strong>${value}</span>`;
}

/**
* Function to a gap to a results table
* @param table The result table where the row will be added
* @returns Nothing
*/
function addGap(table) {
table.innerHTML += "<br><br>"
}
Expand All @@ -29,8 +49,8 @@ $('#ipsearch').on('click', () => {
ip = $('#ip').val()
if (ip) {
$('#iploadercircle').addClass('loader');
$.getJSON('/ip/' + ip, (res) => {
let iptable = document.getElementById('ipresult');
$.getJSON(`/ip/${ip}`, (res) => {
const iptable = document.getElementById('ipresult');
iptable.innerHTML = "";
$('#iploadercircle').removeClass('loader');
addLight(iptable, "Status", res.status)
Expand All @@ -55,7 +75,7 @@ $('#ipsearch').on('click', () => {
})
$('#ipresult').val('')
} else {
let iptable = document.getElementById('ipresult');
const iptable = document.getElementById('ipresult');
iptable.innerHTML = "";
addLight(iptable, "Error", "IP address field was left empty")
}
Expand All @@ -65,31 +85,31 @@ $('#usernamesearch').on('click', () => {
username = $('#username').val()
if (username) {
$('#userloadercircle').addClass('loader');
let usernametable = document.getElementById('usernameresult');
const usernametable = document.getElementById('usernameresult');
usernametable.innerHTML = "";
$.getJSON('/username/' + username, (res) => {
$.getJSON(`/username/${username}`, (res) => {
let recentswap = false;
$('#userloadercircle').removeClass('loader');
for(let i = 0; i < res.length; i++) {
let obj = res[i];
const obj = res[i];
if (obj.Valid) {
if (recentswap) {
usernametable.innerHTML += "<span style='display:flex; padding: 5px; justify-content: center'>" + "<strong>" + obj.Title + ":&nbsp;</strong>" + "<a>" + obj.Domain + "</a>" + "</span>";
$(function(){ $('a:contains(' + obj.Domain + ')').attr("href", obj.Domain)});
$(function(){ $('a:contains(' + obj.Domain + ')').attr("target", "_blank")});
usernametable.innerHTML += `<span style='display:flex; padding: 5px; justify-content: center'><strong>${obj.Title}:&nbsp;</strong><a>${obj.Domain}</a></span>`;
$(function(){ $(`a:contains(${obj.Domain})`).attr("href", obj.Domain)});
$(function(){ $(`a:contains(${obj.Domain})`).attr("target", "_blank")});
recentswap = false;
} else {
usernametable.innerHTML += "<span style='background-color: #4b4b4b; display:flex; padding: 5px; justify-content: center'>" + "<strong>" + obj.Title + ":&nbsp;</strong>" + "<a>" + obj.Domain + "</a>" + "</span>";
$(function(){ $('a:contains(' + obj.Domain + ')').attr("href", obj.Domain)});
$(function(){ $('a:contains(' + obj.Domain + ')').attr("target", "_blank")});
usernametable.innerHTML += `<span style='background-color: #4b4b4b; display:flex; padding: 5px; justify-content: center'><strong>${obj.Title}:&nbsp;</strong><a>${obj.Domain}</a></span>`;
$(function(){ $(`a:contains(${obj.Domain})`).attr("href", obj.Domain)});
$(function(){ $(`a:contains(${obj.Domain})`).attr("target", "_blank")});
recentswap = true;
}
}
}
})
$('#usernameresult').val('')
} else {
let usernametable = document.getElementById('usernameresult');
const usernametable = document.getElementById('usernameresult');
usernametable.innerHTML = "";
addLight(usernametable, "Error", "Username field was left empty")
}
Expand All @@ -98,8 +118,8 @@ $('#usernamesearch').on('click', () => {
$('#vinsearch').on('click', () => {
$('#vinloadercircle').addClass('loader');
vin = $('#vin').val()
$.getJSON('/vin/' + vin, (res) => {
let vintable = document.getElementById('vinresult');
$.getJSON(`/vin/${vin}`, (res) => {
const vintable = document.getElementById('vinresult');
vintable.innerHTML = "";
$('#vinloadercircle').removeClass('loader');
addLight(vintable, "VIN", res.Vin)
Expand Down Expand Up @@ -132,9 +152,9 @@ $('#domainsearch').on('click', () => {
domain = $('#domain').val()
if (domain) {
$('#domainloadercircle').addClass('loader');
$.getJSON('/domain/' + domain, (res) => {
$.getJSON(`/domain/${domain}`, (res) => {
$('#domainloadercircle').removeClass('loader');
let domaintable = document.getElementById('domainresult');
const domaintable = document.getElementById('domainresult');
domaintable.innerHTML = "";
addLight(domaintable, "Domain", res.domain)
addDark(domaintable, "Domain ID", res.domain_id)
Expand Down Expand Up @@ -189,7 +209,7 @@ $('#domainsearch').on('click', () => {

addGap(domaintable)

addLight(domaintable, "Billing Name", res.billings.name)
addLight(domaintable, "Billing Name", res.billing.name)
addDark(domaintable, "Billing Organization", res.billing.organization)
addLight(domaintable, "Billing Street Address", res.billing.street_address)
addDark(domaintable, "Billing City", res.billing.city)
Expand All @@ -206,7 +226,7 @@ $('#domainsearch').on('click', () => {
})
$('#domainresult').val('')
} else {
let domaintable = document.getElementById('domainresult');
const domaintable = document.getElementById('domainresult');
domaintable.innerHTML = "";
addLight(domaintable, "Error", "Domain field was left empty")
}
Expand All @@ -216,27 +236,36 @@ $('#discordsearch').on('click', () => {
discord = $('#discord').val()
if (discord) {
$('#discordloadercircle').addClass('loader');
$.getJSON('/discord/' + discord, (res) => {
let discordtable = document.getElementById('discordresult');
$.getJSON(`/discord/${discord}`, (res) => {
const discordtable = document.getElementById('discordresult');
discordtable.innerHTML = "";
$('#discordloadercircle').removeClass('loader');
addLight(discordtable, "ID", res.id)
addDark(discordtable, "Username", res.username)
addLight(discordtable, "Avatar", res.avatar)
addDark(discordtable, "Discriminator", res.discriminator)
addLight(discordtable, "Public Flags", res.public_flags)
addDark(discordtable, "Flags", res.Flags)
addLight(discordtable, "Purchased Flags", res.purchased_flags)
addDark(discordtable, "Locale", res.locale)
addLight(discordtable, "NSFW Allowed", res.nsfw_allowed)
addDark(discordtable, "Flags", res.flags)
addLight(discordtable, "Banner", res.banner)
addDark(discordtable, "Accent Color", res.accent_color)
addLight(discordtable, "Global Name", res.global_name)
addDark(discordtable, "Avatar Decoration", res.avatar_decoration_data)
addLight(discordtable, "Banner Color", res.banner_color)
addDark(discordtable, "MFA Enabled", res.mfa_enabled)
addLight(discordtable, "Locale", res.locale)
addDark(discordtable, "Premium Type", res.premium_type)
addLight(discordtable, "Email", res.email)
addDark(discordtable, "Verified", res.verified)
addLight(discordtable, "Phone", res.phone)
addLight(discordtable, "Phone", res.phne)
addDark(discordtable, "NSFW Allowed", res.nsfw_allowed)
addLight(discordtable, "Linked Users", res.linked_users)
addDark(discordtable, "Bought Flags", res.purchased_flags)
addLight(discordtable, "Bio", res.bio)
addDark(discordtable, "Auth Types", res.authenticator_types)
})
$('#ipresult').val('')
} else {
let discordtable = document.getElementById('discordresult');
const discordtable = document.getElementById('discordresult');
discordtable.innerHTML = "";
addLight(discordtable, "Error", "Discord token field was left empty")
}
Expand All @@ -245,13 +274,13 @@ $('#discordsearch').on('click', () => {
$('#tinsearch').on('click', () => {
tin = $('#tin').val()
if (tin) {
let tintable = document.getElementById('tinresult');
const tintable = document.getElementById('tinresult');
tintable.innerHTML = "";
$('#tinloadercircle').addClass('loader');
$.getJSON('/tin/' + tin, (res) => {
$.getJSON(`/tin/${tin}`, (res) => {
$('#tinloadercircle').removeClass('loader');
for(let i = 0; i < res.rows.length; i++) {
let obj = res.rows[i];
const obj = res.rows[i];
addLight(tintable, "Assignment Date", obj.r)
addDark(tintable, "Termination Date", obj.e)
addLight(tintable, "Page", obj.pg)
Expand All @@ -266,7 +295,7 @@ $('#tinsearch').on('click', () => {
})
$('#tinresult').val('')
} else {
let tintable = document.getElementById('tinresult');
const tintable = document.getElementById('tinresult');
tintable.innerHTML = "";
addLight(tintable, "Error", "TIN field was left empty")
}
Expand Down
Loading

0 comments on commit b0e9394

Please sign in to comment.