Feature: windows support (#2)

* feat: support windows password fetching

* feat: highlight current wifi ssid on windows. refactor windows code
This commit is contained in:
Huakun Shen 2025-01-21 10:12:00 -05:00 committed by GitHub
parent 09aaf3fdbd
commit 7406729799
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 206 additions and 107 deletions

View File

@ -22,4 +22,5 @@ jobs:
run: | run: |
bun install bun install
bun run build bun run build
bunx kksh verify --publish
bunx jsr publish --allow-slow-types bunx jsr publish --allow-slow-types

View File

@ -11,8 +11,9 @@
``` ```
- Windows - Windows
```powershell ```powershell
$_, $ssid = ((netsh wlan show interface | findstr "Profile" | findstr /v "mode") -split ":",2).trim(); (((netsh wlan show profiles | findstr "Profile") -split ":",2) | findstr /v "Profile").trim(); # find all wifi ssid
$_, $pass = ((netsh wlan show profile name=$ssid key=clear | findstr Key) -split ":").trim(); $_, $ssid = ((netsh wlan show interface | findstr "Profile" | findstr /v "mode") -split ":",2).trim(); # find current wifi ssid
$_, $pass = ((netsh wlan show profile name=$ssid key=clear | findstr Key) -split ":").trim(); # find current wifi password
``` ```
- Linux - Linux
```bash ```bash

View File

@ -1,6 +1,6 @@
{ {
"name": "@kunkun/kunkun-ext-wifi-password", "name": "@kunkun/kunkun-ext-wifi-password",
"version": "0.1.5", "version": "0.1.7",
"license": "MIT", "license": "MIT",
"exports": "./mod.ts", "exports": "./mod.ts",
"publish": { "publish": {

View File

@ -2,7 +2,7 @@
"$schema": "https://schema.kunkun.sh", "$schema": "https://schema.kunkun.sh",
"name": "kunkun-ext-wifi-password", "name": "kunkun-ext-wifi-password",
"license": "MIT", "license": "MIT",
"version": "0.1.5", "version": "0.1.7",
"type": "module", "type": "module",
"kunkun": { "kunkun": {
"name": "Wifi Password", "name": "Wifi Password",
@ -35,6 +35,38 @@
"-w" "-w"
] ]
} }
},
{
"cmd": {
"program": "netsh",
"args": [
"wlan",
"show",
"profiles"
]
}
},
{
"cmd": {
"program": "netsh",
"args": [
"wlan",
"show",
"interfaces"
]
}
},
{
"cmd": {
"program": "netsh",
"args": [
"wlan",
"show",
"profile",
"name=.+",
"key=clear"
]
}
} }
] ]
} }

View File

