├── .github └── workflows │ └── ci.yml ├── .gitignore ├── 18344CF4-87B8-4EAC-960F-0424188DBD78.png ├── 328256C3-89CB-4454-91D1-8A35107A23EB.png ├── C416DACE-0F76-4BF9-A84C-D9B5497B1B00.png ├── D4820948-B40E-4B36-BD86-21E6BFDB7FF8.png ├── LICENSE.md ├── README.md ├── icon.png ├── info.plist ├── media ├── bluetooth.png ├── dns-used.png ├── dns.png ├── ethernet.png ├── network.png ├── vpn-connected.png ├── vpn.png ├── wifi-1.png ├── wifi-2.png ├── wifi-3.png ├── wifi-4.png ├── wifi-active-1.png ├── wifi-active-2.png ├── wifi-active-3.png ├── wifi-active-4.png ├── wifi-error-4.png ├── wifi-lock-1.png ├── wifi-lock-2.png ├── wifi-lock-3.png ├── wifi-lock-4.png ├── wifi-star-1.png ├── wifi-star-2.png ├── wifi-star-3.png └── wifi-star-4.png ├── screenshots ├── wifi-preview.png └── wifilist-preview.png ├── src ├── ap.sh ├── default-dns.conf ├── dns.sh ├── ethernet.sh ├── ethernetCommon.sh ├── helpers.sh ├── media.sh ├── vpn.sh ├── wifi.sh ├── wifiCommon.sh └── workflowHandler.sh └── tests ├── apTests.bats ├── dnsTests.bats ├── ethernetTests.bats ├── variables.bash ├── vpnTests.bats └── wifiTests.bats /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | runs-on: macos-latest 8 | 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@v1 12 | 13 | - name: Install bats 14 | run: brew install bats-core 15 | 16 | - name: Test 17 | run: bats --tap tests 18 | 19 | build: 20 | runs-on: ubuntu-latest 21 | needs: [test] 22 | 23 | steps: 24 | - name: Checkout 25 | uses: actions/checkout@v1 26 | 27 | - name: Build Alfred Workflow 28 | uses: mperezi/build-alfred-workflow@v1 29 | id: alfred_builder 30 | with: 31 | workflow_dir: "." 32 | exclude_patterns: ".git/* .github/* .gitignore" 33 | 34 | - name: Rename 35 | run: mv ${{ steps.alfred_builder.outputs.workflow_file }} Network.alfredworkflow 36 | 37 | - name: Upload Artifact 38 | uses: actions/upload-artifact@v1 39 | with: 40 | name: Network.alfredworkflow 41 | path: Network.alfredworkflow 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | todo.md 3 | temp 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /18344CF4-87B8-4EAC-960F-0424188DBD78.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/18344CF4-87B8-4EAC-960F-0424188DBD78.png -------------------------------------------------------------------------------- /328256C3-89CB-4454-91D1-8A35107A23EB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/328256C3-89CB-4454-91D1-8A35107A23EB.png -------------------------------------------------------------------------------- /C416DACE-0F76-4BF9-A84C-D9B5497B1B00.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/C416DACE-0F76-4BF9-A84C-D9B5497B1B00.png -------------------------------------------------------------------------------- /D4820948-B40E-4B36-BD86-21E6BFDB7FF8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/D4820948-B40E-4B36-BD86-21E6BFDB7FF8.png -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Martin Rodalgaard 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # network Alfred Network Workflow ![](https://github.com/mrodalgaard/alfred-network-workflow/workflows/CI/badge.svg) 2 | 3 | Alfred workflow that can show and change your network settings: Wi-Fi, Ethernet, VPN, DNS, etc. 4 | 5 | This is a collection of the functionalities of already existing network-oriented workflows that I found half-baked or stalled. Improved on performance, usability and details. 6 | 7 | ## Install 8 | 9 | Go to [Latest Release](https://github.com/mrodalgaard/alfred-network-workflow/releases/latest) and under `Assets` download `Network.alfredworkflow`. Once downloaded, double click the file and it will show up in Alfred. 10 | 11 | Or install directly from [Alfred Gallery](https://alfred.app/workflows/mrodalgaard/network/). 12 | 13 | ## Usage 14 | 15 | * Type `wifi` to show Wi-Fi info and enable/disable. 16 | * Type `eth` to show ethernet info (if connected). 17 | * Type `wifilist` to scan for Wi-Fi hotspots. 18 | * Type `vpn` to list configured VPNs and connect. 19 | * Type `dns` to list and change DNS settings for primary connection. 20 | 21 |

22 | alfred-wifi-workflow-wifi 23 | alfred-wifi-workflow-wifilist 24 |

