Rewrite project (and rename as wimi)

This commit is contained in:
0x1eef 2024-09-01 17:14:01 -03:00
parent 536486f6ac
commit a2322e9ba5
30 changed files with 79 additions and 262 deletions

View file

@ -1,4 +1,8 @@
## About <p align="center">
<img src="src/images/icon128x128.png"></img>
<br>
<strong>wimi</strong>
</p>
wimi relays information about your public IP address wimi relays information about your public IP address
from from
@ -13,12 +17,6 @@ The extension can be built locally and installed as a
developer extension / addon on both Chromium and FireFox. developer extension / addon on both Chromium and FireFox.
There are XPI files provided for FireFox users as well. There are XPI files provided for FireFox users as well.
## Example
<p align="center">
<img src="https://raw.githubusercontent.com/0x1eef/wimi/main/share/wimi/wimi.png">
</p>
## Install ## Install
**Chrome** **Chrome**

View file

@ -1,15 +0,0 @@
#!/bin/sh
set -e
sizes="16x16 48x48 64x64 128x128 256x256"
dir="src/images/icons"
for size in ${sizes}; do
convert ${dir}/icon.svg \
-resize ${size} \
-background none \
-trim +repage \
-fuzz 5% \
-transparent white \
-gravity center \
-extent $size \
${dir}/wtf${size}.png
done

22
bin/mkicons Executable file
View file

@ -0,0 +1,22 @@
#!/bin/sh
set -e
##
# variables
sizes="16x16 48x48 64x64 128x128 256x256"
dir="src/images/"
##
# main
for size in ${sizes}; do
gm convert \
"${dir}"/icon.svg \
-resize "${size}" \
-background none \
-trim +repage \
-fuzz 5% \
-transparent white \
-gravity center \
-extent "${size}" \
"${dir}"/icon"${size}".png
done

View file

@ -1,5 +1,17 @@
# -*- mode: org -*- # -*- mode: org -*-
** vNEXT
**** Add bin/mkicons
Replace the previous script
**** Add new icons
Replace the previous set of icons with wimi icons
**** Hello wimi
The project is now known as wimi - short for:
what is my ip address
** v0.5.1 ** v0.5.1
**** Shorten description in manifest **** Shorten description in manifest

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View file

@ -1,45 +1,11 @@
:root { :root {
/* Defaults */
--default-font-size: 1.15em;
/* Colors */ /* Colors */
--primary-red: #d73e48; --primary-color: #E3F2FD;
--primary-green: #32b643; --secondary-color: #333333;
--primary-blue: #302ecd; --accent-color: #007BFF;
--secondary-blue: #807fe2;
--primary-white: #FFF;
--secondary-white: #f1f1fc;
} }
body { #root {
font-size: small; background: var(--primary-color);
width: 400px; color: var(--secondary-color);
}
#root, .loader {
height: 100%;
}
a {
color: var(--primary-blue) !important;
text-decoration: none;
}
a:visited {
color: var(--primary-blue) !important;
}
a:active, a:focus, a:hover {
color: var(--primary-blue) !important;
text-decoration: underline;
}
footer {
background: var(--secondary-white);
color: var(--primary-red);
width: 100%;
}
.loader {
display: flex;
flex-direction: column;
align-items: center;
place-content: center;
} }

View file

@ -5,8 +5,8 @@
<link rel="stylesheet" href="/css/index.css"/> <link rel="stylesheet" href="/css/index.css"/>
<link rel="stylesheet" href="/css/components/BooleanLabel.css"/> <link rel="stylesheet" href="/css/components/BooleanLabel.css"/>
</head> </head>
<body class="h-60"> <body class="h-12 w-full">
<div id="root" class="h-full font-sans"></div> <div id="root"></div>
<script src="/js/index.js"></script> <script src="/js/index.js"></script>
</body> </body>
</html> </html>

1
src/images/icon.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 KiB

BIN
src/images/icon128x128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
src/images/icon16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
src/images/icon256x256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
src/images/icon48x48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

BIN
src/images/icon64x64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View file

