Compare commits

..

5 Commits

Author SHA1 Message Date
dependabot[bot] c53d4532bf Bump astro from 6.1.2 to 6.1.10 in /front
Bumps [astro](https://github.com/withastro/astro/tree/HEAD/packages/astro) from 6.1.2 to 6.1.10.
- [Release notes](https://github.com/withastro/astro/releases)
- [Changelog](https://github.com/withastro/astro/blob/main/packages/astro/CHANGELOG.md)
- [Commits](https://github.com/withastro/astro/commits/astro@6.1.10/packages/astro)

---
updated-dependencies:
- dependency-name: astro
  dependency-version: 6.1.10
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-13 19:06:38 +00:00
Hadi ea5c3484d9 Edit home
Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com>
2026-04-13 19:34:17 +02:00
Hadi c1a50103b9 gravatar: no output when not found
Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com>
2026-04-13 19:28:43 +02:00
Hadi 564798d8fb exemple of overwrite tool's conf
Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com>
2026-04-12 19:30:56 +02:00
Hadi 302166c87d Improve docs, responsive, add Material Icons
Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com>
2026-04-12 16:42:19 +02:00
39 changed files with 188 additions and 113 deletions
+8 -7
View File
@@ -1,6 +1,6 @@
# Tools # Tools
_12 tools registered._ _13 tools registered._
| Tool | Input types | Description | Link | | Tool | Input types | Description | Link |
|------|-------------|-------------|------| |------|-------------|-------------|------|
@@ -8,11 +8,12 @@ _12 tools registered._
| [`github-recon`](tools/github-recon.md) | `username`, `email` | GitHub OSINT reconnaissance tool. Gathers profile info, social links, organisations, SSH/GPG keys, commits, and more from a GitHub username or email. | [Link](https://github.com/anotherhadi/nur-osint) | | [`github-recon`](tools/github-recon.md) | `username`, `email` | GitHub OSINT reconnaissance tool. Gathers profile info, social links, organisations, SSH/GPG keys, commits, and more from a GitHub username or email. | [Link](https://github.com/anotherhadi/nur-osint) |
| [`whois`](tools/whois.md) | `domain`, `ip` | WHOIS lookup for domain registration and IP ownership information. | [Link](https://en.wikipedia.org/wiki/WHOIS) | | [`whois`](tools/whois.md) | `domain`, `ip` | WHOIS lookup for domain registration and IP ownership information. | [Link](https://en.wikipedia.org/wiki/WHOIS) |
| [`dig`](tools/dig.md) | `domain`, `ip` | DNS lookup querying A, AAAA, MX, NS, TXT, and SOA records for a domain, or reverse DNS (PTR) for an IP. | [Link](https://linux.die.net/man/1/dig) | | [`dig`](tools/dig.md) | `domain`, `ip` | DNS lookup querying A, AAAA, MX, NS, TXT, and SOA records for a domain, or reverse DNS (PTR) for an IP. | [Link](https://linux.die.net/man/1/dig) |
| [`ipinfo`](tools/ipinfo.md) | `ip` | IP geolocation via ipinfo.io returns city, region, country, coordinates, ASN/org, timezone, and hostname. | [Link](https://ipinfo.io) | | [`ipinfo`](tools/ipinfo.md) | `ip` | IP geolocation via ipinfo.io: returns city, region, country, coordinates, ASN/org, timezone, and hostname. | [Link](https://ipinfo.io) |
| [`gravatar-recon`](tools/gravatar-recon.md) | `email` | Gravatar OSINT tool. Extracts public profile data from a Gravatar account: name, bio, location, employment, social accounts, phone, and more. | [Link](https://github.com/anotherhadi/gravatar-recon) | | [`gravatar-recon`](tools/gravatar-recon.md) | `email` | Gravatar OSINT tool. Extracts public profile data from a Gravatar account: name, bio, location, employment, social accounts, phone, and more. | [Link](https://github.com/anotherhadi/gravatar-recon) |
| [`whoisfreaks`](tools/whoisfreaks.md) | `email`, `name`, `domain` | Reverse WHOIS lookup via WhoisFreaks find all domains registered by an email, owner name, or keyword across 3.6B+ WHOIS records. | [Link](https://whoisfreaks.com) | | [`whoisfreaks`](tools/whoisfreaks.md) | `email`, `name`, `domain` | Reverse WHOIS lookup via WhoisFreaks: find all domains registered by an email, owner name, or keyword across 3.6B+ WHOIS records. | [Link](https://whoisfreaks.com) |
| [`maigret`](tools/maigret.md) | `username` | Username OSINT across 3000+ sites. Searches social networks, forums, and online platforms for an account matching the target username. | [Link](https://github.com/soxoj/maigret) | | [`maigret`](tools/maigret.md) | `username` | Username OSINT across 3000+ sites. Searches social networks, forums, and online platforms for an account matching the target username. | [Link](https://github.com/soxoj/maigret) |
| [`leakcheck`](tools/leakcheck.md) | `email`, `username`, `phone` | Data breach lookup via LeakCheck.io — searches 7B+ leaked records for email addresses, usernames, and phone numbers across hundreds of breaches. | [Link](https://leakcheck.io) | | [`ghunt`](tools/ghunt.md) | `email` | Google account OSINT via GHunt. Extracts profile info, linked services, and activity from a Google email address. | [Link](https://github.com/mxrch/GHunt) |
| [`crt.sh`](tools/crt.sh.md) | `domain` | SSL/TLS certificate transparency log search via crt.sh — enumerates subdomains and certificates issued for a domain. | [Link](https://crt.sh) | | [`leakcheck`](tools/leakcheck.md) | `email`, `username`, `phone` | Data breach lookup via LeakCheck.io: searches 7B+ leaked records for email addresses, usernames, and phone numbers across hundreds of breaches. | [Link](https://leakcheck.io) |
| [`breachdirectory`](tools/breachdirectory.md) | `email`, `username` | Data breach search via BreachDirectory — checks if an email, username, or phone appears in known data breaches and returns exposed passwords/hashes. | [Link](https://breachdirectory.org) | | [`crt.sh`](tools/crt.sh.md) | `domain` | SSL/TLS certificate transparency log search via crt.sh: enumerates subdomains and certificates issued for a domain. | [Link](https://crt.sh) |
| [`wappalyzer`](tools/wappalyzer.md) | `domain` | Web technology fingerprinting via wappalyzergo — detects CMS, frameworks, web servers, analytics, CDN, and 1500+ other technologies running on a domain. | [Link](https://github.com/projectdiscovery/wappalyzergo) | | [`breachdirectory`](tools/breachdirectory.md) | `email`, `username` | Data breach search via BreachDirectory: checks if an email, username, or phone appears in known data breaches and returns exposed passwords/hashes. | [Link](https://breachdirectory.org) |
| [`wappalyzer`](tools/wappalyzer.md) | `domain` | Web technology fingerprinting via wappalyzergo: detects CMS, frameworks, web servers, analytics, CDN, and 1500+ other technologies running on a domain. | [Link](https://github.com/projectdiscovery/wappalyzergo) |
+2 -2
View File
@@ -1,6 +1,6 @@
# `breachdirectory` # `breachdirectory`
Data breach search via BreachDirectory checks if an email, username, or phone appears in known data breaches and returns exposed passwords/hashes. Data breach search via BreachDirectory: checks if an email, username, or phone appears in known data breaches and returns exposed passwords/hashes.
**Source / documentation:** [https://breachdirectory.org](https://breachdirectory.org) **Source / documentation:** [https://breachdirectory.org](https://breachdirectory.org)
@@ -15,7 +15,7 @@ Configure globally via the Tools page or override per profile.
| Field | Type | Required | Default | Description | | Field | Type | Required | Default | Description |
|-------|------|:--------:|---------|-------------| |-------|------|:--------:|---------|-------------|
| `api_key` | `string` | **yes** | - | RapidAPI key for BreachDirectory (required get one at rapidapi.com/rohan-patra/api/breachdirectory) | | `api_key` | `string` | **yes** | - | RapidAPI key for BreachDirectory (required, get one at rapidapi.com/rohan-patra/api/breachdirectory) |
--- ---
+1 -1
View File
@@ -1,6 +1,6 @@
# `crt.sh` # `crt.sh`
SSL/TLS certificate transparency log search via crt.sh enumerates subdomains and certificates issued for a domain. SSL/TLS certificate transparency log search via crt.sh: enumerates subdomains and certificates issued for a domain.
**Source / documentation:** [https://crt.sh](https://crt.sh) **Source / documentation:** [https://crt.sh](https://crt.sh)
+27
View File
@@ -0,0 +1,27 @@
# `ghunt`
Google account OSINT via GHunt. Extracts profile info, linked services, and activity from a Google email address.
**Source / documentation:** [https://github.com/mxrch/GHunt](https://github.com/mxrch/GHunt)
## Input types
- `email`
## External dependencies
The following binaries must be installed and available in `$PATH`:
- `ghunt`
## Configuration
Configure globally via the Tools page or override per profile.
| Field | Type | Required | Default | Description |
|-------|------|:--------:|---------|-------------|
| `creds` | `string` | **yes** | - | GHunt credentials (content of ~/.malfrats/ghunt/creds.m). To obtain: (1) install GHunt and run 'ghunt login' on your machine, (2) copy the full content of ~/.malfrats/ghunt/creds.m, (3) paste it here. |
---
[← Back to tools index](../tools.md)
+2 -2
View File
@@ -1,6 +1,6 @@
# `ipinfo` # `ipinfo`
IP geolocation via ipinfo.io returns city, region, country, coordinates, ASN/org, timezone, and hostname. IP geolocation via ipinfo.io: returns city, region, country, coordinates, ASN/org, timezone, and hostname.
**Source / documentation:** [https://ipinfo.io](https://ipinfo.io) **Source / documentation:** [https://ipinfo.io](https://ipinfo.io)
@@ -14,7 +14,7 @@ Configure globally via the Tools page or override per profile.
| Field | Type | Required | Default | Description | | Field | Type | Required | Default | Description |
|-------|------|:--------:|---------|-------------| |-------|------|:--------:|---------|-------------|
| `token` | `string` | - | - | ipinfo.io API token (optional free tier allows 50k req/month without one) | | `token` | `string` | - | - | ipinfo.io API token (optional, free tier allows 50k req/month without one) |
--- ---
+2 -2
View File
@@ -1,6 +1,6 @@
# `leakcheck` # `leakcheck`
Data breach lookup via LeakCheck.io searches 7B+ leaked records for email addresses, usernames, and phone numbers across hundreds of breaches. Data breach lookup via LeakCheck.io: searches 7B+ leaked records for email addresses, usernames, and phone numbers across hundreds of breaches.
**Source / documentation:** [https://leakcheck.io](https://leakcheck.io) **Source / documentation:** [https://leakcheck.io](https://leakcheck.io)
@@ -16,7 +16,7 @@ Configure globally via the Tools page or override per profile.
| Field | Type | Required | Default | Description | | Field | Type | Required | Default | Description |
|-------|------|:--------:|---------|-------------| |-------|------|:--------:|---------|-------------|
| `api_key` | `string` | **yes** | - | LeakCheck API key (required get one at leakcheck.io) | | `api_key` | `string` | **yes** | - | LeakCheck API key (required, get one at leakcheck.io) |
--- ---
+1 -1
View File
@@ -1,6 +1,6 @@
# `wappalyzer` # `wappalyzer`
Web technology fingerprinting via wappalyzergo detects CMS, frameworks, web servers, analytics, CDN, and 1500+ other technologies running on a domain. Web technology fingerprinting via wappalyzergo: detects CMS, frameworks, web servers, analytics, CDN, and 1500+ other technologies running on a domain.
**Source / documentation:** [https://github.com/projectdiscovery/wappalyzergo](https://github.com/projectdiscovery/wappalyzergo) **Source / documentation:** [https://github.com/projectdiscovery/wappalyzergo](https://github.com/projectdiscovery/wappalyzergo)
+2 -2
View File
@@ -1,6 +1,6 @@
# `whoisfreaks` # `whoisfreaks`
Reverse WHOIS lookup via WhoisFreaks find all domains registered by an email, owner name, or keyword across 3.6B+ WHOIS records. Reverse WHOIS lookup via WhoisFreaks: find all domains registered by an email, owner name, or keyword across 3.6B+ WHOIS records.
**Source / documentation:** [https://whoisfreaks.com](https://whoisfreaks.com) **Source / documentation:** [https://whoisfreaks.com](https://whoisfreaks.com)
@@ -16,7 +16,7 @@ Configure globally via the Tools page or override per profile.
| Field | Type | Required | Default | Description | | Field | Type | Required | Default | Description |
|-------|------|:--------:|---------|-------------| |-------|------|:--------:|---------|-------------|
| `api_key` | `string` | **yes** | - | WhoisFreaks API key (required free account at whoisfreaks.com) | | `api_key` | `string` | **yes** | - | WhoisFreaks API key (required, free account at whoisfreaks.com) |
--- ---
+1
View File
@@ -1,2 +1,3 @@
.claude/ .claude/
CLAUDE.md
todolist.md todolist.md
+11 -1
View File
@@ -30,6 +30,7 @@ Designed for security researchers, penetration testers, and OSINT investigators
- **Parallel execution**: all tools run simultaneously; results stream in as they arrive - **Parallel execution**: all tools run simultaneously; results stream in as they arrive
- **Profile system**: create named profiles to enable/disable specific tools or override their config per investigation type (quick recon vs. thorough sweep) - **Profile system**: create named profiles to enable/disable specific tools or override their config per investigation type (quick recon vs. thorough sweep)
- **Per-tool configuration**: set API keys, rate limits, and options globally or per profile - **Per-tool configuration**: set API keys, rate limits, and options globally or per profile
- **Proxy support**: route all tool traffic through SOCKS5/SOCKS4/HTTP proxies, with automatic failover across multiple proxies; external binary tools are transparently wrapped with proxychains4
- **Tool availability checks**: tools that depend on an external binary report their status; the interface shows which tools are ready, which need config, and which are unavailable - **Tool availability checks**: tools that depend on an external binary report their status; the interface shows which tools are ready, which need config, and which are unavailable
- **Search history**: completed searches are kept in memory; results can be reviewed without re-running - **Search history**: completed searches are kept in memory; results can be reviewed without re-running
- **Extensible architecture**: adding a new tool is a single Go file implementing one interface, registered in one line - **Extensible architecture**: adding a new tool is a single Go file implementing one interface, registered in one line
@@ -110,6 +111,7 @@ Create `/etc/iky/config.yaml` (or any path, then point `IKY_CONFIG` to it):
tools: tools:
github-recon: github-recon:
token: ghp_yourtoken token: ghp_yourtoken
deepscan: true
whoisfreaks: whoisfreaks:
api_key: yourkey api_key: yourkey
ipinfo: ipinfo:
@@ -117,16 +119,24 @@ tools:
breachdirectory: breachdirectory:
api_key: yourkey api_key: yourkey
proxies:
- url: socks5://user:pass@127.0.0.1:9050
- url: http://proxy.example.com:8080
profiles: profiles:
quick: quick:
enabled: enabled:
- whois - whois
- dig - dig
- crt.sh - crt.sh
- github-recon
disabled: [] disabled: []
tools:
github-recon:
deepscan: false # Overwrite
``` ```
Only include the tools you want to configure everything else falls back to defaults. Only include the tools you want to configure; everything else falls back to defaults.
</details> </details>
+4 -4
View File
@@ -16,13 +16,13 @@ import (
// ansiRe strips all ANSI/VT100 escape sequences (CSI, OSC, etc.). // ansiRe strips all ANSI/VT100 escape sequences (CSI, OSC, etc.).
// RunWithPTY only strips OSC sequences; CSI colour codes need this. // RunWithPTY only strips OSC sequences; CSI colour codes need this.
var ansiRe = regexp.MustCompile(`\x1b[\x5b-\x5f][0-9;]*[A-Za-z]|\x1b[^[\x5b-\x5f]`) var ansiRe = regexp.MustCompile(`\x1b[\x5b-\x5f][0-9;]*[A-Za-z]|\x1b[^\x5b-\x5f]`)
type EnumerateHandler struct { type EnumerateHandler struct {
demo bool demo bool
} }
func NewEnumerateHandler(_ string, demo bool) *EnumerateHandler { func NewEnumerateHandler(demo bool) *EnumerateHandler {
return &EnumerateHandler{demo: demo} return &EnumerateHandler{demo: demo}
} }
@@ -186,7 +186,7 @@ type checkEmailResponse struct {
// userScannerCheck runs user-scanner via PTY (required for output). // userScannerCheck runs user-scanner via PTY (required for output).
// flag is either "-e" (email) or "-u" (username). // flag is either "-e" (email) or "-u" (username).
// Office365 is excluded — it's a known false positive. // Office365 is excluded (known false positive).
// quick=true uses a shorter timeout for a faster but incomplete scan. // quick=true uses a shorter timeout for a faster but incomplete scan.
func userScannerCheck(ctx context.Context, flag, target string, quick bool) (status, reason string, sites []string) { func userScannerCheck(ctx context.Context, flag, target string, quick bool) (status, reason string, sites []string) {
defer func() { defer func() {
@@ -223,7 +223,7 @@ func userScannerCheck(ctx context.Context, flag, target string, quick bool) (sta
if !strings.Contains(line, "[✔]") { if !strings.Contains(line, "[✔]") {
continue continue
} }
// Office365 is a known false positive skip it. // Office365 is a known false positive, skip it.
if strings.Contains(line, "Office365") { if strings.Contains(line, "Office365") {
continue continue
} }
+1 -1
View File
@@ -29,7 +29,7 @@ func NewRouter(
searchHandler := handler.NewSearchHandler(manager, demo) searchHandler := handler.NewSearchHandler(manager, demo)
toolsHandler := handler.NewToolsHandler(factories) toolsHandler := handler.NewToolsHandler(factories)
configHandler := handler.NewConfigHandler(configPath, factories, demo) configHandler := handler.NewConfigHandler(configPath, factories, demo)
enumerateHandler := handler.NewEnumerateHandler(configPath, demo) enumerateHandler := handler.NewEnumerateHandler(demo)
searchLimiter := ikymiddleware.New(rate.Every(10*time.Second), 3) searchLimiter := ikymiddleware.New(rate.Every(10*time.Second), 3)
+3 -3
View File
@@ -14,13 +14,13 @@ import (
const ( const (
name = "breachdirectory" name = "breachdirectory"
description = "Data breach search via BreachDirectory checks if an email, username, or phone appears in known data breaches and returns exposed passwords/hashes." description = "Data breach search via BreachDirectory: checks if an email, username, or phone appears in known data breaches and returns exposed passwords/hashes."
link = "https://breachdirectory.org" link = "https://breachdirectory.org"
icon = "" icon = "mdi:shield-alert"
) )
type Config struct { type Config struct {
APIKey string `yaml:"api_key" iky:"desc=RapidAPI key for BreachDirectory (required get one at rapidapi.com/rohan-patra/api/breachdirectory);required=true"` APIKey string `yaml:"api_key" iky:"desc=RapidAPI key for BreachDirectory (required, get one at rapidapi.com/rohan-patra/api/breachdirectory);required=true"`
} }
type Runner struct { type Runner struct {
+2 -2
View File
@@ -16,9 +16,9 @@ import (
const ( const (
name = "crt.sh" name = "crt.sh"
description = "SSL/TLS certificate transparency log search via crt.sh enumerates subdomains and certificates issued for a domain." description = "SSL/TLS certificate transparency log search via crt.sh: enumerates subdomains and certificates issued for a domain."
link = "https://crt.sh" link = "https://crt.sh"
icon = "" icon = "mdi:certificate-outline"
) )
type Runner struct{} type Runner struct{}
+8 -2
View File
@@ -13,7 +13,7 @@ const (
name = "dig" name = "dig"
description = "DNS lookup querying A, AAAA, MX, NS, TXT, and SOA records for a domain, or reverse DNS (PTR) for an IP." description = "DNS lookup querying A, AAAA, MX, NS, TXT, and SOA records for a domain, or reverse DNS (PTR) for an IP."
link = "https://linux.die.net/man/1/dig" link = "https://linux.die.net/man/1/dig"
icon = "" icon = "mdi:dns"
) )
var recordTypes = []string{"A", "AAAA", "MX", "NS", "TXT", "SOA"} var recordTypes = []string{"A", "AAAA", "MX", "NS", "TXT", "SOA"}
@@ -67,7 +67,13 @@ func (r *Runner) Run(ctx context.Context, target string, inputType tools.InputTy
break break
} }
cmd := exec.CommandContext(ctx, "dig", target, rtype, "+noall", "+answer") cmd := exec.CommandContext(ctx, "dig", target, rtype, "+noall", "+answer")
output, _ := cmd.Output() output, err := cmd.Output()
if err != nil {
if ctx.Err() != nil {
break
}
continue
}
result := strings.TrimSpace(string(output)) result := strings.TrimSpace(string(output))
if result == "" { if result == "" {
continue continue
+3 -3
View File
@@ -18,7 +18,7 @@ const (
name = "ghunt" name = "ghunt"
description = "Google account OSINT via GHunt. Extracts profile info, linked services, and activity from a Google email address." description = "Google account OSINT via GHunt. Extracts profile info, linked services, and activity from a Google email address."
link = "https://github.com/mxrch/GHunt" link = "https://github.com/mxrch/GHunt"
icon = "google" icon = "si:google"
) )
type Config struct { type Config struct {
@@ -103,8 +103,8 @@ func (r *Runner) Run(ctx context.Context, target string, _ tools.InputType, out
} }
if start == -1 { if start == -1 {
// Banner printed but auth line never appeared bad/expired credentials. // Banner printed but auth line never appeared: bad/expired credentials.
out <- tools.Event{Tool: name, Type: tools.EventTypeError, Payload: "GHunt authentication failed credentials may be missing or expired (run 'ghunt login' and update your creds in Settings)"} out <- tools.Event{Tool: name, Type: tools.EventTypeError, Payload: "GHunt authentication failed: credentials may be missing or expired (run 'ghunt login' and update your creds in Settings)"}
out <- tools.Event{Tool: name, Type: tools.EventTypeCount, Payload: 0} out <- tools.Event{Tool: name, Type: tools.EventTypeCount, Payload: 0}
out <- tools.Event{Tool: name, Type: tools.EventTypeDone} out <- tools.Event{Tool: name, Type: tools.EventTypeDone}
return nil return nil
+1 -1
View File
@@ -12,7 +12,7 @@ const (
name = "github-recon" name = "github-recon"
description = "GitHub OSINT reconnaissance tool. Gathers profile info, social links, organisations, SSH/GPG keys, commits, and more from a GitHub username or email." description = "GitHub OSINT reconnaissance tool. Gathers profile info, social links, organisations, SSH/GPG keys, commits, and more from a GitHub username or email."
link = "https://github.com/anotherhadi/nur-osint" link = "https://github.com/anotherhadi/nur-osint"
icon = "github" icon = "si:github"
) )
type Config struct { type Config struct {
+4 -1
View File
@@ -3,6 +3,7 @@ package gravatarrecon
import ( import (
"context" "context"
"os/exec" "os/exec"
"strings"
"github.com/anotherhadi/iknowyou/internal/tools" "github.com/anotherhadi/iknowyou/internal/tools"
) )
@@ -11,7 +12,7 @@ const (
name = "gravatar-recon" name = "gravatar-recon"
description = "Gravatar OSINT tool. Extracts public profile data from a Gravatar account: name, bio, location, employment, social accounts, phone, and more." description = "Gravatar OSINT tool. Extracts public profile data from a Gravatar account: name, bio, location, employment, social accounts, phone, and more."
link = "https://github.com/anotherhadi/gravatar-recon" link = "https://github.com/anotherhadi/gravatar-recon"
icon = "" icon = "si:gravatar"
) )
type Runner struct{} type Runner struct{}
@@ -46,9 +47,11 @@ func (r *Runner) Run(ctx context.Context, target string, _ tools.InputType, out
if err != nil && ctx.Err() != nil { if err != nil && ctx.Err() != nil {
out <- tools.Event{Tool: name, Type: tools.EventTypeError, Payload: "scan cancelled"} out <- tools.Event{Tool: name, Type: tools.EventTypeError, Payload: "scan cancelled"}
} else if output != "" { } else if output != "" {
if !strings.Contains(output, "status 404") {
out <- tools.Event{Tool: name, Type: tools.EventTypeOutput, Payload: output} out <- tools.Event{Tool: name, Type: tools.EventTypeOutput, Payload: output}
count = 1 count = 1
} }
}
out <- tools.Event{Tool: name, Type: tools.EventTypeCount, Payload: count} out <- tools.Event{Tool: name, Type: tools.EventTypeCount, Payload: count}
out <- tools.Event{Tool: name, Type: tools.EventTypeDone} out <- tools.Event{Tool: name, Type: tools.EventTypeDone}
return nil return nil
+3 -3
View File
@@ -13,13 +13,13 @@ import (
const ( const (
name = "ipinfo" name = "ipinfo"
description = "IP geolocation via ipinfo.io returns city, region, country, coordinates, ASN/org, timezone, and hostname." description = "IP geolocation via ipinfo.io: returns city, region, country, coordinates, ASN/org, timezone, and hostname."
link = "https://ipinfo.io" link = "https://ipinfo.io"
icon = "" icon = "mdi:ip-network"
) )
type Config struct { type Config struct {
Token string `yaml:"token" iky:"desc=ipinfo.io API token (optional free tier allows 50k req/month without one);required=false"` Token string `yaml:"token" iky:"desc=ipinfo.io API token (optional, free tier allows 50k req/month without one);required=false"`
} }
type Runner struct { type Runner struct {
+3 -3
View File
@@ -14,13 +14,13 @@ import (
const ( const (
name = "leakcheck" name = "leakcheck"
description = "Data breach lookup via LeakCheck.io searches 7B+ leaked records for email addresses, usernames, and phone numbers across hundreds of breaches." description = "Data breach lookup via LeakCheck.io: searches 7B+ leaked records for email addresses, usernames, and phone numbers across hundreds of breaches."
link = "https://leakcheck.io" link = "https://leakcheck.io"
icon = "" icon = "mdi:database-alert"
) )
type Config struct { type Config struct {
APIKey string `yaml:"api_key" iky:"desc=LeakCheck API key (required get one at leakcheck.io);required=true"` APIKey string `yaml:"api_key" iky:"desc=LeakCheck API key (required, get one at leakcheck.io);required=true"`
} }
type Runner struct { type Runner struct {
+2 -2
View File
@@ -14,7 +14,7 @@ const (
name = "maigret" name = "maigret"
description = "Username OSINT across 3000+ sites. Searches social networks, forums, and online platforms for an account matching the target username." description = "Username OSINT across 3000+ sites. Searches social networks, forums, and online platforms for an account matching the target username."
link = "https://github.com/soxoj/maigret" link = "https://github.com/soxoj/maigret"
icon = "" icon = "mdi:radar"
) )
var accountsRe = regexp.MustCompile(`returned (\d+) accounts`) var accountsRe = regexp.MustCompile(`returned (\d+) accounts`)
@@ -68,7 +68,7 @@ func (r *Runner) Run(ctx context.Context, target string, _ tools.InputType, out
cmd := exec.CommandContext(ctx, "maigret", args...) cmd := exec.CommandContext(ctx, "maigret", args...)
output, err := tools.RunWithPTY(ctx, cmd) output, err := tools.RunWithPTY(ctx, cmd)
// Crop at Python traceback (NixOS read-only store error results are unaffected) // Crop at Python traceback (NixOS read-only store error, results are unaffected)
if idx := strings.Index(output, "Traceback (most recent call last)"); idx != -1 { if idx := strings.Index(output, "Traceback (most recent call last)"); idx != -1 {
output = strings.TrimSpace(output[:idx]) output = strings.TrimSpace(output[:idx])
} }
+1 -1
View File
@@ -7,7 +7,7 @@ type EventType string
const ( const (
EventTypeOutput EventType = "output" // raw ANSI text, payload is a plain string EventTypeOutput EventType = "output" // raw ANSI text, payload is a plain string
EventTypeError EventType = "error" EventTypeError EventType = "error"
EventTypeCount EventType = "count" // payload is int, additive emit once or multiple times from Run EventTypeCount EventType = "count" // payload is int, additive; emit once or multiple times from Run
EventTypeDone EventType = "done" EventTypeDone EventType = "done"
) )
+1 -1
View File
@@ -12,7 +12,7 @@ const (
name = "user-scanner" name = "user-scanner"
description = "🕵️‍♂️ (2-in-1) Email & Username OSINT suite. Analyzes 195+ scan vectors (95+ email / 100+ username) for security research, investigations, and digital footprinting." description = "🕵️‍♂️ (2-in-1) Email & Username OSINT suite. Analyzes 195+ scan vectors (95+ email / 100+ username) for security research, investigations, and digital footprinting."
link = "https://github.com/kaifcodec/user-scanner" link = "https://github.com/kaifcodec/user-scanner"
icon = "" icon = "mdi:account-search"
) )
type Config struct { type Config struct {
+2 -2
View File
@@ -16,9 +16,9 @@ import (
const ( const (
name = "wappalyzer" name = "wappalyzer"
description = "Web technology fingerprinting via wappalyzergo detects CMS, frameworks, web servers, analytics, CDN, and 1500+ other technologies running on a domain." description = "Web technology fingerprinting via wappalyzergo: detects CMS, frameworks, web servers, analytics, CDN, and 1500+ other technologies running on a domain."
link = "https://github.com/projectdiscovery/wappalyzergo" link = "https://github.com/projectdiscovery/wappalyzergo"
icon = "wappalyzer" icon = "si:wappalyzer"
) )
type Runner struct { type Runner struct {
+1 -1
View File
@@ -12,7 +12,7 @@ const (
name = "whois" name = "whois"
description = "WHOIS lookup for domain registration and IP ownership information." description = "WHOIS lookup for domain registration and IP ownership information."
link = "https://en.wikipedia.org/wiki/WHOIS" link = "https://en.wikipedia.org/wiki/WHOIS"
icon = "" icon = "mdi:card-search"
) )
type Runner struct{} type Runner struct{}
+3 -3
View File
@@ -16,13 +16,13 @@ import (
const ( const (
name = "whoisfreaks" name = "whoisfreaks"
description = "Reverse WHOIS lookup via WhoisFreaks find all domains registered by an email, owner name, or keyword across 3.6B+ WHOIS records." description = "Reverse WHOIS lookup via WhoisFreaks: find all domains registered by an email, owner name, or keyword across 3.6B+ WHOIS records."
link = "https://whoisfreaks.com" link = "https://whoisfreaks.com"
icon = "" icon = "mdi:database-search"
) )
type Config struct { type Config struct {
APIKey string `yaml:"api_key" iky:"desc=WhoisFreaks API key (required free account at whoisfreaks.com);required=true"` APIKey string `yaml:"api_key" iky:"desc=WhoisFreaks API key (required, free account at whoisfreaks.com);required=true"`
} }
type Runner struct { type Runner struct {
+1 -1
View File
@@ -15,7 +15,7 @@
"@lucide/svelte": "^1.7.0", "@lucide/svelte": "^1.7.0",
"@tailwindcss/vite": "^4.2.1", "@tailwindcss/vite": "^4.2.1",
"ansi_up": "^6.0.6", "ansi_up": "^6.0.6",
"astro": "6.1.2", "astro": "6.1.10",
"dompurify": "^3.3.3", "dompurify": "^3.3.3",
"js-yaml": "^4.1.1", "js-yaml": "^4.1.1",
"remark-github-blockquote-alert": "^2.1.0", "remark-github-blockquote-alert": "^2.1.0",
+5 -3
View File
@@ -60,17 +60,19 @@
{#each filtered as sheet} {#each filtered as sheet}
<a <a
href={`/cheatsheets/${sheet.id}`} href={`/cheatsheets/${sheet.id}`}
class="card bg-base-200 hover:bg-base-300 transition-colors p-4 flex flex-row items-center gap-4" class="card bg-base-200 hover:bg-base-300 transition-colors p-4 flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-4"
> >
<div class="flex items-center gap-4 flex-1 min-w-0">
<div class="size-2 rounded-full bg-primary shrink-0"></div> <div class="size-2 rounded-full bg-primary shrink-0"></div>
<div class="flex-1 min-w-0"> <div class="min-w-0">
<div class="font-semibold text-sm">{sheet.title}</div> <div class="font-semibold text-sm">{sheet.title}</div>
{#if sheet.description} {#if sheet.description}
<div class="text-base-content/50 text-xs mt-0.5">{sheet.description}</div> <div class="text-base-content/50 text-xs mt-0.5">{sheet.description}</div>
{/if} {/if}
</div> </div>
</div>
{#if sheet.tags && sheet.tags.length > 0} {#if sheet.tags && sheet.tags.length > 0}
<div class="flex gap-1 shrink-0"> <div class="flex flex-wrap gap-1 sm:justify-end">
{#each sheet.tags as tag} {#each sheet.tags as tag}
<span class="badge badge-xs badge-ghost">{tag}</span> <span class="badge badge-xs badge-ghost">{tag}</span>
{/each} {/each}
+1 -1
View File
@@ -19,6 +19,6 @@
{#if demo} {#if demo}
<div class="w-full bg-warning/15 border-b border-warning/30 py-1.5 px-4 flex items-center justify-center gap-2 text-xs text-warning"> <div class="w-full bg-warning/15 border-b border-warning/30 py-1.5 px-4 flex items-center justify-center gap-2 text-xs text-warning">
<FlaskConical size={13} class="shrink-0" /> <FlaskConical size={13} class="shrink-0" />
<span>Demo mode searches and configuration changes are disabled</span> <span>Demo mode: searches and configuration changes are disabled</span>
</div> </div>
{/if} {/if}
+4 -4
View File
@@ -158,8 +158,8 @@
if (s === "found") return "Found"; if (s === "found") return "Found";
if (s === "not_found") return "Not found"; if (s === "not_found") return "Not found";
if (s === "maybe") return "Maybe"; if (s === "maybe") return "Maybe";
if (s === "checking") return "Checking"; if (s === "checking") return "Checking...";
return ""; return "-";
} }
</script> </script>
@@ -296,7 +296,7 @@
{#if !userScannerAvailable} {#if !userScannerAvailable}
<div class="alert alert-warning text-sm gap-2"> <div class="alert alert-warning text-sm gap-2">
<TriangleAlert size={15} class="shrink-0" /> <TriangleAlert size={15} class="shrink-0" />
<span><span class="font-mono">user-scanner</span> is not installed email and username checking will be unavailable.</span> <span><span class="font-mono">user-scanner</span> is not installed, email and username checking will be unavailable.</span>
</div> </div>
{/if} {/if}
@@ -414,7 +414,7 @@
<HelpCircle size={13} /> Maybe <HelpCircle size={13} /> Maybe
</span> </span>
{:else} {:else}
<span class="text-xs text-base-content/30"></span> <span class="text-xs text-base-content/30">-</span>
{/if} {/if}
</td> </td>
<td class="text-right"> <td class="text-right">
+33 -12
View File
@@ -13,6 +13,15 @@
} from "@lucide/svelte"; } from "@lucide/svelte";
import type { Snippet } from "svelte"; import type { Snippet } from "svelte";
let mobileMenuOpen = $state(false);
function onDocumentClick(e: MouseEvent) {
if (!mobileMenuOpen) return;
if (!(e.target as HTMLElement).closest("[data-mobile-nav]")) {
mobileMenuOpen = false;
}
}
let { let {
action, action,
}: { }: {
@@ -46,17 +55,20 @@
]; ];
</script> </script>
<svelte:document onclick={onDocumentClick} />
<div class="bg-base-200"> <div class="bg-base-200">
<div class="navbar max-w-5xl m-auto"> <div class="navbar max-w-5xl m-auto">
<div class="navbar-start"> <div class="navbar-start">
<div class="dropdown"> <div class="relative" data-mobile-nav>
<div tabindex="0" role="button" class="btn btn-ghost lg:hidden"> <button
<Menu size={20} /> class="btn btn-ghost lg:hidden"
</div> onclick={(e) => { e.stopPropagation(); mobileMenuOpen = !mobileMenuOpen; }}
<ul
tabindex="-1"
class="menu menu-sm dropdown-content bg-base-300 rounded-box z-50 mt-3 w-52 p-2"
> >
<Menu size={20} />
</button>
{#if mobileMenuOpen}
<ul class="menu menu-sm absolute bg-base-300 rounded-box z-50 mt-1 w-52 p-2">
{#each navLinks as link} {#each navLinks as link}
<li> <li>
{#if link.children} {#if link.children}
@@ -64,7 +76,11 @@
<ul class="p-2"> <ul class="p-2">
{#each link.children as sublink} {#each link.children as sublink}
<li> <li>
<a href={sublink.href} class="flex items-center gap-2"> <a
href={sublink.href}
class="flex items-center gap-2"
onclick={() => (mobileMenuOpen = false)}
>
{#if sublink.icon} {#if sublink.icon}
{@const Icon = sublink.icon} {@const Icon = sublink.icon}
<Icon size={12} /> <Icon size={12} />
@@ -75,7 +91,11 @@
{/each} {/each}
</ul> </ul>
{:else} {:else}
<a href={link.href} class="flex items-center gap-2"> <a
href={link.href}
class="flex items-center gap-2"
onclick={() => (mobileMenuOpen = false)}
>
{#if link.icon} {#if link.icon}
{@const Icon = link.icon} {@const Icon = link.icon}
<Icon size={12} /> <Icon size={12} />
@@ -86,8 +106,9 @@
</li> </li>
{/each} {/each}
</ul> </ul>
{/if}
</div> </div>
<!-- Logo à gauche sur écran moyen et grand --> <!-- Logo on medium/large screens -->
<a <a
href="/" href="/"
class="btn btn-ghost text-xl hidden sm:flex justify-center gap-2 items-center" class="btn btn-ghost text-xl hidden sm:flex justify-center gap-2 items-center"
@@ -98,7 +119,7 @@
</div> </div>
<div class="navbar-center lg:flex"> <div class="navbar-center lg:flex">
<!-- Logo centré sur petit écran (mobile) --> <!-- Logo centered on mobile -->
<a <a
href="/" href="/"
class="btn btn-ghost text-xl flex sm:hidden justify-center gap-2 items-center" class="btn btn-ghost text-xl flex sm:hidden justify-center gap-2 items-center"
@@ -106,7 +127,7 @@
<img src="/logo.svg" class="m-auto h-4" alt="iky logo" /> <img src="/logo.svg" class="m-auto h-4" alt="iky logo" />
<img src="/logo-large.svg" class="m-auto h-4" alt="iky logo large" /> <img src="/logo-large.svg" class="m-auto h-4" alt="iky logo large" />
</a> </a>
<!-- Nav links sur grand écran --> <!-- Nav links on large screens -->
<ul class="menu menu-horizontal px-1 hidden lg:flex"> <ul class="menu menu-horizontal px-1 hidden lg:flex">
{#each navLinks as link} {#each navLinks as link}
<li> <li>
+2 -2
View File
@@ -141,7 +141,7 @@
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
{#if proxies.length === 0} {#if proxies.length === 0}
<p class="text-sm text-base-content/40"> <p class="text-sm text-base-content/40">
No proxies configured tools will connect directly. No proxies configured, tools will connect directly.
</p> </p>
{:else} {:else}
{#each proxies as proxy, i} {#each proxies as proxy, i}
@@ -191,7 +191,7 @@
<p class="text-xs text-base-content/40"> <p class="text-xs text-base-content/40">
Supported: <span class="font-mono">socks5://</span>, Supported: <span class="font-mono">socks5://</span>,
<span class="font-mono">socks4://</span>, <span class="font-mono">socks4://</span>,
<span class="font-mono">http://</span> — on failure, the next proxy is tried automatically. <span class="font-mono">http://</span>. On failure, the next proxy is tried automatically.
</p> </p>
</div> </div>
{/if} {/if}
+3 -3
View File
@@ -8,7 +8,7 @@
const DETECTORS = { const DETECTORS = {
email: (_raw, v) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v), email: (_raw, v) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v),
phone: (_raw, v) => /^\+\d{1,4} \d{4,}$/.test(v), phone: (_raw, v) => /^\+\d{1,4} \d{4,}$/.test(v),
ip: (_raw, v) => /^(\d{1,3}\.){3}\d{1,3}$/.test(v) || /^[0-9a-fA-F:]{3,39}$/.test(v), ip: (_raw, v) => /^(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)(\.(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)){3}$/.test(v) || (/^[0-9a-fA-F:]{3,39}$/.test(v) && v.includes(':')),
domain: (raw, v) => /^https?:\/\//.test(raw) || /^(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/.test(v), domain: (raw, v) => /^https?:\/\//.test(raw) || /^(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/.test(v),
name: (_raw, v) => /^[a-zA--ÿ'-]+(?: [a-zA-ZÀ-ÿ'-]+){1,2}$/.test(v), name: (_raw, v) => /^[a-zA--ÿ'-]+(?: [a-zA-ZÀ-ÿ'-]+){1,2}$/.test(v),
}; };
@@ -16,8 +16,8 @@
const VALIDATORS = { const VALIDATORS = {
email: { test: (v) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v), msg: "Invalid email address" }, email: { test: (v) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v), msg: "Invalid email address" },
username: { test: (v) => /^[a-zA-Z0-9._-]+$/.test(v), msg: "Username may only contain a-z, 0-9, . - _" }, username: { test: (v) => /^[a-zA-Z0-9._-]+$/.test(v), msg: "Username may only contain a-z, 0-9, . - _" },
phone: { test: (v) => /^\+\d{1,4} \d{4,}$/.test(v), msg: "Format: +INDICATIF NUMERO (ex: +33 0612345678)" }, phone: { test: (v) => /^\+\d{1,4} \d{4,}$/.test(v), msg: "Format: +COUNTRYCODE NUMBER (e.g. +1 2025550147)" },
ip: { test: (v) => /^(\d{1,3}\.){3}\d{1,3}$/.test(v) || /^[0-9a-fA-F:]{3,39}$/.test(v), msg: "Invalid IP address" }, ip: { test: (v) => /^(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)(\.(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)){3}$/.test(v) || (/^[0-9a-fA-F:]{3,39}$/.test(v) && v.includes(':')), msg: "Invalid IP address" },
domain: { test: (v) => /^(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/.test(v), msg: "Invalid domain name" }, domain: { test: (v) => /^(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/.test(v), msg: "Invalid domain name" },
}; };
+1 -1
View File
@@ -230,7 +230,7 @@
</details> </details>
{#if demo} {#if demo}
<p class="text-xs text-base-content/40 italic">Results shown are not exhaustive demo mode only displays a subset of what the tools can find.</p> <p class="text-xs text-base-content/40 italic">Results shown are not exhaustive: demo mode only displays a subset of what the tools can find.</p>
{/if} {/if}
</div> </div>
+2 -2
View File
@@ -406,7 +406,7 @@
<div class="alert alert-warning py-2 px-3 text-sm gap-2"> <div class="alert alert-warning py-2 px-3 text-sm gap-2">
<AlertTriangle size={15} class="shrink-0" /> <AlertTriangle size={15} class="shrink-0" />
<span> <span>
<strong>proxychains4</strong> not found in PATH external binary tools <strong>proxychains4</strong> not found in PATH, external binary tools
(maigret, ghunt, etc.) will <strong>not</strong> be proxied. (maigret, ghunt, etc.) will <strong>not</strong> be proxied.
Only HTTP-based tools are affected by the proxy config. Only HTTP-based tools are affected by the proxy config.
</span> </span>
@@ -418,7 +418,7 @@
{#if proxies.length === 0} {#if proxies.length === 0}
<div class="border border-dashed border-base-300 rounded-box py-8 text-center"> <div class="border border-dashed border-base-300 rounded-box py-8 text-center">
<Shield size={24} class="mx-auto mb-2 text-base-content/20" /> <Shield size={24} class="mx-auto mb-2 text-base-content/20" />
<p class="text-sm text-base-content/40">No proxies tools connect directly.</p> <p class="text-sm text-base-content/40">No proxies, tools connect directly.</p>
</div> </div>
{:else} {:else}
{#each proxies as proxy, i} {#each proxies as proxy, i}
+17 -14
View File
@@ -1,13 +1,26 @@
<script lang="ts"> <script lang="ts">
const { iconName = "", size=16 }: { iconName: string , size: number} = $props(); const { iconName = "", size = 16 }: { iconName: string; size: number } = $props();
const genericFallbackUrl = "/Wrench.svg"; const genericFallbackUrl = "/Wrench.svg";
function resolveUrl(name: string): string {
if (name.startsWith("mdi:")) {
return `https://cdn.jsdelivr.net/npm/@mdi/svg@latest/svg/${name.slice(4)}.svg`;
}
if (name.startsWith("sh:")) {
return `https://cdn.jsdelivr.net/gh/selfhst/icons/svg/${name.slice(3)}.svg`;
}
// si: prefix or no prefix, default to Simple Icons
const slug = name.startsWith("si:") ? name.slice(3) : name;
return `https://cdn.simpleicons.org/${slug}`;
}
const src = $derived(iconName ? resolveUrl(iconName) : genericFallbackUrl);
</script> </script>
{#if iconName}
<img <img
src="https://cdn.simpleicons.org/{iconName}" {src}
alt={iconName + " icon"} alt={iconName ? iconName + " icon" : "Tool icon"}
class="opacity-50" class="opacity-50"
width={size} width={size}
height={size} height={size}
@@ -17,13 +30,3 @@
target.src = genericFallbackUrl; target.src = genericFallbackUrl;
}} }}
/> />
{:else}
<img
src={genericFallbackUrl}
alt={"Tool icon"}
class="opacity-50"
width={size}
height={size}
style="filter: brightness(0) invert(1);"
/>
{/if}
@@ -97,7 +97,7 @@ Once you have a **name**, an **email**, or a **unique username**, its time to
If you want to move from manual investigation to automated intelligence, check out [Github-Recon](https://github.com/anotherhadi/github-recon). If you want to move from manual investigation to automated intelligence, check out [Github-Recon](https://github.com/anotherhadi/github-recon).
Written in Go, this powerful CLI tool aggregates public OSINT data by automating the techniques mentioned above and more. Whether you start with a username or a single email address, it can retrieve SSH/GPG keys, enumerate social accounts, and find "close friends" based on interactions. Written in Go, this powerful CLI tool aggregates public OSINT data by automating the techniques mentioned above and more. Whether you start with a username or a single email address, it can retrieve SSH/GPG keys, enumerate social accounts, and find "close friends" based on interactions.
Its standout features include a **Deep Scan** mode-which clones repositories to perform regex searches and TruffleHog secret detectionand an automated **Email Spoofing** engine that instantly identifies the account linked to any primary email address. Its standout features include a **Deep Scan** mode (clones repositories for regex searches and TruffleHog secret detection) and an automated **Email Spoofing** engine that identifies the account linked to any primary email address.
<a href="https://github.com/anotherhadi/github-recon" class="link-card" target="_blank"> <a href="https://github.com/anotherhadi/github-recon" class="link-card" target="_blank">
<span> <span>
+1 -1
View File
@@ -141,7 +141,7 @@ import Layout from "@src/layouts/Layout.astro";
</li> </li>
</ul> </ul>
<p class="text-base-content/70 text-sm leading-relaxed"> <p class="text-base-content/70 text-sm leading-relaxed">
If no proxies are configured, tools connect directly — behaviour is identical to before. If no proxies are configured, tools connect directly.
</p> </p>
</section> </section>
+1
View File
@@ -75,6 +75,7 @@ in {
IKY_FRONT_DIR = "${cfg.package}/share/iky/frontend"; IKY_FRONT_DIR = "${cfg.package}/share/iky/frontend";
IKY_SEARCH_TTL = cfg.searchTTL; IKY_SEARCH_TTL = cfg.searchTTL;
IKY_CLEANUP_INTERVAL = cfg.cleanupInterval; IKY_CLEANUP_INTERVAL = cfg.cleanupInterval;
HOME = "%S/iky";
}; };
serviceConfig = { serviceConfig = {