25 | 26 | ## Limitations 27 | 28 | Requires Alfred Powerpack to install this extension. 29 | 30 | This workflow might behave differently on macOS versions older than 10.7 Lion. This workflow is primarily implemented in Bash interacting with macOS network cli utils (like `networksetup`, `scutil` and `airport`) with a little help from AppleScript. 31 | 32 | Most functionality of this workflow will work without your user being administrator on your machine (see if your user is set as `Admin` or `Standard` in "System Settings.app" -> "Users & Groups"), but actions which changes network settings might fail if you are only a standard user. 33 | 34 | WIFI / Access Point changes requires your keychain password which is a known limitation [Read more](https://github.com/mrodalgaard/alfred-network-workflow/issues/11#issuecomment-559252188). 35 | 36 | ## Tests 37 | 38 | [bats](https://github.com/bats-core/bats-core) is used for automatic testing of Bash functionality. Install with `brew install bats-core` using [brew](http://brew.sh/). 39 | 40 | Run tests: `bats tests` 41 | 42 | ## Credits 43 | 44 | > Contributions, bug reports and feature requests are very welcome. 45 | 46 | >     _- Martin_ 47 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/icon.png -------------------------------------------------------------------------------- /info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | bundleid 6 | dk.rodalgaard.alfred.network 7 | category 8 | Tools 9 | connections 10 | 11 | 18344CF4-87B8-4EAC-960F-0424188DBD78 12 | 13 | 14 | destinationuid 15 | 709DCCB5-61D3-4693-8C39-F0A34FA8F6AD 16 | modifiers 17 | 0 18 | modifiersubtext 19 | 20 | vitoclose 21 | 22 | 23 | 24 | 306C666D-40A5-42F2-A4A0-776B168E7799 25 | 26 | 328256C3-89CB-4454-91D1-8A35107A23EB 27 | 28 | 29 | destinationuid 30 | E94FF980-5C9E-41B4-862B-30C04F904070 31 | modifiers 32 | 0 33 | modifiersubtext 34 | 35 | vitoclose 36 | 37 | 38 | 39 | 4C74C452-E821-4F45-9B74-F0C28889BA4F 40 | 41 | 42 | destinationuid 43 | C8DB69EA-BBA7-41E9-B60C-CF315A5F1CAD 44 | modifiers 45 | 0 46 | modifiersubtext 47 | 48 | vitoclose 49 | 50 | 51 | 52 | 709DCCB5-61D3-4693-8C39-F0A34FA8F6AD 53 | 54 | 55 | destinationuid 56 | E675530B-3605-4460-8074-3122E0461D9D 57 | modifiers 58 | 0 59 | modifiersubtext 60 | 61 | vitoclose 62 | 63 | 64 | 65 | 82D72C1A-0B33-483F-AA5E-E25B02CC7971 66 | 67 | C416DACE-0F76-4BF9-A84C-D9B5497B1B00 68 | 69 | 70 | destinationuid 71 | 306C666D-40A5-42F2-A4A0-776B168E7799 72 | modifiers 73 | 0 74 | modifiersubtext 75 | 76 | vitoclose 77 | 78 | 79 | 80 | C8DB69EA-BBA7-41E9-B60C-CF315A5F1CAD 81 | 82 | D4820948-B40E-4B36-BD86-21E6BFDB7FF8 83 | 84 | 85 | destinationuid 86 | 82D72C1A-0B33-483F-AA5E-E25B02CC7971 87 | modifiers 88 | 0 89 | modifiersubtext 90 | 91 | vitoclose 92 | 93 | 94 | 95 | E94FF980-5C9E-41B4-862B-30C04F904070 96 | 97 | 98 | destinationuid 99 | E675530B-3605-4460-8074-3122E0461D9D 100 | modifiers 101 | 0 102 | modifiersubtext 103 | 104 | vitoclose 105 | 106 | 107 | 108 | 109 | createdby 110 | Martin Rodalgaard 111 | description 112 | Show and change your network settings 113 | disabled 114 | 115 | name 116 | Network 117 | objects 118 | 119 | 120 | config 121 | 122 | alfredfiltersresults 123 | 124 | alfredfiltersresultsmatchmode 125 | 0 126 | argumenttreatemptyqueryasnil 127 | 128 | argumenttrimmode 129 | 0 130 | argumenttype 131 | 2 132 | escaping 133 | 102 134 | keyword 135 | wifi 136 | queuedelaycustom 137 | 3 138 | queuedelayimmediatelyinitially 139 | 140 | queuedelaymode 141 | 0 142 | queuemode 143 | 1 144 | runningsubtext 145 | Fetching wifi information ... 146 | script 147 | . src/wifi.sh 148 | scriptargtype 149 | 0 150 | scriptfile 151 | 152 | subtext 153 | Wi-Fi info 154 | title 155 | Wi-Fi 156 | type 157 | 0 158 | withspace 159 | 160 | 161 | type 162 | alfred.workflow.input.scriptfilter 163 | uid 164 | 328256C3-89CB-4454-91D1-8A35107A23EB 165 | version 166 | 3 167 | 168 | 169 | config 170 | 171 | concurrently 172 | 173 | escaping 174 | 102 175 | script 176 | . src/wifi.sh "{query}" 177 | scriptargtype 178 | 0 179 | scriptfile 180 | 181 | type 182 | 0 183 | 184 | type 185 | alfred.workflow.action.script 186 | uid 187 | E94FF980-5C9E-41B4-862B-30C04F904070 188 | version 189 | 2 190 | 191 | 192 | config 193 | 194 | autopaste 195 | 196 | clipboardtext 197 | {query} 198 | ignoredynamicplaceholders 199 | 200 | transient 201 | 202 | 203 | type 204 | alfred.workflow.output.clipboard 205 | uid 206 | E675530B-3605-4460-8074-3122E0461D9D 207 | version 208 | 3 209 | 210 | 211 | config 212 | 213 | alfredfiltersresults 214 | 215 | alfredfiltersresultsmatchmode 216 | 0 217 | argumenttreatemptyqueryasnil 218 | 219 | argumenttrimmode 220 | 0 221 | argumenttype 222 | 2 223 | escaping 224 | 102 225 | keyword 226 | eth 227 | queuedelaycustom 228 | 3 229 | queuedelayimmediatelyinitially 230 | 231 | queuedelaymode 232 | 0 233 | queuemode 234 | 1 235 | runningsubtext 236 | Fetching ethernet information ... 237 | script 238 | . src/ethernet.sh 239 | scriptargtype 240 | 0 241 | scriptfile 242 | 243 | subtext 244 | Ethernet Info 245 | title 246 | Ethernet 247 | type 248 | 0 249 | withspace 250 | 251 | 252 | type 253 | alfred.workflow.input.scriptfilter 254 | uid 255 | 18344CF4-87B8-4EAC-960F-0424188DBD78 256 | version 257 | 3 258 | 259 | 260 | config 261 | 262 | concurrently 263 | 264 | escaping 265 | 102 266 | script 267 | . src/ethernet.sh "{query}" 268 | scriptargtype 269 | 0 270 | scriptfile 271 | 272 | type 273 | 0 274 | 275 | type 276 | alfred.workflow.action.script 277 | uid 278 | 709DCCB5-61D3-4693-8C39-F0A34FA8F6AD 279 | version 280 | 2 281 | 282 | 283 | config 284 | 285 | concurrently 286 | 287 | escaping 288 | 102 289 | script 290 | . src/ap.sh "{query}" 291 | scriptargtype 292 | 0 293 | scriptfile 294 | 295 | type 296 | 0 297 | 298 | type 299 | alfred.workflow.action.script 300 | uid 301 | C8DB69EA-BBA7-41E9-B60C-CF315A5F1CAD 302 | version 303 | 2 304 | 305 | 306 | config 307 | 308 | alfredfiltersresults 309 | 310 | alfredfiltersresultsmatchmode 311 | 2 312 | argumenttreatemptyqueryasnil 313 | 314 | argumenttrimmode 315 | 0 316 | argumenttype 317 | 1 318 | escaping 319 | 102 320 | keyword 321 | wifilist 322 | queuedelaycustom 323 | 3 324 | queuedelayimmediatelyinitially 325 | 326 | queuedelaymode 327 | 0 328 | queuemode 329 | 1 330 | runningsubtext 331 | Scanning for access points ... 332 | script 333 | . src/ap.sh 334 | scriptargtype 335 | 0 336 | scriptfile 337 | 338 | subtext 339 | List of Wi-Fi access points 340 | title 341 | Wi-Fi List 342 | type 343 | 0 344 | withspace 345 | 346 | 347 | type 348 | alfred.workflow.input.scriptfilter 349 | uid 350 | 4C74C452-E821-4F45-9B74-F0C28889BA4F 351 | version 352 | 3 353 | 354 | 355 | config 356 | 357 | concurrently 358 | 359 | escaping 360 | 68 361 | script 362 | . src/vpn.sh "{query}" 363 | scriptargtype 364 | 0 365 | scriptfile 366 | 367 | type 368 | 0 369 | 370 | type 371 | alfred.workflow.action.script 372 | uid 373 | 306C666D-40A5-42F2-A4A0-776B168E7799 374 | version 375 | 2 376 | 377 | 378 | config 379 | 380 | alfredfiltersresults 381 | 382 | alfredfiltersresultsmatchmode 383 | 2 384 | argumenttreatemptyqueryasnil 385 | 386 | argumenttrimmode 387 | 0 388 | argumenttype 389 | 1 390 | escaping 391 | 102 392 | keyword 393 | vpn 394 | queuedelaycustom 395 | 3 396 | queuedelayimmediatelyinitially 397 | 398 | queuedelaymode 399 | 0 400 | queuemode 401 | 1 402 | runningsubtext 403 | Fetching VPN list ... 404 | script 405 | . src/vpn.sh 406 | scriptargtype 407 | 0 408 | scriptfile 409 | 410 | subtext 411 | List of VPNs 412 | title 413 | VPN List 414 | type 415 | 0 416 | withspace 417 | 418 | 419 | type 420 | alfred.workflow.input.scriptfilter 421 | uid 422 | C416DACE-0F76-4BF9-A84C-D9B5497B1B00 423 | version 424 | 3 425 | 426 | 427 | config 428 | 429 | concurrently 430 | 431 | escaping 432 | 102 433 | script 434 | . src/dns.sh "{query}" 435 | scriptargtype 436 | 0 437 | scriptfile 438 | 439 | type 440 | 0 441 | 442 | type 443 | alfred.workflow.action.script 444 | uid 445 | 82D72C1A-0B33-483F-AA5E-E25B02CC7971 446 | version 447 | 2 448 | 449 | 450 | config 451 | 452 | alfredfiltersresults 453 | 454 | alfredfiltersresultsmatchmode 455 | 2 456 | argumenttreatemptyqueryasnil 457 | 458 | argumenttrimmode 459 | 0 460 | argumenttype 461 | 1 462 | escaping 463 | 102 464 | keyword 465 | dns 466 | queuedelaycustom 467 | 3 468 | queuedelayimmediatelyinitially 469 | 470 | queuedelaymode 471 | 0 472 | queuemode 473 | 1 474 | runningsubtext 475 | Fetching DNS list ... 476 | script 477 | . src/dns.sh 478 | scriptargtype 479 | 0 480 | scriptfile 481 | 482 | subtext 483 | List of DNS 484 | title 485 | DNS List 486 | type 487 | 0 488 | withspace 489 | 490 | 491 | type 492 | alfred.workflow.input.scriptfilter 493 | uid 494 | D4820948-B40E-4B36-BD86-21E6BFDB7FF8 495 | version 496 | 3 497 | 498 | 499 | readme 500 | https://github.com/mrodalgaard/alfred-network-workflow 501 | uidata 502 | 503 | 18344CF4-87B8-4EAC-960F-0424188DBD78 504 | 505 | xpos 506 | 30 507 | ypos 508 | 140 509 | 510 | 306C666D-40A5-42F2-A4A0-776B168E7799 511 | 512 | xpos 513 | 230 514 | ypos 515 | 380 516 | 517 | 328256C3-89CB-4454-91D1-8A35107A23EB 518 | 519 | xpos 520 | 30 521 | ypos 522 | 20 523 | 524 | 4C74C452-E821-4F45-9B74-F0C28889BA4F 525 | 526 | xpos 527 | 30 528 | ypos 529 | 260 530 | 531 | 709DCCB5-61D3-4693-8C39-F0A34FA8F6AD 532 | 533 | xpos 534 | 230 535 | ypos 536 | 140 537 | 538 | 82D72C1A-0B33-483F-AA5E-E25B02CC7971 539 | 540 | xpos 541 | 230 542 | ypos 543 | 500 544 | 545 | C416DACE-0F76-4BF9-A84C-D9B5497B1B00 546 | 547 | xpos 548 | 30 549 | ypos 550 | 380 551 | 552 | C8DB69EA-BBA7-41E9-B60C-CF315A5F1CAD 553 | 554 | xpos 555 | 230 556 | ypos 557 | 260 558 | 559 | D4820948-B40E-4B36-BD86-21E6BFDB7FF8 560 | 561 | xpos 562 | 30 563 | ypos 564 | 500 565 | 566 | E675530B-3605-4460-8074-3122E0461D9D 567 | 568 | xpos 569 | 510 570 | ypos 571 | 20 572 | 573 | E94FF980-5C9E-41B4-862B-30C04F904070 574 | 575 | xpos 576 | 230 577 | ypos 578 | 20 579 | 580 | 581 | userconfigurationconfig 582 | 583 | version 584 | 1.7 585 | webaddress 586 | https://github.com/mrodalgaard/alfred-network-workflow 587 | 588 | 589 | -------------------------------------------------------------------------------- /media/bluetooth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/bluetooth.png -------------------------------------------------------------------------------- /media/dns-used.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/dns-used.png -------------------------------------------------------------------------------- /media/dns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/dns.png -------------------------------------------------------------------------------- /media/ethernet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/ethernet.png -------------------------------------------------------------------------------- /media/network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/network.png -------------------------------------------------------------------------------- /media/vpn-connected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/vpn-connected.png -------------------------------------------------------------------------------- /media/vpn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/vpn.png -------------------------------------------------------------------------------- /media/wifi-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/wifi-1.png -------------------------------------------------------------------------------- /media/wifi-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/wifi-2.png -------------------------------------------------------------------------------- /media/wifi-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/wifi-3.png -------------------------------------------------------------------------------- /media/wifi-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/wifi-4.png -------------------------------------------------------------------------------- /media/wifi-active-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/wifi-active-1.png -------------------------------------------------------------------------------- /media/wifi-active-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/wifi-active-2.png -------------------------------------------------------------------------------- /media/wifi-active-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/wifi-active-3.png -------------------------------------------------------------------------------- /media/wifi-active-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/wifi-active-4.png -------------------------------------------------------------------------------- /media/wifi-error-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/wifi-error-4.png -------------------------------------------------------------------------------- /media/wifi-lock-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/wifi-lock-1.png -------------------------------------------------------------------------------- /media/wifi-lock-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/wifi-lock-2.png -------------------------------------------------------------------------------- /media/wifi-lock-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/wifi-lock-3.png -------------------------------------------------------------------------------- /media/wifi-lock-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/wifi-lock-4.png -------------------------------------------------------------------------------- /media/wifi-star-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/wifi-star-1.png -------------------------------------------------------------------------------- /media/wifi-star-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/wifi-star-2.png -------------------------------------------------------------------------------- /media/wifi-star-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/wifi-star-3.png -------------------------------------------------------------------------------- /media/wifi-star-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/media/wifi-star-4.png -------------------------------------------------------------------------------- /screenshots/wifi-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/screenshots/wifi-preview.png -------------------------------------------------------------------------------- /screenshots/wifilist-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrodalgaard/alfred-network-workflow/0c1beda36a0d38dd7145c251439e76ed4c951a87/screenshots/wifilist-preview.png -------------------------------------------------------------------------------- /src/ap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . src/wifiCommon.sh 4 | . src/workflowHandler.sh 5 | 6 | # Handle action 7 | if [ "$1" != "" ]; then 8 | if [ "$1" == "Null" ]; then 9 | exit 10 | fi 11 | 12 | # Extract password for AP, which is needed by networksetup 13 | PASS=$(security 2>&1 >/dev/null find-generic-password -ga "$1" \ 14 | | awk '/ / {print $2}' | tr -d '"') 15 | networksetup -setairportnetwork "$INTERFACE" "$1" "$PASS" 16 | exit 17 | fi 18 | 19 | INFO=$($AIRPORT --getinfo) 20 | SAVED_APS=$(networksetup -listpreferredwirelessnetworks "$INTERFACE") 21 | 22 | ACTIVE_ID=$(getBSSID "$INFO") 23 | if [ "$ACTIVE_ID" == "" ]; then 24 | ACTIVE_ID=$(getSSID "$INFO") 25 | fi 26 | 27 | # Scan airport access points and remove header 28 | APS=$($AIRPORT --scan | awk 'NR>1') 29 | 30 | if [ "$APS" == "" ]; then 31 | # Handle no wifi access points found 32 | addResult "" "Null" "No access points found" "" "$ICON_WIFI_ERROR" 33 | else 34 | PARSED_APS='' 35 | 36 | # Parse each AP scan line 37 | while read -r LINE; do 38 | PARSED_APS+=$(getAPDetails "$LINE" "$ACTIVE_ID" "$SAVED_APS")$'\n' 39 | done <<< "$APS" 40 | 41 | # Sort parsed access points by priority and name 42 | PARSED_APS=$(echo "$PARSED_APS" | sort) 43 | 44 | # Sort and create workflow results from each line 45 | while read -r LINE; do 46 | IFS='~' read -r -a ARRAY <<< "$LINE" 47 | 48 | if [ "${ARRAY[0]}" != "" ]; then 49 | addResult "" "${ARRAY[1]}" "${ARRAY[1]}" "RSSI ${ARRAY[3]} dBm, channel ${ARRAY[4]}" "${ARRAY[6]}" 50 | fi 51 | done <<< "$PARSED_APS" 52 | fi 53 | 54 | getXMLResults 55 | -------------------------------------------------------------------------------- /src/default-dns.conf: -------------------------------------------------------------------------------- 1 | # 2 | # @file dns.conf 3 | # 4 | # Alfred Network Workflow 5 | # Custom DNS List 6 | # 7 | # Format: 8 | # : 9 | # 10 | 11 | Google DNS : 8.8.8.8, 8.8.4.4 12 | OpenDNS : 208.67.222.222, 208.67.220.220 13 | Cloudflare DNS: 1.1.1.1, 1.0.0.1 14 | DNS.WATCH : 84.200.69.80, 84.200.70.40 15 | Alibaba DNS : 223.5.5.5, 223.6.6.6 16 | V2EX DNS : 199.91.73.222, 178.79.131.110 17 | 114 DNS : 114.114.114.114, 114.114.115.115 18 | -------------------------------------------------------------------------------- /src/dns.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . src/helpers.sh 4 | 5 | # Copy defaults to alfred cache dir if they do not exist 6 | FILE=$alfred_workflow_cache/dns.conf 7 | if [ ! -f "$FILE" ]; then 8 | mkdir -p "$alfred_workflow_cache" 9 | cp src/default-dns.conf "$FILE" 10 | fi 11 | 12 | NAME="$(getPrimaryInterfaceName)" 13 | 14 | # Handle action 15 | if [ "$1" != "" ]; then 16 | if [ "$1" == "EDIT" ]; then 17 | open -a TextEdit "$FILE" 18 | exit 19 | elif [ "$1" == "DEFAULT" ]; then 20 | DNS="empty" 21 | else 22 | DNS=$(echo "$1" | sed 's/ \/ / /g') 23 | fi 24 | 25 | networksetup -setdnsservers "${NAME%,*}" $DNS 26 | dscacheutil -flushcache 27 | exit 28 | fi 29 | 30 | DNSSTRING=$(getDNS "$(networksetup -getdnsservers "$NAME")") 31 | 32 | # Parse dns config file 33 | while read -r LINE; do 34 | DNSCONFIG=$(parseDNSLine "$LINE" "$DNSSTRING") 35 | IFS='~' read -r -a ARRAY <<< "$DNSCONFIG" 36 | 37 | if [ "$ARRAY" != "" ]; then 38 | addResult "" "${ARRAY[1]}" "${ARRAY[0]}" "${ARRAY[1]}" "${ARRAY[2]}" 39 | fi 40 | done < "$FILE" 41 | 42 | addResult "" "EDIT" "Edit DNS List" "" "$ICON_DNS" 43 | 44 | if [ "$DNSSTRING" == "" ]; then 45 | addResult "" "DEFAULT" "Default DNS (used)" "Default" "$ICON_DNS_USED" 46 | else 47 | addResult "" "DEFAULT" "Default DNS" "Default" "$ICON_DNS" 48 | fi 49 | 50 | getXMLResults 51 | -------------------------------------------------------------------------------- /src/ethernet.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . src/ethernetCommon.sh 4 | . src/workflowHandler.sh 5 | 6 | # Handle action 7 | if [ "$1" != "" ]; then 8 | echo "$1" | tr -d '\n' 9 | exit 10 | fi 11 | 12 | # Handle ethernet unconnected state 13 | if [ "$(getEthernetState "$INTERFACE")" == 0 ]; then 14 | addResult "" "" "Not Connected" "Ethernet is not connected" "$ICON_ETH" 15 | getXMLResults 16 | return 17 | fi 18 | 19 | # Get network configuration 20 | NETINFO=$(networksetup -getinfo "$NAME") 21 | NETCONFIG=$(getConnectionConfig "$NETINFO") 22 | 23 | MAC=$(getEthernetMac) 24 | NAME=$(getEthernetName) 25 | 26 | # Output IPv4 27 | IPv4=$(getIPv4 "$NETINFO") 28 | if [[ ! -z "$IPv4" ]]; then 29 | addResult "" "$IPv4" "$IPv4" "IPv4 address ($NETCONFIG)" "$ICON_ETH" 30 | fi 31 | 32 | # Output IPv6 33 | IPv6=$(getIPv6 "$NETINFO") 34 | if [ "$IPv6" != "" ]; then 35 | addResult "" "$IPv6" "$IPv6" "IPv6 address ($NETCONFIG)" "$ICON_ETH" 36 | fi 37 | 38 | # Output global IP 39 | GLOBALIP=$(getGlobalIP) 40 | if [ "$GLOBALIP" != "" ]; then 41 | addResult "" "$GLOBALIP" "$GLOBALIP" "Global IP" "$ICON_ETH" 42 | fi 43 | 44 | # Output VPN 45 | SCUTIL=$(scutil --nc list) 46 | VPN=$(getVPN "$SCUTIL") 47 | if [ "$VPN" != "" ]; then 48 | addResult "" "$VPN" "$VPN" "VPN connection" "$ICON_ETH" 49 | fi 50 | 51 | # Output DNS list 52 | DNSSTRING=$(getDNS "$(networksetup -getdnsservers "$NAME")") 53 | if [ "$DNSSTRING" != "" ]; then 54 | addResult "" "$DNSSTRING" "$DNSSTRING" "DNS list" "$ICON_ETH" 55 | fi 56 | 57 | addResult "" "" "$NAME connected" "$INTERFACE ($MAC)" "$ICON_ETH" 58 | 59 | getXMLResults 60 | -------------------------------------------------------------------------------- /src/ethernetCommon.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . src/helpers.sh 4 | 5 | LIST=$(networksetup -listallhardwareports) 6 | INTERFACE=$(getEthernetInterface "$LIST") 7 | NAME=$(getEthernetName "$LIST") 8 | -------------------------------------------------------------------------------- /src/helpers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . src/workflowHandler.sh 4 | . src/media.sh 5 | 6 | ETHERNET_REGEX="LAN$|Lan$|Ethernet$|AX[0-9A-Z]+$" 7 | WIFI_REGEX="Airport$|Wi-Fi$" 8 | 9 | PRIORITY_HIGH="1" 10 | PRIORITY_MEDIUM="2" 11 | PRIORITY_LOW="5" 12 | 13 | # Trim string 14 | # $1 = Input string 15 | # $! = Trimmed string 16 | trim () { 17 | str="$1" 18 | match=" " 19 | while [ "${str:0:${#match}}" == "$match" ]; do 20 | str="${str:${#match}:${#str}}" 21 | done 22 | while [ "${str:$((${#str}-${#match}))}" == "$match" ]; do 23 | str="${str:0:$((${#str} - ${#match}))}" 24 | done 25 | echo "$str" 26 | } 27 | 28 | # Get wifi state as boolean 29 | # $1 = Wi-Fi interface name 30 | # $! = Boolean 31 | getWifiState() { 32 | if [ "$(networksetup -getairportpower "$1" | grep On)" != "" ]; then 33 | echo 1 34 | else 35 | echo 0 36 | fi 37 | } 38 | 39 | # Get ethernet state as boolean 40 | # $1 = Ethernet interface name 41 | # $! = Boolean 42 | getEthernetState() { 43 | if [ "$1" != "" ]; then 44 | echo 1 45 | else 46 | echo 0 47 | fi 48 | } 49 | 50 | # Get wifi port name 51 | # $1 = networksetup -listallhardwareports 52 | # $! = String 53 | getWifiName() { 54 | local LIST=${1-$(networksetup -listallhardwareports)} 55 | local DETAILS=$(echo "$LIST" | grep -A 2 -E "$WIFI_REGEX") 56 | echo "$DETAILS" | grep -Eo "AirPort|Wi-Fi" 57 | } 58 | 59 | # Get ethernet port name 60 | # $1 = networksetup -listallhardwareports 61 | # $! = String 62 | getEthernetName() { 63 | local LIST=${1-$(networksetup -listallhardwareports)} 64 | local DETAILS=$(echo "$LIST" | grep -A 2 -E "$ETHERNET_REGEX") 65 | echo "$DETAILS" | awk '/Hardware / {print substr($0, index($0, $3))}' 66 | } 67 | 68 | # Get wifi interface name 69 | # $1 = networksetup -listallhardwareports 70 | # $! = String 71 | getWifiInterface() { 72 | local LIST=${1-$(networksetup -listallhardwareports)} 73 | local DETAILS=$(echo "$LIST" | grep -A 2 -E "$WIFI_REGEX") 74 | echo "$DETAILS" | grep -m 1 -o -e en[0-9] 75 | } 76 | 77 | # Get ethernet interface name 78 | # $1 = networksetup -listallhardwareports 79 | # $! = String 80 | getEthernetInterface() { 81 | local LIST=${1-$(networksetup -listallhardwareports)} 82 | local DETAILS=$(echo "$LIST" | grep -A 2 -E "$ETHERNET_REGEX") 83 | echo "$DETAILS" | grep -m 1 -o -e en[0-9] 84 | } 85 | 86 | # Get wifi mac address 87 | # $1 = networksetup -listallhardwareports 88 | # $! = String 89 | getWifiMac() { 90 | local LIST=${1-$(networksetup -listallhardwareports)} 91 | local DETAILS=$(echo "$LIST" | grep -A 2 -E "$WIFI_REGEX") 92 | echo "$DETAILS" | awk '/Ethernet Address: / {print substr($0, index($0, $3))}' 93 | } 94 | 95 | # Get ethernet mac address 96 | # $1 = networksetup -listallhardwareports 97 | # $! = String 98 | getEthernetMac() { 99 | local LIST=${1-$(networksetup -listallhardwareports)} 100 | local DETAILS=$(echo "$LIST" | grep -A 2 -E "$ETHERNET_REGEX") 101 | echo "$DETAILS" | awk '/Ethernet Address: / {print substr($0, index($0, $3))}' 102 | } 103 | 104 | # Find name of primary connected network interface 105 | # $! = String 106 | getPrimaryInterfaceName() { 107 | local INTERFACE=$(getEthernetInterface) 108 | if [ $(getEthernetState "$INTERFACE") != 0 ]; then 109 | echo "$(getEthernetName)" 110 | else 111 | echo "$(getWifiName)" 112 | fi 113 | } 114 | 115 | # Extract connection configuration 116 | # $1 = networksetup -getinfo 117 | # $! = String 118 | getConnectionConfig() { 119 | echo "$1" | grep 'Configuration$' 120 | } 121 | 122 | # Extract IP4 123 | # $1 = networksetup -getinfo 124 | # $! = String 125 | getIPv4() { 126 | echo "$1" | grep '^IP\saddress' \ 127 | | awk '/ address/ {print substr($0, index($0, $3))}' 128 | } 129 | 130 | # Extract IP6 131 | # $1 = networksetup -getinfo 132 | # $! = String 133 | getIPv6() { 134 | local IPv6=$(echo "$1" \ 135 | | grep '^IPv6 IP address' \ 136 | | awk '/ address/ {print substr($0, index($0, $4))}') 137 | 138 | if [ "$IPv6" == "none" ]; then 139 | echo "" 140 | else 141 | echo "$IPv6" 142 | fi 143 | } 144 | 145 | # Extract SSID 146 | # $1 = airport -getinfo 147 | # $! = String 148 | getSSID() { 149 | echo "$1" | awk '/ SSID/ {print substr($0, index($0, $2))}' 150 | } 151 | 152 | # Pad BSSID 153 | # $1 = BSSID string 154 | # $! = String 155 | padBSSID() { 156 | if [ ${#1} == 17 ]; then 157 | echo "$1" 158 | else 159 | for PART in $(echo "$1" | tr ":" "\n"); do 160 | if [ "$skipFirst" != "" ]; then 161 | printf ":" 162 | fi 163 | skipFirst=true 164 | printf "%02s" "$PART" 165 | done 166 | fi 167 | } 168 | 169 | # Get BSSID 170 | # $1 = airport -getinfo 171 | # $! = String 172 | getBSSID() { 173 | local BSSID=$(echo "$1" | awk '/ BSSID/ {print substr($0, index($0, $2))}' | xargs) 174 | # Handle missing BSSID 175 | if [ "$BSSID" == "BSSID:" ]; then 176 | echo "" 177 | else 178 | echo $(padBSSID "$BSSID") 179 | fi 180 | } 181 | 182 | # Extract wifi authentication 183 | # $1 = airport -getinfo 184 | # $! = String 185 | getAuth() { 186 | echo "$1" | awk '/ link auth/ {print substr($0, index($0, $2))}' 187 | } 188 | 189 | # Resolve global IP 190 | # $1 = Dig resolver address (optional) 191 | # $! = String 192 | getGlobalIP() { 193 | local RESOLVER=${1:-"myip.opendns.com @resolver1.opendns.com"} 194 | 195 | local IP=$(dig -4 +time=2 +tries=1 +short $RESOLVER) 196 | if [[ "$IP" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then 197 | echo "$IP" 198 | fi 199 | } 200 | 201 | # Get connected VPN 202 | # $1 = scutil --nc list 203 | # $! = String 204 | getVPN() { 205 | echo "$1" | awk '/\/*.(Connected)/ {print $7}' | tr -d '"' 206 | } 207 | 208 | # Get VPN info 209 | # $1 = `scutil --nc list` lines 210 | # $! = Separated string of VPN info 211 | getVPNInfo() { 212 | if [[ "$1" =~ \*[[:space:]]\(([a-zA-Z ]*)\)[[:space:]].*\"(.*)\".*\[(.*)\] ]] 213 | then 214 | STATE=${BASH_REMATCH[1]} 215 | NAME=${BASH_REMATCH[2]} 216 | TYPE=${BASH_REMATCH[3]} 217 | fi 218 | 219 | if [ "$STATE" == "Connected" ]; then 220 | AP_ICON=$ICON_VPN_CONNECTED 221 | else 222 | AP_ICON=$ICON_VPN 223 | fi 224 | 225 | echo "$STATE"~"$NAME"~"$TYPE"~"$AP_ICON" 226 | } 227 | 228 | # Get DNS info 229 | # $1 = `networksetup -getdnsservers ` 230 | # $! = String 231 | getDNS() { 232 | if [[ "$1" != *"any DNS"* ]]; then 233 | echo $1 | sed 's/ / \/ /g' 234 | else 235 | echo "" 236 | fi 237 | } 238 | 239 | # Parse DNS info 240 | # $1 = line of dns config file 241 | # $2 = active dns list 242 | # $! = Separated string of dns config elements 243 | parseDNSLine() { 244 | IFS=':' read -r -a ARRAY <<< "$1" 245 | if [[ "${ARRAY[0]}" =~ ^# ]] || [ "${ARRAY[0]}" == "" ] || [ "${ARRAY[1]}" == "" ]; then 246 | return 247 | fi 248 | 249 | local ID=$(trim "${ARRAY[0]}") 250 | local DNS=$(echo "${ARRAY[1]}" | sed 's/ //g' | sed 's/,/ \/ /g') 251 | local ICON=$ICON_DNS 252 | 253 | if [ "$DNS" == "$2" ]; then 254 | ICON=$ICON_DNS_USED 255 | ID="$ID (used)" 256 | fi 257 | 258 | echo "$ID"~"$DNS"~"$ICON" 259 | } 260 | 261 | # Get saved access point 262 | # $1 = networksetup -listpreferredwirelessnetworks 263 | # $! = Separated string of saved access points 264 | getSavedAPs() { 265 | while read -r line; do 266 | OUTPUT=$OUTPUT~$line 267 | done <<< "$1" 268 | echo "${OUTPUT:1}" 269 | } 270 | 271 | # Check if list contains an element 272 | # $1 = List of elements 273 | # $2 = Element to check 274 | # $! = Boolean 275 | listContains() { 276 | while read -r ITEM; do 277 | if [ "$ITEM" == "$2" ]; then 278 | echo 1 279 | fi 280 | done <<< "$1" 281 | } 282 | 283 | # Get WiFi strength 284 | # $1 = Wifi RSSI 285 | # $! = Wifi strength level 1-4 286 | getWifiStrength() { 287 | if [ "$1" -lt -80 ]; then 288 | echo 1 289 | elif [ "$1" -lt -70 ]; then 290 | echo 2 291 | elif [ "$1" -lt -60 ]; then 292 | echo 3 293 | else 294 | echo 4 295 | fi 296 | } 297 | 298 | # Parse access point details string 299 | # $1 = `airpot --scan` line 300 | # $2 = BSSID or SSID of the active access point (optional) 301 | # $3 = List of favorite access points (optional) 302 | # $! = Separated string of access point settings 303 | getAPDetails() { 304 | # Example: SSID BSSID RSSI CHANNEL HT CC SECURITY 305 | # Example: "Test-Network 21:aa:4c:b4:cc:11 -24 6 Y US WPA2(PSK/AES/AES)" 306 | if [[ "$1" =~ [[:space:]]*(.*)[[:space:]]+([0-9a-f:]{17})?[[:space:]]+(-[0-9]{2})[[:space:]]+([,+0-9]+)[[:space:]]+([YN]{1})[[:space:]]+([-A-Z]{2})[[:space:]]+(.*) ]] 307 | then 308 | SSID=$(echo ${BASH_REMATCH[1]} | xargs) 309 | BSSID=${BASH_REMATCH[2]} 310 | RSSI=${BASH_REMATCH[3]} 311 | CHANNEL=${BASH_REMATCH[4]} 312 | HT=${BASH_REMATCH[5]} 313 | CC=${BASH_REMATCH[6]} 314 | SECURITY=$(echo ${BASH_REMATCH[7]} | xargs) 315 | fi 316 | 317 | FAVORITED=$(listContains "$3" "$SSID") 318 | PRIORITY=$PRIORITY_LOW 319 | 320 | if [ "$BSSID" != "" ] && [ "$BSSID" == "$2" ] || [ "$SSID" == "$2" ]; then 321 | AP_ICON=$ICON_WIFI_ACTIVE_ 322 | PRIORITY=$PRIORITY_HIGH 323 | elif [ "$FAVORITED" != "" ]; then 324 | AP_ICON=$ICON_WIFI_STAR_ 325 | PRIORITY=$PRIORITY_MEDIUM 326 | elif [[ "$SECURITY" =~ "NONE" ]]; then 327 | AP_ICON=$ICON_WIFI_ 328 | else 329 | AP_ICON=$ICON_WIFI_LOCK_ 330 | fi 331 | 332 | AP_ICON=$AP_ICON$(getWifiStrength "$RSSI")$ICON_END 333 | 334 | if [ "$SSID" != "" ]; then 335 | echo "$PRIORITY"~"$SSID"~"$BSSID"~"$RSSI"~"$CHANNEL"~"$SECURITY"~"$AP_ICON" 336 | fi 337 | } 338 | -------------------------------------------------------------------------------- /src/media.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ICON_END=".png" 4 | 5 | ICON_WIFI="media/wifi-4.png" 6 | ICON_WIFI_="media/wifi-" 7 | ICON_WIFI_4="media/wifi-4.png" 8 | ICON_WIFI_3="media/wifi-3.png" 9 | ICON_WIFI_2="media/wifi-2.png" 10 | ICON_WIFI_1="media/wifi-1.png" 11 | 12 | ICON_WIFI_LOCK="media/wifi-lock-4.png" 13 | ICON_WIFI_LOCK_="media/wifi-lock-" 14 | ICON_WIFI_LOCK_4="media/wifi-lock-4.png" 15 | ICON_WIFI_LOCK_3="media/wifi-lock-3.png" 16 | ICON_WIFI_LOCK_2="media/wifi-lock-2.png" 17 | ICON_WIFI_LOCK_1="media/wifi-lock-1.png" 18 | 19 | ICON_WIFI_STAR="media/wifi-star-4.png" 20 | ICON_WIFI_STAR_="media/wifi-star-" 21 | ICON_WIFI_STAR_4="media/wifi-star-4.png" 22 | ICON_WIFI_STAR_3="media/wifi-star-3.png" 23 | ICON_WIFI_STAR_2="media/wifi-star-2.png" 24 | ICON_WIFI_STAR_1="media/wifi-star-1.png" 25 | 26 | ICON_WIFI_ACTIVE="media/wifi-active-4.png" 27 | ICON_WIFI_ACTIVE_="media/wifi-active-" 28 | ICON_WIFI_ACTIVE_4="media/wifi-active-4.png" 29 | ICON_WIFI_ACTIVE_3="media/wifi-active-3.png" 30 | ICON_WIFI_ACTIVE_2="media/wifi-active-2.png" 31 | ICON_WIFI_ACTIVE_1="media/wifi-active-1.png" 32 | 33 | ICON_WIFI_ERROR="media/wifi-error-4.png" 34 | 35 | ICON_ETH="media/ethernet.png" 36 | 37 | ICON_VPN="media/vpn.png" 38 | ICON_VPN_CONNECTED="media/vpn-connected.png" 39 | 40 | ICON_DNS="media/dns.png" 41 | ICON_DNS_USED="media/dns-used.png" 42 | -------------------------------------------------------------------------------- /src/vpn.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . src/workflowHandler.sh 4 | . src/helpers.sh 5 | 6 | # Handle action 7 | if [ "$1" != "" ]; then 8 | IS_CONNECTED=$(test -z `scutil --nc status "$1" | head -n 1 | grep Connected` && echo 0 || echo 1); 9 | if [ $IS_CONNECTED -eq 1 ]; then 10 | scutil --nc stop "$1" 11 | else 12 | scutil --nc show "$1" | head -1 | grep PPP:L2TP 2>&1 > /dev/null 13 | if [ $? -eq 0 ]; then 14 | networksetup -connectpppoeservice "$1" 15 | else 16 | scutil --nc start "$1" 17 | fi 18 | fi 19 | 20 | exit 21 | fi 22 | 23 | while read -r LINE; do 24 | OUTPUT="$(getVPNInfo "$LINE")" 25 | IFS='~' read -r -a ARRAY <<< "$OUTPUT" 26 | 27 | addResult "" "${ARRAY[1]}" "${ARRAY[1]}" "${ARRAY[2]} (${ARRAY[0]})" "${ARRAY[3]}" 28 | done <<< "$(echo "$(scutil --nc list)" | awk 'NR>1')" 29 | 30 | getXMLResults 31 | -------------------------------------------------------------------------------- /src/wifi.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . src/wifiCommon.sh 4 | . src/workflowHandler.sh 5 | 6 | # Handle action 7 | if [ "$1" != "" ]; then 8 | if [ "$1" == "On" ] || [ "$1" == "Off" ]; then 9 | networksetup -setairportpower "$INTERFACE" "$1" 10 | else 11 | echo "$1" | tr -d '\n' 12 | fi 13 | exit 14 | fi 15 | 16 | # Get interface mac address 17 | MAC=$(getWifiMac) 18 | 19 | # Handle Wi-Fi off state 20 | if [ "$(getWifiState "$INTERFACE")" == 0 ]; then 21 | addResult "" "On" "Turn $NAME on" "$INTERFACE ($MAC)" "$ICON_WIFI_ERROR" 22 | getXMLResults 23 | return 24 | fi 25 | 26 | # Get network configuration 27 | NETINFO=$(networksetup -getinfo "$NAME") 28 | NETCONFIG=$(getConnectionConfig "$NETINFO") 29 | 30 | # Output IPv4 31 | IPv4=$(getIPv4 "$NETINFO") 32 | if [ "$IPv4" != "" ]; then 33 | addResult "" "$IPv4" "$IPv4" "IPv4 address ($NETCONFIG)" "$ICON_WIFI" 34 | fi 35 | 36 | # Output IPv6 37 | IPv6=$(getIPv6 "$NETINFO") 38 | if [ "$IPv6" != "" ]; then 39 | addResult "" "$IPv6" "$IPv6" "IPv6 address ($NETCONFIG)" "$ICON_WIFI" 40 | fi 41 | 42 | # Output WiFi AP info 43 | INFO=$($AIRPORT --getinfo) 44 | SSID=$(getSSID "$INFO") 45 | BSSID=$(getBSSID "$INFO") 46 | AUTH=$(getAuth "$INFO") 47 | 48 | # Use BSSID with SSID as fallback 49 | SSID_NAME="$SSID ($BSSID)" 50 | if [ "$BSSID" == "" ]; then 51 | SSID_NAME="$SSID" 52 | fi 53 | 54 | if [ "$SSID" != "" ]; then 55 | addResult "" "$SSID" "$SSID_NAME" "$NAME access point ($AUTH)" "$ICON_WIFI" 56 | fi 57 | 58 | # Output global IP 59 | GLOBALIP=$(getGlobalIP) 60 | if [ "$GLOBALIP" != "" ]; then 61 | addResult "" "$GLOBALIP" "$GLOBALIP" "Global IP" "$ICON_WIFI" 62 | fi 63 | 64 | # Output VPN 65 | VPN=$(getVPN "$(scutil --nc list)") 66 | if [ "$VPN" != "" ]; then 67 | addResult "" "$VPN" "$VPN" "VPN connection" "$ICON_WIFI" 68 | fi 69 | 70 | # Output DNS list 71 | DNSSTRING=$(getDNS "$(networksetup -getdnsservers "$NAME")") 72 | if [ "$DNSSTRING" != "" ]; then 73 | addResult "" "$DNSSTRING" "$DNSSTRING" "DNS list" "$ICON_WIFI" 74 | fi 75 | 76 | addResult "" "Off" "Turn $NAME Off" "$INTERFACE ($MAC)" "$ICON_WIFI" 77 | 78 | getXMLResults 79 | -------------------------------------------------------------------------------- /src/wifiCommon.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . src/helpers.sh 4 | 5 | LIST=$(networksetup -listallhardwareports) 6 | INTERFACE=$(getWifiInterface "$LIST") 7 | NAME=$(getWifiName "$LIST") 8 | 9 | AIRPORT="/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport" 10 | -------------------------------------------------------------------------------- /src/workflowHandler.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | RESULTS=() 4 | 5 | ################################################################################ 6 | # Adds a result to the result array 7 | # 8 | # $1 uid 9 | # $2 arg 10 | # $3 title 11 | # $4 subtitle 12 | # $5 icon 13 | # $6 valid 14 | # $7 autocomplete 15 | ############################################################################### 16 | addResult() { 17 | RESULT="$(xmlEncode "$3")$(xmlEncode "$4")$(xmlEncode "$5")" 18 | RESULTS+=("$RESULT") 19 | } 20 | 21 | ############################################################################### 22 | # Prints the feedback xml to stdout 23 | ############################################################################### 24 | getXMLResults() { 25 | echo "" 26 | 27 | # if [ "${#string[@]}" = "0" ]; then 28 | # echo "No results foundPlease try another search term" 29 | # fi 30 | 31 | for R in ${RESULTS[*]}; do 32 | echo "$R" | tr "\n" " " 33 | done 34 | 35 | echo "" 36 | } 37 | 38 | ############################################################################### 39 | # Escapes XML special characters with their entities 40 | ############################################################################### 41 | xmlEncode() { 42 | echo "$1" | sed -e 's/&/\&/g' -e 's/>/\>/g' -e 's/ "$PREFFILE" 78 | fi 79 | echo "$1=$2" >> "$PREFFILE" 80 | } 81 | 82 | ############################################################################### 83 | # Read a value for a given key from the workflow preferences 84 | # 85 | # $1 key 86 | # $2 non-volatile 0/1 87 | # $3 filename (optional, filename will be "settings" if not specified) 88 | ############################################################################### 89 | getPref() { 90 | if [ "$2" = "0" ]; then 91 | local PREFDIR="$alfred_workflow_data" 92 | else 93 | local PREFDIR="$alfred_workflow_cache" 94 | fi 95 | 96 | if [ ! -d "$PREFDIR" ]; then 97 | return 98 | fi 99 | 100 | if [ -z "$3" ]; then 101 | local PREFFILE="${PREFDIR}/settings" 102 | else 103 | local PREFFILE="${PREFDIR}/$3" 104 | fi 105 | 106 | if [ ! -f "$PREFFILE" ]; then 107 | return 108 | fi 109 | 110 | local VALUE=$(sed "/^\#/d" "$PREFFILE" | grep "$1" | tail -n 1 | cut -d "=" -f2-) 111 | echo "$VALUE" 112 | } 113 | 114 | getLang() { 115 | defaults read .GlobalPreferences AppleLanguages | tr -d [:space:] | cut -c2-3 116 | } 117 | -------------------------------------------------------------------------------- /tests/apTests.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | . src/helpers.sh 4 | load variables 5 | 6 | @test "getSavedAPs: get saved access points" { 7 | run getSavedAPs "$SAVED_APS" 8 | IFS='~' read -r -a ARRAY <<< "$output" 9 | 10 | [ "$status" -eq 0 ] 11 | [ "${ARRAY[0]}" == "Test-Network" ] 12 | [ "${ARRAY[1]}" == "Test-Network2" ] 13 | [ "${ARRAY[2]}" == "Martins iPhone" ] 14 | } 15 | 16 | @test "getAPDetails: get AP" { 17 | INPUT=" Test-Network 21:aa:4c:b4:cc:11 -24 6 Y US WPA2(PSK/AES/AES)" 18 | 19 | run getAPDetails "$INPUT" 20 | IFS='~' read -r -a ARRAY <<< "$output" 21 | 22 | [ "$status" -eq 0 ] 23 | [ "${ARRAY[0]}" == $PRIORITY_LOW ] 24 | [ "${ARRAY[1]}" == "Test-Network" ] 25 | [ "${ARRAY[2]}" == "21:aa:4c:b4:cc:11" ] 26 | [ "${ARRAY[3]}" == "-24" ] 27 | [ "${ARRAY[4]}" == "6" ] 28 | [ "${ARRAY[5]}" == "WPA2(PSK/AES/AES)" ] 29 | [ "${ARRAY[6]}" == $ICON_WIFI_LOCK ] 30 | } 31 | 32 | @test "getAPDetails: no BSSID on MacOS Monterey" { 33 | INPUT=" y6Uj4xYm -76 11 Y -- WPA2(PSK/AES/AES) " 34 | 35 | run getAPDetails "$INPUT" 36 | IFS='~' read -r -a ARRAY <<< "$output" 37 | 38 | [ "$status" -eq 0 ] 39 | [ "${ARRAY[0]}" == $PRIORITY_LOW ] 40 | [ "${ARRAY[1]}" == "y6Uj4xYm" ] 41 | [ "${ARRAY[2]}" == "" ] 42 | [ "${ARRAY[3]}" == "-76" ] 43 | [ "${ARRAY[4]}" == "11" ] 44 | [ "${ARRAY[5]}" == "WPA2(PSK/AES/AES)" ] 45 | [ "${ARRAY[6]}" == $ICON_WIFI_LOCK_2 ] 46 | } 47 | 48 | @test "getAPDetails: get multiband AP with spaces" { 49 | INPUT=" New AP 50:1d:bf:56:2f:2e -54 132,+1 Y DK WPA2(PSK/AES/AES) " 50 | 51 | run getAPDetails "$INPUT" 52 | IFS='~' read -r -a ARRAY <<< "$output" 53 | 54 | [ "${ARRAY[1]}" == "New AP" ] 55 | [ "${ARRAY[2]}" == "50:1d:bf:56:2f:2e" ] 56 | [ "${ARRAY[3]}" == "-54" ] 57 | [ "${ARRAY[4]}" == "132,+1" ] 58 | [ "${ARRAY[5]}" == "WPA2(PSK/AES/AES)" ] 59 | [ "${ARRAY[6]}" == $ICON_WIFI_LOCK ] 60 | } 61 | 62 | @test "getAPDetails: get random printer AP" { 63 | INPUT=" HP-Print-02-Officejet Pro 8600 9c:b6:54:58:05:02 -79 4 N -- WPA2(PSK/AES/AES) " 64 | 65 | run getAPDetails "$INPUT" 66 | IFS='~' read -r -a ARRAY <<< "$output" 67 | 68 | [ "${ARRAY[0]}" == $PRIORITY_LOW ] 69 | [ "${ARRAY[1]}" == "HP-Print-02-Officejet Pro 8600" ] 70 | [ "${ARRAY[2]}" == "9c:b6:54:58:05:02" ] 71 | [ "${ARRAY[3]}" == "-79" ] 72 | [ "${ARRAY[4]}" == "4" ] 73 | [ "${ARRAY[5]}" == "WPA2(PSK/AES/AES)" ] 74 | [ "${ARRAY[6]}" == $ICON_WIFI_LOCK_2 ] 75 | } 76 | 77 | @test "getAPDetails: get random printer AP on MacOS Monterey" { 78 | INPUT=" HP-Print-02-Officejet Pro 8600 -79 4 N -- WPA2(PSK/AES/AES) " 79 | 80 | run getAPDetails "$INPUT" 81 | IFS='~' read -r -a ARRAY <<< "$output" 82 | 83 | [ "${ARRAY[0]}" == $PRIORITY_LOW ] 84 | [ "${ARRAY[1]}" == "HP-Print-02-Officejet Pro 8600" ] 85 | [ "${ARRAY[2]}" == "" ] 86 | [ "${ARRAY[3]}" == "-79" ] 87 | [ "${ARRAY[4]}" == "4" ] 88 | [ "${ARRAY[5]}" == "WPA2(PSK/AES/AES)" ] 89 | [ "${ARRAY[6]}" == $ICON_WIFI_LOCK_2 ] 90 | } 91 | 92 | @test "getAPDetails: get unknown AP" { 93 | INPUT=" test 08:61:6e:c0:9b:ff -27 11 Y -- WPA(PSK/AES,TKIP/TKIP) WPA2(PSK/AES,TKIP/TKIP)" 94 | 95 | run getAPDetails "$INPUT" 96 | IFS='~' read -r -a ARRAY <<< "$output" 97 | 98 | [ "${ARRAY[0]}" == $PRIORITY_LOW ] 99 | [ "${ARRAY[1]}" == "test" ] 100 | [ "${ARRAY[2]}" == "08:61:6e:c0:9b:ff" ] 101 | [ "${ARRAY[5]}" == "WPA(PSK/AES,TKIP/TKIP) WPA2(PSK/AES,TKIP/TKIP)" ] 102 | [ "${ARRAY[6]}" == $ICON_WIFI_LOCK ] 103 | } 104 | 105 | @test "getAPDetails: active AP is marked with an icon" { 106 | INPUT=" New AP 50:1d:bf:56:2f:2e -54 132,+1 Y DK WPA2(PSK/AES/AES) " 107 | 108 | run getAPDetails "$INPUT" "50:1d:bf:56:2f:2e" 109 | IFS='~' read -r -a ARRAY <<< "$output" 110 | 111 | [ "${ARRAY[0]}" == $PRIORITY_HIGH ] 112 | [ "${ARRAY[1]}" == "New AP" ] 113 | [ "${ARRAY[2]}" == "50:1d:bf:56:2f:2e" ] 114 | [ "${ARRAY[6]}" == $ICON_WIFI_ACTIVE ] 115 | } 116 | 117 | @test "getAPDetails: active AP without BSSID is marked with an icon" { 118 | INPUT=" New AP -54 132,+1 Y DK WPA2(PSK/AES/AES) " 119 | 120 | run getAPDetails "$INPUT" "New AP" 121 | IFS='~' read -r -a ARRAY <<< "$output" 122 | 123 | [ "${ARRAY[0]}" == $PRIORITY_HIGH ] 124 | [ "${ARRAY[1]}" == "New AP" ] 125 | [ "${ARRAY[6]}" == $ICON_WIFI_ACTIVE ] 126 | } 127 | 128 | @test "getAPDetails: do not mark unknown active AP" { 129 | INPUT=" New AP 2 -54 132,+1 Y DK WPA2(PSK/AES/AES) " 130 | 131 | run getAPDetails "$INPUT" "New AP" 132 | IFS='~' read -r -a ARRAY <<< "$output" 133 | 134 | [ "${ARRAY[0]}" == $PRIORITY_LOW ] 135 | [ "${ARRAY[1]}" == "New AP 2" ] 136 | [ "${ARRAY[6]}" == $ICON_WIFI_LOCK ] 137 | } 138 | 139 | @test "getAPDetails: active BSSID can contain starting zeros" { 140 | INPUT=" New AP 50:0d:0f:56:00:2e -54 132,+1 Y DK WPA2(PSK/AES/AES) " 141 | 142 | run getAPDetails "$INPUT" "50:0d:0f:56:00:2e" 143 | IFS='~' read -r -a ARRAY <<< "$output" 144 | 145 | [ "${ARRAY[1]}" == "New AP" ] 146 | [ "${ARRAY[2]}" == "50:0d:0f:56:00:2e" ] 147 | [ "${ARRAY[6]}" == $ICON_WIFI_ACTIVE ] 148 | } 149 | 150 | @test "getAPDetails: filter empty SSIDs" { 151 | INPUT=" 50:0d:0f:56:00:2e -54 132,+1 Y DK WPA2(PSK/AES/AES) " 152 | 153 | run getAPDetails "$INPUT" 154 | IFS='~' read -r -a ARRAY <<< "$output" 155 | 156 | [ "${#ARRAY[@]}" == 0 ] 157 | } 158 | 159 | @test "getAPDetails: favorited AP is marked with an icon" { 160 | INPUT=" New AP 50:1d:bf:56:2f:2e -54 132,+1 Y DK WPA2(PSK/AES/AES) " 161 | AP_LIST="New AP 162 | Random other AP" 163 | 164 | run getAPDetails "$INPUT" "1234" "$AP_LIST" 165 | IFS='~' read -r -a ARRAY <<< "$output" 166 | 167 | [ "${ARRAY[0]}" == $PRIORITY_MEDIUM ] 168 | [ "${ARRAY[1]}" == "New AP" ] 169 | [ "${ARRAY[2]}" == "50:1d:bf:56:2f:2e" ] 170 | [ "${ARRAY[6]}" == $ICON_WIFI_STAR ] 171 | } 172 | 173 | @test "getAPDetails: open AP is marked with a plain icon" { 174 | INPUT=" New AP 50:1d:bf:56:2f:2e -54 132,+1 Y DK NONE " 175 | 176 | run getAPDetails "$INPUT" 177 | IFS='~' read -r -a ARRAY <<< "$output" 178 | 179 | [ "${ARRAY[1]}" == "New AP" ] 180 | [ "${ARRAY[6]}" == $ICON_WIFI ] 181 | } 182 | 183 | @test "getAPDetails: icon is set according to strength" { 184 | INPUT=" New AP 50:1d:bf:56:2f:2e -55 1 Y US NONE " 185 | run getAPDetails "$INPUT" 186 | IFS='~' read -r -a ARRAY <<< "$output" 187 | [ "${ARRAY[6]}" == "$ICON_WIFI_4" ] 188 | 189 | INPUT=" New AP 50:1d:bf:56:2f:2e -65 1 Y US NONE " 190 | run getAPDetails "$INPUT" 191 | IFS='~' read -r -a ARRAY <<< "$output" 192 | [ "${ARRAY[6]}" == "$ICON_WIFI_3" ] 193 | 194 | INPUT=" New AP 50:1d:bf:56:2f:2e -75 1 Y US NONE " 195 | run getAPDetails "$INPUT" 196 | IFS='~' read -r -a ARRAY <<< "$output" 197 | [ "${ARRAY[6]}" == $ICON_WIFI_2 ] 198 | 199 | INPUT=" New AP 50:1d:bf:56:2f:2e -85 1 Y US NONE " 200 | run getAPDetails "$INPUT" 201 | IFS='~' read -r -a ARRAY <<< "$output" 202 | [ "${ARRAY[6]}" == $ICON_WIFI_1 ] 203 | } 204 | 205 | @test "listContains: contains element" { 206 | run listContains "$AP_LIST" "bar baz" 207 | [ "$status" -eq 0 ] 208 | [ "$output" == 1 ] 209 | } 210 | 211 | @test "listContains: does not contain element" { 212 | run listContains "$AP_LIST" "not" 213 | [ "$output" == "" ] 214 | } 215 | 216 | @test "listContains: list is empty" { 217 | run listContains "" "foo" 218 | [ "$output" == "" ] 219 | } 220 | 221 | @test "listContains: element is empty" { 222 | run listContains "$AP_LIST" 223 | [ "$output" == "" ] 224 | } 225 | -------------------------------------------------------------------------------- /tests/dnsTests.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | . src/helpers.sh 4 | load variables 5 | 6 | @test "getDNS: get current DNS list" { 7 | run getDNS "$DNS" 8 | [ "$output" = "8.8.8.8 / 8.8.4.4 / 192.168.1.1" ] 9 | } 10 | 11 | @test "parseDNSLine: parse a single dns config line" { 12 | run parseDNSLine "Google DNS:8.8.8.8,8.8.4.4" 13 | IFS='~' read -r -a ARRAY <<< "$output" 14 | [ "$status" -eq 0 ] 15 | [ "${ARRAY[0]}" == "Google DNS" ] 16 | [ "${ARRAY[1]}" == "8.8.8.8 / 8.8.4.4" ] 17 | [ "${ARRAY[2]}" == "$ICON_DNS" ] 18 | } 19 | 20 | @test "parseDNSLine: parse simple config" { 21 | run parseDNSLine "OpenerDNS:42.120.21.30" 22 | IFS='~' read -r -a ARRAY <<< "$output" 23 | [ "${ARRAY[0]}" == "OpenerDNS" ] 24 | [ "${ARRAY[1]}" == "42.120.21.30" ] 25 | } 26 | 27 | @test "parseDNSLine: parse with spaces" { 28 | run parseDNSLine " Random DNS : 1.2.3.4 , 6.7.8.9" 29 | IFS='~' read -r -a ARRAY <<< "$output" 30 | [ "${ARRAY[0]}" == "Random DNS" ] 31 | [ "${ARRAY[1]}" == "1.2.3.4 / 6.7.8.9" ] 32 | } 33 | 34 | @test "parseDNSLine: ignore comments" { 35 | run parseDNSLine "# comment" 36 | IFS='~' read -r -a ARRAY <<< "$output" 37 | [ "${ARRAY[0]}" == "" ] 38 | } 39 | 40 | @test "parseDNSLine: ignore comments with separator" { 41 | run parseDNSLine "# comment: this is a comment" 42 | IFS='~' read -r -a ARRAY <<< "$output" 43 | [ "${ARRAY[0]}" == "" ] 44 | } 45 | 46 | @test "parseDNSLine: ignore empty lines" { 47 | run parseDNSLine " " 48 | IFS='~' read -r -a ARRAY <<< "$output" 49 | [ "${ARRAY[0]}" == "" ] 50 | } 51 | 52 | @test "parseDNSLine: set used state" { 53 | run parseDNSLine "Google DNS:8.8.8.8,8.8.4.4" "8.8.8.8 / 8.8.4.4" 54 | IFS='~' read -r -a ARRAY <<< "$output" 55 | [ "${ARRAY[0]}" == "Google DNS (used)" ] 56 | [ "${ARRAY[1]}" == "8.8.8.8 / 8.8.4.4" ] 57 | [ "${ARRAY[2]}" == "$ICON_DNS_USED" ] 58 | } 59 | 60 | @test "parseDNSLine: handle invalid line" { 61 | run parseDNSLine "Invalid 1.2.3.4" 62 | IFS='~' read -r -a ARRAY <<< "$output" 63 | [ "${ARRAY[0]}" == "" ] 64 | } 65 | 66 | @test "parseDNSLine: handle missing ip" { 67 | run parseDNSLine "Invalid:" 68 | IFS='~' read -r -a ARRAY <<< "$output" 69 | [ "${ARRAY[0]}" == "" ] 70 | } 71 | -------------------------------------------------------------------------------- /tests/ethernetTests.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | . src/helpers.sh 4 | load variables 5 | 6 | @test "getEthernetState: get ethernet state" { 7 | run getEthernetState en4 8 | [ "$status" -eq 0 ] 9 | [ "$output" = 1 -o "$output" = 0 ] 10 | } 11 | 12 | @test "getEthernetName: get name" { 13 | run getEthernetName "$LIST" 14 | [ "$status" -eq 0 ] 15 | [ "$output" = "Thunderbolt Ethernet" ] 16 | } 17 | 18 | @test "getEthernetName: get ax name" { 19 | run getEthernetName "$LIST3" 20 | [ "$status" -eq 0 ] 21 | [ "$output" = "AX88179A" ] 22 | } 23 | 24 | @test "getEthernetInterface: get interface Thunderbolt" { 25 | run getEthernetInterface "$LIST" 26 | [ "$status" -eq 0 ] 27 | [ "$output" = "en4" ] 28 | } 29 | 30 | @test "getEthernetInterface: get interface USB" { 31 | run getEthernetInterface "$LIST2" 32 | [ "$status" -eq 0 ] 33 | [ "$output" = "en7" ] 34 | } 35 | 36 | @test "getEthernetMac: get mac address" { 37 | run getEthernetMac "$LIST" 38 | [ "$status" -eq 0 ] 39 | [ "$output" = "40:0c:8d:00:ef:8c" ] 40 | } 41 | -------------------------------------------------------------------------------- /tests/variables.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | LIST=" 4 | Hardware Port: Thunderbolt Ethernet 5 | Device: en4 6 | Ethernet Address: 40:0c:8d:00:ef:8c 7 | 8 | Hardware Port: Wi-Fi 9 | Device: en0 10 | Ethernet Address: f8:06:c1:00:a3:cc 11 | 12 | Hardware Port: Bluetooth PAN 13 | Device: en3 14 | Ethernet Address: b7:06:b1:01:a2:ce 15 | 16 | Hardware Port: Thunderbolt 1 17 | Device: en1 18 | Ethernet Address: f2:00:11:48:00:20 19 | 20 | Hardware Port: Thunderbolt 2 21 | Device: en2 22 | Ethernet Address: f2:00:12:48:50:22 23 | 24 | Hardware Port: Thunderbolt Bridge 25 | Device: bridge0 26 | Ethernet Address: cc:f6:b1:77:f7:02 27 | 28 | VLAN Configurations 29 | ===================" 30 | 31 | LIST2=" 32 | Hardware Port: USB 10/100/1000 LAN 33 | Device: en7 34 | Ethernet Address: de:ad:be:ef:fe:ed 35 | 36 | Hardware Port: Wi-Fi 37 | Device: en0 38 | Ethernet Address: f8:06:c1:00:a3:cc 39 | 40 | VLAN Configurations 41 | ===================" 42 | 43 | LIST3=" 44 | Hardware Port: Wi-Fi 45 | Device: en1 46 | Ethernet Address: f8:06:c1:00:a3:cc 47 | 48 | Hardware Port: AX88179A 49 | Device: en3 50 | Ethernet Address: de:ad:be:ef:fe:ed 51 | 52 | Hardware Port: Ethernet Adapter (en4) 53 | Device: en4 54 | Ethernet Address: de:ad:be:ef:fe:ee 55 | 56 | VLAN Configurations 57 | ===================" 58 | 59 | NETINFO='DHCP Configuration 60 | IP address: 192.168.1.100 61 | Subnet mask: 255.255.255.0 62 | Router: 192.168.1.1 63 | Client ID: 64 | IPv6: Automatic 65 | IPv6 IP address: none 66 | IPv6 Router: none 67 | Wi-Fi ID: f8:06:c1:00:a3:cc' 68 | 69 | INFO='agrCtlRSSI: -47 70 | agrExtRSSI: 0 71 | agrCtlNoise: -91 72 | agrExtNoise: 0 73 | state: running 74 | op mode: station 75 | lastTxRate: 450 76 | maxRate: 450 77 | lastAssocStatus: 0 78 | 802.11 auth: open 79 | link auth: wpa2-psk 80 | BSSID: c8:7:19:2c:0:6f 81 | SSID: Test-Network 82 | MCS: 23 83 | channel: 36,1' 84 | 85 | SCUTIL='Available network connection services in the current set (*=enabled): 86 | * (Disconnected) 9798DAED-21C7-44A1-B382-EFCE7E1373F1 PPP --> Modem (usbmodem1411) "Arduino Uno" [PPP:Modem] 87 | * (Disconnected) CBA1BCD8-D18D-4241-9EF4-5656AF89F09B PPP --> Modem (usbserial) "USB-Serial Controller D" [PPP:Modem] 88 | * (Disconnected) F9BABC6E-649F-4113-95BC-94E1467FCBE8 PPP --> Modem (usbmodem1d112) "SAMSUNG_Android" [PPP:Modem] 89 | * (Connected) 65F5A798-4B98-4DA1-87D8-9D605FFF6188 PPP --> L2TP "Test-VPN" [PPP:L2TP]' 90 | 91 | DNS="8.8.8.8 92 | 8.8.4.4 93 | 192.168.1.1" 94 | 95 | SAVED_APS=" Test-Network 96 | Test-Network2 97 | Martins iPhone" 98 | 99 | AP_LIST="foo 100 | bar baz 101 | qux" 102 | -------------------------------------------------------------------------------- /tests/vpnTests.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | . src/helpers.sh 4 | load variables 5 | 6 | @test "getVPNInfo: get vpn info" { 7 | INPUT="* (Disconnected) 65F5A799-4C98-4DA1-87D7-9D605D9D666C IPSec \"My-VPN\" [IPSec]" 8 | 9 | run getVPNInfo "$INPUT" 10 | IFS='~' read -r -a ARRAY <<< "$output" 11 | 12 | [ "$status" -eq 0 ] 13 | [ "${ARRAY[0]}" == "Disconnected" ] 14 | [ "${ARRAY[1]}" == "My-VPN" ] 15 | [ "${ARRAY[2]}" == "IPSec" ] 16 | [ "${ARRAY[3]}" == "$ICON_VPN" ] 17 | } 18 | 19 | @test "getVPNInfo: get connected vpn info" { 20 | INPUT="* (Connected) 65F5A799-4C98-4DA1-87D7-9D605D9D666C IPSec \"Another: VPN\" [IPSec]" 21 | 22 | run getVPNInfo "$INPUT" 23 | IFS='~' read -r -a ARRAY <<< "$output" 24 | 25 | [ "$status" -eq 0 ] 26 | [ "${ARRAY[0]}" == "Connected" ] 27 | [ "${ARRAY[1]}" == "Another: VPN" ] 28 | [ "${ARRAY[2]}" == "IPSec" ] 29 | [ "${ARRAY[3]}" == "$ICON_VPN_CONNECTED" ] 30 | } 31 | 32 | @test "getVPNInfo: get other service" { 33 | INPUT="* (Disconnected) 04D2AFD3-F0BC-47BB-9C91-9E9B4F5675A6 PPP --> L2TP \"Some L2TP VPN\" [PPP:L2TP]" 34 | 35 | run getVPNInfo "$INPUT" 36 | IFS='~' read -r -a ARRAY <<< "$output" 37 | 38 | [ "$status" -eq 0 ] 39 | [ "${ARRAY[0]}" == "Disconnected" ] 40 | [ "${ARRAY[1]}" == "Some L2TP VPN" ] 41 | [ "${ARRAY[2]}" == "PPP:L2TP" ] 42 | [ "${ARRAY[3]}" == "$ICON_VPN" ] 43 | } 44 | 45 | @test "getVPNInfo: get connected vpn info with paranthesis" { 46 | INPUT="* (Connected) 65F5A799-4C98-4DA1-87D7-9D605D9D666C IPSec (com.vpn.vpn) \"Another: VPN\" [IPSec]" 47 | 48 | run getVPNInfo "$INPUT" 49 | IFS='~' read -r -a ARRAY <<< "$output" 50 | 51 | [ "$status" -eq 0 ] 52 | [ "${ARRAY[0]}" == "Connected" ] 53 | [ "${ARRAY[1]}" == "Another: VPN" ] 54 | [ "${ARRAY[2]}" == "IPSec" ] 55 | [ "${ARRAY[3]}" == "$ICON_VPN_CONNECTED" ] 56 | } -------------------------------------------------------------------------------- /tests/wifiTests.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | . src/helpers.sh 4 | load variables 5 | 6 | @test "getWifiState: get wifi state" { 7 | run getWifiState en0 8 | [ "$status" -eq 0 ] 9 | [ "$output" = 1 -o "$output" = 0 ] 10 | } 11 | 12 | @test "getWifiName: get name" { 13 | run getWifiName "$LIST" 14 | [ "$status" -eq 0 ] 15 | [ "$output" = "Wi-Fi" ] 16 | } 17 | 18 | @test "getWifiInterface: get interface" { 19 | run getWifiInterface "$LIST" 20 | [ "$status" -eq 0 ] 21 | [ "$output" = "en0" ] 22 | } 23 | 24 | @test "getWifiMac: get mac address" { 25 | run getWifiMac "$LIST" 26 | [ "$status" -eq 0 ] 27 | [ "$output" = "f8:06:c1:00:a3:cc" ] 28 | } 29 | 30 | @test "getConnectionConfig: get connection config" { 31 | run getConnectionConfig "$NETINFO" 32 | [ "$output" = "DHCP Configuration" ] 33 | } 34 | 35 | @test "getIPv4: get IPv4" { 36 | run getIPv4 "$NETINFO" 37 | [ "$output" = "192.168.1.100" ] 38 | } 39 | 40 | @test "getIPv6: get non-existing IPv6" { 41 | run getIPv6 "$NETINFO" 42 | [ "$output" = "" ] 43 | } 44 | 45 | @test "getSSID: get SSID" { 46 | run getSSID "$INFO" 47 | [ "$output" = "Test-Network" ] 48 | } 49 | 50 | @test "getBSSID: get BSSID" { 51 | run getBSSID "$INFO" 52 | [ "$output" = "c8:07:19:2c:00:6f" ] 53 | } 54 | 55 | @test "getBSSID: no BSSID" { 56 | run getBSSID " BSSID:" 57 | [ "$output" = "" ] 58 | } 59 | 60 | @test "getBSSID: zero pads BSSID" { 61 | run getBSSID " BSSID: c8:7:19:2c:0:6f" 62 | [ "$output" = "c8:07:19:2c:00:6f" ] 63 | } 64 | 65 | @test "getAuth: get auth" { 66 | run getAuth "$INFO" 67 | [ "$output" = "auth: wpa2-psk" ] 68 | } 69 | 70 | @test "getGlobalIP: get global IP" { 71 | run getGlobalIP 72 | [[ "$output" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]] 73 | } 74 | 75 | @test "getGlobalIP: handle invalid resolver" { 76 | run getGlobalIP "non-existing" 77 | [[ "$output" = "" ]] 78 | } 79 | 80 | @test "getVPN: get connected VPN" { 81 | run getVPN "$SCUTIL" 82 | [ "$output" = "Test-VPN" ] 83 | } 84 | --------------------------------------------------------------------------------