@ -1,15 +1,29 @@
import { ErrorRenderer } from "~/components/ErrorRenderer";
import { ResponseRenderer } from "~/components/ResponseRenderer";
import { Loader } from "~/components/Loader";
import { useWebService } from "~/hooks/useWebService"; import { useWebService } from "~/hooks/useWebService";
export function App() { export function App() {
const [response, error] = useWebService(); const [response, error] = useWebService();
if (response) { if (response) {
return <ResponseRenderer response={response} />; return (
<div data-testid="response" className="font-sans p-2 flex">
<img className="w-8 h-8" src={`/images/flags/${response.countryCode}.svg`} />
<div className="flex flex-col ml-3">
<span className="text-xs">{response.IPAddress}</span>
<span className="text-xs">{response.ISP}</span>
</div>
</div>
);
} else if (error) { } else if (error) {
return <ErrorRenderer error={error} />; return (
<div data-testid="error" className="font-sans p-2 flex items-center w-full h-full">
<img className="w-8 h-8" src={`/images/icon.svg`} />
<span className="ml-3 text-xs">Error</span>
</div>
);
} else { } else {
return <Loader />; return (
<div data-testid="loading" className="font-sans p-2 flex items-center w-full h-full">
<img className="w-8 h-8" src={`/images/icon.svg`} />
<span className="ml-3 text-xs">Loading</span>
</div>
);
} }
} }

View file

@ -1,14 +0,0 @@
import { Footer } from "~/components/Footer";
export function ErrorRenderer({ error }: { error: Error }) {
const t = chrome.i18n.getMessage;
return (
<div data-testid="error" className="w-full h-full">
<div className="flex flex-col h-5/6 justify-center w-3/4 m-auto"></div>
<Footer>
<span className="font-bold">{t("error")}</span>:
<span data-testid="error-message">{error.message}</span>
</Footer>
</div>
);
}

View file

@ -1,9 +0,0 @@
import type { ReactNode } from "react";
export function Footer({ children }: { children: ReactNode }) {
return (
<footer className="flex h-10">
<div className="w-3/4 m-auto">{children}</div>
</footer>
);
}

View file

@ -1,11 +0,0 @@
import { Footer } from "~/components/Footer";
export function Loader() {
const t = chrome.i18n.getMessage;
return (
<div className="w-full h-full" data-testid="loader">
<div className="flex flex-col h-5/6 justify-center w-3/4 m-auto"></div>
<Footer>{t("loading")}</Footer>
</div>
);
}

View file

@ -1,56 +0,0 @@
import { useEffect, ReactNode } from "react";
import { TResponse } from "~/lib/response";
import { Footer } from "~/components/Footer";
type TFunction = typeof chrome.i18n.getMessage;
export function ResponseRenderer({ response }: { response: TResponse }) {
const t = chrome.i18n.getMessage;
useEffect(() => {
const { body } = document;
const width = (() => {
const addr = response.IPAddress;
if (addr.length >= 30) {
return 525;
} else if (addr.length >= 20) {
return 450;
} else {
return 400;
}
})();
body.style.width = `${width}px`;
}, [response]);
return (
<div className="w-full h-full">
<div className="flex flex-col h-5/6 justify-center w-3/4 m-auto" data-testid="response">
<Row name={t("ip_address")} value={response.IPAddress} />
<Row name={t("location")} value={`${response.City}, ${response.Country}`} />
<Row name={t("isp")} value={response.ISP} />
<Row name={t("tor_exit_node")} value={<BooleanLabel on={response.isTorExitNode} t={t} />} />
</div>
<Footer>
<a target="_blank" href={`https://${t("clean.myip.wtf")}`}>
{t("clean.myip.wtf")}
</a>
</Footer>
</div>
);
}
function BooleanLabel({ on, t }: { on: boolean; t: TFunction }) {
if (on) {
return <label className="label label-rounded label-success">{t("yes")}</label>;
} else {
return <label className="label label-rounded label-error">{t("no")}</label>;
}
}
function Row({ name, value }: { name: string; value: ReactNode }) {
return (
<div className="flex h-8">
<div className="flex w-2/4 items-center font-semibold">{name}</div>
<div className="flex w-3/4 items-center justify-end">{value}</div>
</div>
);
}

View file

