-
-
Notifications
You must be signed in to change notification settings - Fork 13
/
pwned.sh
140 lines (116 loc) · 4.38 KB
/
pwned.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#!/usr/bin/env bash
# ==============================================================================
# Home Assistant Community Add-ons: Bashio
# Bashio is a bash function library for use with Home Assistant add-ons.
#
# It contains a set of commonly used operations and can be used
# to be included in add-on scripts to reduce code duplication across add-ons.
# ==============================================================================
# ------------------------------------------------------------------------------
# Checks if a given password is safe to use.
#
# Arguments:
# $1 The password to check
# ------------------------------------------------------------------------------
function bashio::pwned.is_safe_password() {
local password="${1}"
local occurrences
bashio::log.trace "${FUNCNAME[0]}" "<REDACTED PASSWORD>"
if ! occurrences=$(bashio::pwned "${password}"); then
bashio::log.warning "Could not check password, assuming it is safe."
return "${__BASHIO_EXIT_OK}"
fi
if [[ "${occurrences}" -ne 0 ]]; then
return "${__BASHIO_EXIT_NOK}"
fi
return "${__BASHIO_EXIT_OK}"
}
# ------------------------------------------------------------------------------
# Gets the number of occurrences of the password in the list.
#
# Arguments:
# $1 The password to check
# ------------------------------------------------------------------------------
function bashio::pwned.occurances() {
local password="${1}"
local occurrences
bashio::log.trace "${FUNCNAME[0]}" "<REDACTED PASSWORD>"
if ! occurrences=$(bashio::pwned "${password}"); then
occurrences="0"
fi
echo -n "${occurrences}"
return "${__BASHIO_EXIT_OK}"
}
# ------------------------------------------------------------------------------
# Makes a call to the Have I Been Pwned password database
#
# Arguments:
# $1 The password to check
# ------------------------------------------------------------------------------
function bashio::pwned() {
local password="${1}"
local response
local status
local hibp_hash
local count
bashio::log.trace "${FUNCNAME[0]}" "${password//./x}"
# Do not check empty password
if ! bashio::var.has_value "${password}"; then
bashio::log.warning 'Cannot check empty password against HaveIBeenPwned.'
return "${__BASHIO_EXIT_NOK}"
fi
# Hash the password
password=$(echo -n "${password}" \
| sha1sum \
| tr '[:lower:]' '[:upper:]' \
| awk -F' ' '{ print $1 }'
)
bashio::log.debug "Password SHA1: ${password}"
# Check with have I Been Pwned, only send the first 5 chars of the hash
if ! response=$(curl \
--silent \
--show-error \
--write-out '\n%{http_code}' \
--request GET \
"${__BASHIO_HIBP_ENDPOINT}/${password:0:5}"
); then
bashio::log.debug "${response}"
bashio::log.error "Something went wrong contacting the HIBP API"
return "${__BASHIO_EXIT_NOK}"
fi
status=${response##*$'\n'}
response=${response%"$status"}
bashio::log.debug "Requested API resource: ${__BASHIO_HIBP_ENDPOINT}/${password:0:5}"
bashio::log.debug "API HTTP Response code: ${status}"
bashio::log.trace "API Response: ${response}"
if [[ "${status}" -eq 429 ]]; then
bashio::log.error "HIBP Rate limit exceeded."
return "${__BASHIO_EXIT_NOK}"
fi
if [[ "${status}" -eq 503 ]]; then
bashio::log.error "HIBP Service unavailable."
return "${__BASHIO_EXIT_NOK}"
fi
if [[ "${status}" -ne 200 ]]; then
bashio::log.error "Unknown HIBP HTTP error occurred."
return "${__BASHIO_EXIT_NOK}"
fi
# Check the list of returned hashes for a match
for hibp_hash in ${response}; do
if [[ "${password:5:35}" == "${hibp_hash%%:*}" ]]; then
# Found a match! This is bad :(
count=$(echo "${hibp_hash#*:}" | tr -d '\r')
bashio::log.warning \
"Password is in the Have I Been Pwned database!"
bashio::log.warning \
"Password appeared ${count} times!"
echo "${count}"
# Well, at least the execution of this function succeeded.
return "${__BASHIO_EXIT_OK}"
fi
done
# Password was not found
echo "0"
bashio::log.info "Password is NOT in the Have I Been Pwned database! Nice!"
return "${__BASHIO_EXIT_OK}"
}