From 0019d271fb6f2108c59ecbc70474df4503d5b8d6 Mon Sep 17 00:00:00 2001 From: Lucien Cartier-Tilet Date: Sat, 13 Mar 2021 17:39:25 +0100 Subject: [PATCH] First version of nordvpn.el --- README.org | 14 +++++ nordvpn.el | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 README.org create mode 100644 nordvpn.el diff --git a/README.org b/README.org new file mode 100644 index 0000000..d86c79e --- /dev/null +++ b/README.org @@ -0,0 +1,14 @@ +#+TITLE: nordvpn.el +#+AUTHOR: Lucien Cartier-Tilet +#+EMAIL: lucien@phundrak.com +#+DATE: 2021-03-13 + +~nordvpn.el~ is an Elisp interface to the ~nordvpn~ cli command available on +GNU/Linux. It is currently in alpha stage, use it at your own risks. + +These functions rely on the information found in the files pointed at by +~auth-sources~. If you use a ~.authinfo~ file (or a ~.authinfo.gpg~ file), you +should add the following line, modified of course with your own credentials. +#+BEGIN_SRC text +machine nordvpn login yourUsername password yourPassword +#+END_SRC diff --git a/nordvpn.el b/nordvpn.el new file mode 100644 index 0000000..9530f72 --- /dev/null +++ b/nordvpn.el @@ -0,0 +1,179 @@ +;;; nordvpn.el --- NordVPN interface for Emacs -*- lexical-binding: t -*- + +;;; Copyright (C) 2021 Phundrak + +;; Author: Phundrak +;; Maintainer: Phundrak +;; Homepage: https://labs.phundrak.com/phundrak/nordvpn.el +;; Version: 0.1.0 +;; Keywords: nordvpn, vpn, convenience +;; Package-Requires: ((emacs "27") (s "1.12.0") (ido "1.0.1")) + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; Functions collection for interacting with NordVPN from Emacs. + +;;; Code: + +(defcustom nordvpn-default-country nil + "Default country to which NordVPN should connect" + :type 'string + :group 'nordvpn) + +(defcustom nordvpn-default-city nil + "Default city to which NordVPN should connect" + :type 'string + :group 'nordvpn) + +(defun nordvpn--cut-weird-prefix (string) + "Cut the prefix almost always found in NordVPN's returned string +ending with some Ctrl-M char." + (replace-regexp-in-string ".* " + "" + string)) + +(defun nordvpn--get-list (string) + "Get a list from NordVPN's output `STRING', such as cities or +countries." + (s-split "\n" + (nordvpn--cut-weird-prefix string) + t)) + +(defun nordvpn--get-countries () + "Returns the list of countries offered by NordVPN." + (nordvpn--get-list (nordvpn--cut-weird-prefix (eshell-command-result "nordvpn countries")))) + +(defun nordvpn--get-country () + "Get a country among the ones offered by NordVPN." + (let ((countries (nordvpn--get-countries)) + (country (ido-completing-read "Country: " countries))) + (if (null country) + nordvpn-default-country + country))) + +(defun nordvpn--get-cities (&optional country) + "Get the list of cities available in `COUNTRY'. If `COUNTRY' is +nil, then it will be asked interactively to the user." + (let ((country (if (null country) + (nordvpn--get-country) + country))) + (nordvpn--get-list (eshell-command-result (format "nordvpn cities %s" + country))))) + +(defun nordvpn--get-city (&optional country) + "Get a specific city from the list of cities available for +`COUNTRY'. If `COUNTRY' is nil, the user will have to choose +through `nordvpn--get-country'. If the result is nil, the +function will fallback to `nordvpn-default-country'." + (let* ((country (if (null country) + (nordvpn--get-country) + country)) + (command (format "nordvpn cities %s" country)) + (cities (nordvpn--get-list (eshell-command-result command)))) + (ido-completing-read "City: " cities))) + +(defun nordvpn--get-groups () + "Get the list of server groups available." + (nordvpn--get-list (eshell-command-result "nordvpn groups"))) + +(defun nordvpn--get-group () + "Select one of the available server groups." + (ido-completing-read "Group: " (nordvpn--get-groups))) + +(defun nordvpn--get-credentials () + "Get user credentials from `auth-source' files." + (let* ((found (car (auth-source-search :max 1 + :host "nordvpn" + :require '(:user :secret) + :create t)))) + (if found + (list + (plist-get found :user) + (let ((password (plist-get found :secret))) + (while (functionp password) + (setf password (funcall password))) + password)) + nil))) + +(defun nordvpn-connect-to-country (&option country) + "Connect with NordVPN to a specific country. If `COUNTRY' is nil, +then \"nordvpn c\" is called, otherwise \"nordvpc c `COUNTRY'\" +is called." + (message "NordVPN: %s" + (nordvpn--cut-weird-prefix + (eshell-command-result + (if country + (format "nordvpn c %s" country) + "nordvpn c"))))) + +(defun nordvpn-connect-to-city (city &optinal country) + "Connect with NordVPN to a specific `CITY'. An additional +`COUNTRY' may be specified. If no country is provided to the +function, \"nordvpn c `CITY'\" will be called, otherwise +\"nordvpn c `COUNTRY' `CITY'\" will be called." + (message "NordVPN: %s" + (nordvpn--cut-weird-prefix + (eshell-command-result + (if country + (format "nordvpn c %s %s" country city) + (format "nordvpn c %s" city)))))) + +(defun nordvpn-connect-to-group (group) + "Connect with NordVPN to the specified `GROUP'." + (message "NordVPN: %s" + (nordvpn--cut-weird-prefix + (eshell-command-result + (format "nordvpn c %s"))))) + +(defun nordvpn-connect (&optional arg) + "Connect to NordVPN. + +If `ARG' is non nil or if `nordvpn-default-country' is nil, will +ask the user which country to connect to." + (interactive "P") + (nordvpn-connect-to-country (if arg + (nordvpn--get-country) + nordvpn-default-country))) + +;; nordvpn-connect-to-city &option country city +;; C-u nordvpn-connect-to-city &option city country + +(defun nordvpn-disconnect () + "Disconnect NordVPN from the current server." + (interactive) + (message "NordVPN: %s" + (nordvpn--cut-weird-prefix (eshell-command-result "nordvpn d")))) + +(defun nordvpn-logout () + "Logout from NordVPN." + (interactive) + (message "NordVPN: %s" + (nordvpn--cut-weird-prefix (shell-command-to-string "nordvpn logout")))) + +(defun nordvpn-login () + "Log into your NordVPN account. Credentials are read from +`auth-source' files." + (interactive) + (let* ((credentials (nordvpn--get-credentials)) + (username (car credentials)) + (password (cadr credentials)) + (command (format "nordvpn login -u %s -p \"%s\"" username + password))) + (message "NordVPN: %s" + (nordvpn--cut-weird-prefix (shell-command-to-string command))))) + +(provide 'nordvpn) +;;; nordvpn.el ends here