@ -3,6 +3,7 @@ export type TResponse = {
ISP: string; ISP: string;
City: string; City: string;
Country: string; Country: string;
countryCode: string;
isTorExitNode: boolean; isTorExitNode: boolean;
}; };
@ -11,6 +12,7 @@ export type TServerResponse = {
YourISP: string; YourISP: string;
YourCity: string; YourCity: string;
YourCountry: string; YourCountry: string;
YourCountryCode: string;
YourTorExit: boolean; YourTorExit: boolean;
}; };
@ -21,6 +23,7 @@ export function Response(res: TServerResponse): TResponse {
self.ISP = res.YourISP; self.ISP = res.YourISP;
self.City = res.YourCity; self.City = res.YourCity;
self.Country = res.YourCountry; self.Country = res.YourCountry;
self.countryCode = res.YourCountryCode;
self.isTorExitNode = res.YourTorExit; self.isTorExitNode = res.YourTorExit;
return self; return self;

View file

@ -7,11 +7,11 @@
"default_popup": "/html/browseraction.html" "default_popup": "/html/browseraction.html"
}, },
"icons": { "icons": {
"16": "images/icons/wtf16x16.png", "16": "images/icon16x16.png",
"48": "images/icons/wtf48x48.png", "48": "images/icon48x48.png",
"64": "images/icons/wtf64x64.png", "64": "images/icon64x64.png",
"128": "images/icons/wtf128x128.png", "128": "images/icon128x128.png",
"256": "images/icons/wtf256x256.png" "256": "images/icon256x256.png"
}, },
"permissions": [], "permissions": [],
"default_locale": "en", "default_locale": "en",

View file

@ -24,7 +24,7 @@ describe("App.tsx", () => {
test("loading text is rendered", () => { test("loading text is rendered", () => {
render(<App/>); render(<App/>);
expect(screen.getByText("Loading...")).toBeInTheDocument(); expect(screen.getByTestId("loading")).toBeInTheDocument();
}); });
}); });

View file

@ -1,27 +0,0 @@
import React from "react";
import '@testing-library/jest-dom';
import { render, screen } from "@testing-library/react";
import { ErrorRenderer } from "~/components/ErrorRenderer";
import { getMessage } from "./mocks/chrome.i18n";
describe("ErrorRenderer.tsx", () => {
const globalChrome = global.chrome;
const error = new Error("This is an example error message");
beforeEach(() => {
const chrome: any = { i18n: { getMessage } };
global.chrome = chrome;
render(<ErrorRenderer error={error}/>);
});
afterEach(() => {
global.chrome = globalChrome;
});
test("an error is rendered", () => {
const { getByTestId, getByText } = screen;
const span = getByTestId("error-message");
expect(getByText("Error")).toBeInTheDocument();
expect(span.textContent).toEqual(error.message);
});
});

View file

@ -1,67 +0,0 @@
import React from "react";
import '@testing-library/jest-dom';
import { render, screen } from "@testing-library/react";
import { ResponseRenderer } from "~/components/ResponseRenderer";
import { getMessage } from "./mocks/chrome.i18n";
describe("ResponseRenderer.tsx", () => {
const globalChrome = global.chrome;
beforeEach(() => {
const chrome: any = { i18n: { getMessage } };
global.chrome = chrome;
});
afterEach(() => {
global.chrome = globalChrome;
});
const defaultResponse = {
IPAddress: "89.222.123.45",
ISP: "FooBar Ltd",
City: "FooBar City",
Country: "United States of FooBar",
isTorExitNode: false
};
describe("when isTorExitNode is false", () => {
const response = { ...defaultResponse };
beforeEach(() => {
render(<ResponseRenderer response={response}/>);
});
test("an IP address is rendered", () => {
expect(screen.getByText("IP Address")).toBeInTheDocument();
expect(screen.getByText(response.IPAddress)).toBeInTheDocument();
});
test("an ISP is rendered", () => {
expect(screen.getByText("ISP")).toBeInTheDocument();
expect(screen.getByText(response.ISP)).toBeInTheDocument();
});
test("a location is rendered", () => {
expect(screen.getByText("Location")).toBeInTheDocument();
expect(screen.getByText(`${response.City}, ${response.Country}`)).toBeInTheDocument();
});
test("isTorExitNode is rendered as No", () => {
expect(screen.getByText("Tor exit node")).toBeInTheDocument();
expect(screen.getByText("No")).toBeInTheDocument();
});
});
describe("when isTorExitNode is true", () => {
const response = { ...defaultResponse, isTorExitNode: true };
beforeEach(() => {
render(<ResponseRenderer response={response}/>);
});
test("isTorExitNode is rendered as Yes", () => {
expect(screen.getByText("Tor exit node")).toBeInTheDocument();
expect(screen.getByText("Yes")).toBeInTheDocument();
});
});
});

View file

@ -8,6 +8,7 @@ export function success(_path: RequestInfo | URL, _options?: RequestInit) {
YourISP: "FooBar Ltd", YourISP: "FooBar Ltd",
YourCity: "Foo City", YourCity: "Foo City",
YourCountry: "United States of FooBar", YourCountry: "United States of FooBar",
YourCountryCode: "BR",
YourTorExit: false YourTorExit: false
}) })
) )