@ -1,99 +1,164 @@
import { import {
Action, Action,
clipboard, clipboard,
expose, expose,
Form, Form,
fs, fs,
Icon, Icon,
IconEnum, IconEnum,
List, List,
Markdown, Markdown,
os, os,
path, path,
shell, shell,
toast, toast,
ui, ui,
WorkerExtension WorkerExtension,
} from "@kksh/api/ui/worker" } from "@kksh/api/ui/worker";
import qrcode from "qrcode" import qrcode from "qrcode";
class ExtensionTemplate extends WorkerExtension { async function windowsGetCurrentWifiSsid() {
networks: string[] = [] const cmd = shell.createCommand("netsh", ["wlan", "show", "interfaces"]);
const result = await cmd.execute();
if (result.code !== 0) {
return undefined;
}
const lines = result.stdout.split("\n");
const ssid = lines.find((line) => line.includes("SSID"));
return ssid ? ssid.split(":")[1].trim() : undefined;
}
get listItems() { async function windowsGetWifiPassword(ssid: string) {
return this.networks.map( const cmd = shell.createCommand("netsh", [
(x) => "wlan",
new List.Item({ "show",
title: x, "profile",
value: x, "name=" + ssid,
icon: new Icon({ "key=clear",
type: IconEnum.Iconify, ]);
value: "mdi:wifi" const result = await cmd.execute();
}) if (result.code !== 0) {
}) return undefined;
) }
} return result.stdout
.split("\n")
.find((line) => line.includes("Key Content"))
?.split(":")[1]
.trim();
}
async load() { async function windowsGetWifiSsids() {
ui.setSearchBarPlaceholder("Search for wifi and press enter to get password") const cmd = shell.createCommand("netsh", ["wlan", "show", "profiles"]);
const platform = await os.platform() const result = await cmd.execute();
if (platform === "macos") { if (result.code !== 0) {
const cmd = shell.createCommand("networksetup", ["-listpreferredwirelessnetworks", "en0"]) return undefined;
const result = await cmd.execute() }
if (result.code !== 0) { return result.stdout
toast.error("Failed to get wifi password") .split("\n")
return .filter((line) => line.includes("User Profile"))
} .map((line) => line.split(":")[1].trim());
this.networks = result.stdout }
.trim()
.split("\n")
.slice(1)
.map((x) => x.trim())
}
return ui.render(
new List.List({
items: this.listItems
})
)
}
async onListItemSelected(ssid: string): Promise<void> { class ListWifiPasswords extends WorkerExtension {
ui.render( networks: string[] = [];
new List.List({ currentWifiPassword: string | undefined;
inherits: ["items"],
detail: undefined get listItems() {
}) return this.networks.map(
) (x) =>
const cmd = shell.createCommand("security", [ new List.Item({
"find-generic-password", title: x,
"-D", value: x,
`AirPort network password`, icon: new Icon({
"-a", type: IconEnum.Iconify,
ssid, value: "mdi:wifi",
"-w" hexColor: this.currentWifiPassword === x ? "#ff0" : undefined,
]) }),
const result = await cmd.execute() })
if (result.code !== 0) { );
console.log(result.stderr) }
toast.error("Failed to get wifi password")
return async load() {
} ui.setSearchBarPlaceholder(
const wifiPassword = result.stdout.trim() "Search for wifi and press enter to get password"
toast.success(`Wifi password: ${wifiPassword}, written to clipboard`) );
clipboard.writeText(wifiPassword) const platform = await os.platform();
const wifiConnectUrl = `WIFI:S:${ssid};T:WPA;P:${wifiPassword};;` if (platform === "macos") {
let qrcodeSvg: string | undefined const cmd = shell.createCommand("networksetup", [
try { "-listpreferredwirelessnetworks",
qrcodeSvg = await qrcode.toString(wifiConnectUrl) "en0",
} catch (error) { ]);
toast.error(`Failed to generate QR code: ${error}`) const result = await cmd.execute();
console.error(error) if (result.code !== 0) {
} toast.error("Failed to get wifi password");
// <img src="${qrcodeImageBase64}" style="display: block; margin: 0 auto;" /> return;
if (!qrcodeSvg) { }
return toast.error("Failed to generate QR code") this.networks = result.stdout
} .trim()
const markdown = ` .split("\n")
.slice(1)
.map((x) => x.trim());
} else if (platform === "windows") {
this.currentWifiPassword = await windowsGetCurrentWifiSsid();
this.networks = (await windowsGetWifiSsids()) ?? [];
} else if (platform === "linux") {
}
return ui.render(
new List.List({
items: this.listItems,
})
);
}
async onListItemSelected(ssid: string): Promise<void> {
const platform = await os.platform();
ui.render(
new List.List({
inherits: ["items"],
detail: undefined,
})
);
let wifiPassword: string | undefined;
if (platform === "macos") {
const cmd = shell.createCommand("security", [
"find-generic-password",
"-D",
`AirPort network password`,
"-a",
ssid,
"-w",
]);
const result = await cmd.execute();
if (result.code !== 0) {
console.log(result.stderr);
toast.error("Failed to get wifi password");
return;
}
wifiPassword = result.stdout.trim();
} else if (platform === "windows") {
wifiPassword = await windowsGetWifiPassword(ssid);
}
if (!wifiPassword) {
toast.error("Failed to get wifi password");
return;
}
toast.success(`Wifi password: ${wifiPassword}, written to clipboard`);
clipboard.writeText(wifiPassword);
const wifiConnectUrl = `WIFI:S:${ssid};T:WPA;P:${wifiPassword};;`;
let qrcodeSvg: string | undefined;
try {
qrcodeSvg = await qrcode.toString(wifiConnectUrl);
} catch (error) {
toast.error(`Failed to generate QR code: ${error}`);
console.error(error);
}
// <img src="${qrcodeImageBase64}" style="display: block; margin: 0 auto;" />
if (!qrcodeSvg) {
return toast.error("Failed to generate QR code");
}
const markdown = `
<div style="display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 2em;"> <div style="display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 2em;">
<div style="width: 10em; height: 10em; display: block;"> <div style="width: 10em; height: 10em; display: block;">
${qrcodeSvg} ${qrcodeSvg}
@ -101,17 +166,17 @@ class ExtensionTemplate extends WorkerExtension {
<p style="text-align: center;">Wifi Password: <strong>${wifiPassword}</strong></p> <p style="text-align: center;">Wifi Password: <strong>${wifiPassword}</strong></p>
<p style="text-align: center;">Connect URL: <strong>${wifiConnectUrl}</strong></p> <p style="text-align: center;">Connect URL: <strong>${wifiConnectUrl}</strong></p>
</div> </div>
` `;
return ui.render( return ui.render(
new List.List({ new List.List({
inherits: ["items"], inherits: ["items"],
detail: new List.ItemDetail({ detail: new List.ItemDetail({
width: 60, width: 60,
children: [new Markdown(markdown)] children: [new Markdown(markdown)],
}) }),
}) })
) );
} }
} }
expose(new ExtensionTemplate()) expose(new ListWifiPasswords());