├── .gitignore ├── LICENSE ├── README.md ├── create-superadmin.sh ├── gen.sh ├── preview.png ├── style.css └── unifi-api.sh /.gitignore: -------------------------------------------------------------------------------- 1 | vouchers.* 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UniFi Voucher Generator 2 | 3 | Generates UniFi Hotspot vouchers using the UniFi controller API ready for printing. Customise the design using CSS. 4 | 5 | This should work on any Linux/Mac machine that can reach the UniFi controller. 6 | 7 | **Feb 2020**: Now works with UniFi 5.12.35 Controller. 8 | 9 | ![Preview of generated output](preview.png) 10 | 11 | ## Setup 12 | 13 | 1. Clone the repo: 14 | 15 | ``` 16 | git clone https://github.com/davidmaitland/unifi-voucher-generator.git 17 | ``` 18 | 19 | 2. Set the variables in `unifi-api.sh` with your controller's details (username, password, baseurl, site). 20 | 21 | 3. Optionally customise the variables in `gen.sh` and the styles in `style.css`. 22 | 23 | ## Run 24 | 25 | 1. Run `./gen.sh` $time $amount // for example ./gen.sh 100 10 - 100minutes 10 codes. 26 | 27 | 2. Open `vouchers.html` and print! 28 | -------------------------------------------------------------------------------- /create-superadmin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Files needed 4 | pwd=`pwd` 5 | . $pwd/unifi-api.sh 6 | 7 | # Generation settings 8 | 9 | uniemail=$1 10 | uniusername=$2 11 | unipassword=$3 12 | 13 | #login to the controller 14 | unifi_login >/dev/null 15 | #create admin + grep accountID of just created read-only user 16 | uniuser=`unifi_create_admin $uniemail $uniusername $unipassword | tr ':' '\n' | tail -1 | cut -d '"' -f 2` 17 | #grant superadmin permissions to the just created user 18 | unifi_grant_superadmin $uniuser 19 | #logoff 20 | unifi_logout 21 | -------------------------------------------------------------------------------- /gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Files needed 4 | pwd=`pwd` 5 | . $pwd/unifi-api.sh 6 | 7 | # Generation settings 8 | if [ -n "$1" ]; then 9 | time=$1 # Voucher time limit (minutes) 10 | else 11 | time=60 # Voucher time limit (minutes) 12 | fi 13 | if [ -n "$2" ]; then 14 | amount=$2 # New vouchers to generate 15 | else 16 | amount=10 # New vouchers to generate 17 | fi 18 | 19 | # HTML Settings 20 | line1="WiFi Voucher" 21 | line2="Valid for $time minutes" 22 | 23 | # Generate vouchers 24 | unifi_login 25 | voucherID=`unifi_create_voucher $time $amount $note` 26 | unifi_get_vouchers $voucherID > vouchers.tmp 27 | unifi_logout 28 | 29 | vouchers=`awk -F"[,:]" '{for(i=1;i<=NF;i++){if($i~/code\042/){print $(i+1)} } }' vouchers.tmp | sed 's/\"//g'` 30 | 31 | # Build HTML 32 | if [ -e vouchers.html ]; then 33 | echo "Removing old vouchers." 34 | rm vouchers.html 35 | fi 36 | 37 | echo '' >> vouchers.html 38 | 39 | for code in $vouchers 40 | do 41 | line3=${code:0:5}" "${code:5:10} 42 | html='
'$line1'
'$line2'
'$line3'
' 43 | echo $html >> vouchers.html 44 | done 45 | 46 | echo "" >> vouchers.html 47 | 48 | # Remove tmp 49 | if [ -e vouchers.tmp ]; then 50 | echo "Removing vouchers tmp file." 51 | rm vouchers.tmp 52 | fi 53 | -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DJM0/unifi-voucher-generator/c7a4ceef2b1b03b5c8f12afc4320eed08c6fccff/preview.png -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #444; 3 | font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; 4 | } 5 | 6 | .voucher { 7 | float: left; 8 | 9 | margin: -1px 0 0 -1px; 10 | padding: 10px 15px; 11 | 12 | border: 1px dashed #ddd; 13 | } 14 | 15 | .line1 { 16 | display: inline-block; 17 | 18 | max-width: 150px; 19 | 20 | font-size: 17px; 21 | line-height: 22px; 22 | } 23 | 24 | .line2 { 25 | float: right; 26 | 27 | margin: 2px 0 0 20px; 28 | 29 | color: #777; 30 | font-size: 13px; 31 | line-height: 20px; 32 | } 33 | 34 | .line3 { 35 | padding-top: 10px; 36 | 37 | font-weight: lighter; 38 | font-size: 28px; 39 | line-height: 34px; 40 | letter-spacing: 2px; 41 | } 42 | -------------------------------------------------------------------------------- /unifi-api.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #username=ubnt 4 | #password=ubnt 5 | #baseurl=https://unifi:8443 6 | #site=default 7 | #[ -f ./unifi_sh_env ] && . ./unifi_sh_env 8 | 9 | cookie=$(mktemp) 10 | 11 | curl_cmd="curl --tlsv1 --silent --cookie ${cookie} --cookie-jar ${cookie} --insecure " 12 | 13 | named_args_to_payload() { 14 | payload="" 15 | for a in "$@" ; do 16 | if [ "${a##*=*}" = "" ] ; then 17 | k=`echo $a | cut -d = -f 1` 18 | v=`echo $a | cut -d = -f 2` 19 | payload="${payload}, \"$k\":\"$v\"" 20 | fi 21 | done 22 | echo ${payload} 23 | } 24 | 25 | unifi_requires() { 26 | if [ -z "$username" -o -z "$password" -o -z "$baseurl" -o -z "$site" ] ; then 27 | echo "Error! please define required env vars before including unifi_sh. E.g. " 28 | echo "" 29 | echo "export username=ubnt" 30 | echo "export password=ubnt" 31 | echo "export baseurl=https://localhost:8443" 32 | echo "export site=default" 33 | echo "" 34 | return 35 | fi 36 | } 37 | 38 | unifi_login() { 39 | # authenticate against unifi controller 40 | ${curl_cmd} --data "{\"username\":\"$username\", \"password\":\"$password\"}" $baseurl/api/login 41 | } 42 | 43 | unifi_logout() { 44 | # logout 45 | ${curl_cmd} $baseurl/logout 46 | } 47 | 48 | unifi_api() { 49 | if [ $# -lt 1 ] ; then 50 | echo "Usage: $0 [json]" 51 | echo " uri example /stat/sta " 52 | return 53 | fi 54 | uri=$1 55 | shift 56 | [ "${uri:0:1}" != "/" ] && uri="/$uri" 57 | json="$@" 58 | [ "$json" = "" ] && json="{}" 59 | ${curl_cmd} --data "$json" $baseurl/api/s/$site$uri 60 | } 61 | 62 | # cmd/stamgr 63 | # authorize-guest(mac, minutes, [up=kbps, down=kbps, bytes=MB]) 64 | unifi_authorize_guest() { 65 | if [ $# -lt 2 ] ; then 66 | echo "Usage: $0 [up=kbps] [down=kbps] [bytes=MB] [ap_mac=mac]" 67 | return 68 | fi 69 | 70 | mac=$1 71 | minutes=$2 72 | other_payload=`named_args_to_payload "$@"` 73 | 74 | ${curl_cmd} --data "{\"cmd\":\"authorize-guest\", \"mac\":\"${mac}\", \"minutes\":${minutes}${other_payload}}" $baseurl/api/s/$site/cmd/stamgr 75 | } 76 | 77 | # cmd/stamgr 78 | # unauthorize-guest(mac) 79 | unifi_unauthorize_guest() { 80 | if [ $# -lt 1 ] ; then 81 | echo "Usage: $0 " 82 | return 83 | fi 84 | 85 | mac=$1 86 | 87 | ${curl_cmd} --data "{\"cmd\":\"unauthorize-guest\", \"mac\":\"${mac}\"}" $baseurl/api/s/$site/cmd/stamgr 88 | } 89 | 90 | # cmd/stamgr 91 | # kick-sta(mac) 92 | unifi_reconnect_sta() { 93 | if [ $# -lt 1 ] ; then 94 | echo "Usage: $0 " 95 | return 96 | fi 97 | 98 | mac=$1 99 | 100 | ${curl_cmd} --data "{\"cmd\":\"kick-sta\", \"mac\":\"${mac}\"}" $baseurl/api/s/$site/cmd/stamgr 101 | } 102 | 103 | # cmd/stamgr 104 | # block-sta(mac) 105 | unifi_block_sta() { 106 | if [ $# -lt 1 ] ; then 107 | echo "Usage: $0 " 108 | return 109 | fi 110 | 111 | mac=$1 112 | 113 | ${curl_cmd} --data "{\"cmd\":\"block-sta\", \"mac\":\"${mac}\"}" $baseurl/api/s/$site/cmd/stamgr 114 | } 115 | 116 | unifi_backup() { 117 | if [ "$1" = "" ]; then 118 | output=unifi-backup.unf # or `date +%Y%m%d`.unf 119 | else 120 | output=$1 121 | fi 122 | 123 | # ask controller to do a backup, response contains the path to the backup file 124 | path=`$curl_cmd --data "{\"cmd\":\"backup\"}" $baseurl/api/s/$site/cmd/backup | sed -n 's/.*\(\/dl.*unf\).*/\1/p'` 125 | 126 | # download the backup to the destinated output file 127 | $curl_cmd $baseurl$path -o $output 128 | } 129 | 130 | # cmd/hotspot 131 | # create-voucher(expires, n, [note=notes, up=kbps, down=kbps, bytes=MB]) 132 | # @returns create_time 133 | unifi_create_voucher() { 134 | if [ $# -lt 2 ] ; then 135 | echo "Usage: $0 [note=notes] [up=kbps] [down=kbps] [bytes=MB]" 136 | return 137 | fi 138 | minutes=$1 139 | n=$2 140 | other_payload=`named_args_to_payload "$@"` 141 | token=`${curl_cmd} --data "{\"cmd\":\"create-voucher\",\"expire\":${minutes},\"n\":$n ${other_payload}}" $baseurl/api/s/$site/cmd/hotspot \ 142 | | sed -e 's/.*"create_time"\s*:\s*\([0-9]\+\).*/\1/'` 143 | echo "token=$token" 144 | if [ "$token" != "" ] ; then 145 | ${curl_cmd} --data "{\"create_time\":${token}}" $baseurl/api/s/$site/stat/voucher 146 | echo $token > create.tmp 147 | fi 148 | } 149 | 150 | # stat/voucher 151 | # query(create_time) 152 | unifi_get_vouchers() { 153 | set -x 154 | if [ $# -lt 0 ] ; then 155 | echo "Usage: $0 [token]" 156 | return 157 | fi 158 | n=`cat create.tmp` 159 | token=$n 160 | [ "$token" != "" ] && other_payload="\"create_time\":${token}" 161 | ${curl_cmd} --data "{${other_payload}}" $baseurl/api/s/$site/stat/voucher 162 | echo ${curl_cmd} --data "{${other_payload}}" $baseurl/api/s/$site/stat/voucher 163 | } 164 | 165 | # delete-voucher(id) 166 | unifi_delete_voucher() { 167 | if [ $# -lt 1 ] ; then 168 | echo "Usage: $0 " 169 | return 170 | fi 171 | id=$1 172 | ${curl_cmd} --data "{\"cmd\":\"delete-voucher\",\"_id\":\"${id}\"}" $baseurl/api/s/$site/cmd/hotspot 173 | } 174 | 175 | # stat/sta 176 | unifi_list_sta() { 177 | ${curl_cmd} --data "{}" $baseurl/api/s/$site/stat/sta 178 | } 179 | 180 | # upgrade device to the given firmware 181 | unifi_upgrade_external() { 182 | if [ $# -lt 2 ] ; then 183 | echo "Usage: $0 " 184 | return 185 | fi 186 | 187 | mac=$1 188 | firmware_url=$2 189 | 190 | ${curl_cmd} --data "{\"url\":\"${firmware_url}\", \"mac\":\"${mac}\"}" $baseurl/api/s/$site/cmd/devmgr/upgrade-external 191 | } 192 | 193 | # press upgrade button 194 | unifi_upgrade() { 195 | if [ $# -lt 1 ] ; then 196 | echo "Usage: $0 " 197 | return 198 | fi 199 | 200 | mac=$1 201 | 202 | ${curl_cmd} --data "{\"mac\":\"${mac}\"}" $baseurl/api/s/$site/cmd/devmgr/upgrade 203 | } 204 | 205 | unifi_list_devices() { 206 | ${curl_cmd} --data "{}" $baseurl/api/s/$site/stat/device 207 | } 208 | unifi_create_admin() { 209 | if [ $# -lt 3 ] ; then 210 | echo "Usage: $0 " 211 | return 212 | fi 213 | 214 | uniemail=$1 215 | uniusername=$2 216 | unipassword=$3 217 | ${curl_cmd} --data "{\"cmd\":\"create-admin\", \"email\":\"${uniemail}\", \"name\":\"${uniusername}\", \"permissions\":\"\", \"requires_new_password\":\"true\", \"role\":\"readonly\", \"x_password\":\"${unipassword}\"}" $baseurl/api/s/$site/cmd/sitemgr 218 | } 219 | 220 | unifi_grant_superadmin () { 221 | if [ $# -lt 1 ] ; then 222 | echo "Usage: $0 accountID" 223 | return 224 | fi 225 | 226 | superid=$1 227 | ${curl_cmd} --data "{\"cmd\":\"grant-super-admin\", \"admin\":\"${superid}\"}" $baseurl/api/s/$site/cmd/sitemgr 228 | } 229 | unifi_requires 230 | --------------------------------------------------------------------------------