Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,14 @@ __pycache__
.vscode/launch.json
doc/_links.rst
etc/wifi_credentials
.node-red/
iotempower-admin-credentials
iotempower-admin-password.hash

.gradle
*.lock
gc.properties
cache.properties
buildOutput*/

.DS_Store
.DS_Store
49 changes: 29 additions & 20 deletions bin/iot_install
Original file line number Diff line number Diff line change
Expand Up @@ -546,30 +546,39 @@ if [[ "$install_node_red" == 1 ]]; then
init_nodejs
deactivate # termux can't do the following in venv - do we need to specialize this?
echo_format "Installing Node Red"
npm install --unsafe-perm node-red
npm install --unsafe-perm node-red bcryptjs
mkdir -p "$HOME/.node-red"
cp "$IOTEMPOWER_LOCAL"/nodejs/node_modules/node-red/settings.js "$HOME/.node-red/"
nodered_config=~/.node-red/settings.js

if ! grep -q "module.exports.httpAdminRoot = '/nodered';" "$nodered_config" ; then
cat << EOF >> "$nodered_config"
module.exports.httpAdminRoot = '/nodered';
module.exports.httpNodeRoot = '/nodered';
module.exports.adminAuth= {
type: "credentials",
users: [{
username: "admin",
password: "\$2b\$08\$W5LDP3eTaIYjz5iJkKVwMu9JDg3cPFMUvBypMCmYA3fpjYQlzFC4e",
permissions: "*"
}]
};
nodered_config="$HOME/.node-red/settings.js"
if [[ ! -f "$nodered_config" ]]; then
cp "$IOTEMPOWER_LOCAL"/nodejs/node_modules/node-red/settings.js "$nodered_config"
fi

if ! IOTEMPOWER_NODE_RED_AUTH_QUIET=1 bash "$IOTEMPOWER_ROOT/bin/nodered_ensure_admin_auth" "$nodered_config"; then
echo "Failed to configure Node-RED admin authentication, aborting." 1>&2
exit 1
fi
if grep -q "IOTEMPOWER_NODE_RED_ADMIN_AUTH" "$nodered_config"; then
cat << EOF
Node-RED admin account created.

Username: admin
Password file: ~/.node-red/iotempower-admin-credentials

Run:
iot nodered-password show
iot nodered-password reset
iot nodered-password set
EOF
pushd "$HOME/.node-red"
fi
pushd "$HOME/.node-red"
if ! npm ls @flowfuse/node-red-dashboard > /dev/null 2>&1; then
npm i @flowfuse/node-red-dashboard # install dashboard 2
fi
if ! npm ls node-red-contrib-influxdb > /dev/null 2>&1; then
npm i node-red-contrib-influxdb # install influxdb connector
popd
echo_format "Changed $nodered_config."
fi # node-red config
fi
popd
echo_format "Changed $nodered_config."
activate
fi # node-red

Expand Down
122 changes: 122 additions & 0 deletions bin/iot_nodered-password
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#!/usr/bin/env bash

usage() {
cat << EOF
Syntax: iot nodered-password <status|show|reset|set>

Manage the IoTempower-generated Node-RED admin password.

Commands:
status Show whether IoTempower-managed Node-RED auth is configured.
show Print the generated username and password if the recovery file exists and is mode 600.
reset Generate a new password and update the bcrypt hash plus recovery file.
set Prompt twice for a new password without echoing it, then update the hash plus recovery file.

The password is never accepted as a command-line argument, to avoid shell
history exposure.
EOF
}

if [[ "$1" = "help" || "$1" = "-h" || "$1" = "--help" || -z "$1" ]]; then
usage
exit 0
fi

[ "$IOTEMPOWER_ACTIVE" = "yes" ] || { echo "IoTempower not active, aborting." 1>&2; exit 1; }

command="$1"
shift

nodered_user_dir="${IOTEMPOWER_NODE_RED_USER_DIR:-$HOME/.node-red}"
nodered_config="${IOTEMPOWER_NODE_RED_SETTINGS_FILE:-$nodered_user_dir/settings.js}"
node_cli="$IOTEMPOWER_ROOT/bin/nodered_password_cli.js"

if [[ ! -f "$node_cli" ]]; then
echo "Cannot find Node-RED password helper: $node_cli" 1>&2
exit 1
fi

ensure_managed_auth() {
if ! bash "$IOTEMPOWER_ROOT/bin/nodered_ensure_admin_auth" "$nodered_config"; then
echo "Failed to configure IoTempower-managed Node-RED admin authentication." 1>&2
exit 1
fi
if ! node "$node_cli" is-managed "$nodered_config"; then
echo "Node-RED has custom adminAuth; not changing credentials." 1>&2
exit 1
fi
}

restart_reminder() {
cat << EOF

Restart Node-RED for the change to take effect:
iot service restart web
EOF
}

read_password_hidden() {
local prompt="$1"
local value=""

if [[ -t 0 && -e /dev/tty ]]; then
IFS= read -r -s -p "$prompt" value < /dev/tty
printf '\n' > /dev/tty
else
IFS= read -r -s value
fi
printf '%s' "$value"
}

case "$command" in
status)
[[ $# -eq 0 ]] || { usage 1>&2; exit 1; }
node "$node_cli" status "$nodered_config"
;;
show)
[[ $# -eq 0 ]] || { usage 1>&2; exit 1; }
node "$node_cli" show "$nodered_config"
;;
reset)
[[ $# -eq 0 ]] || { usage 1>&2; exit 1; }
ensure_managed_auth
if ! node "$node_cli" reset "$nodered_config"; then
exit 1
fi
restart_reminder
;;
set)
[[ $# -eq 0 ]] || {
echo "Do not pass the password on the command line. Run: iot nodered-password set" 1>&2
exit 1
}
ensure_managed_auth
password_one="$(read_password_hidden "New Node-RED admin password: ")"
password_two="$(read_password_hidden "Repeat Node-RED admin password: ")"
if [[ "$password_one" != "$password_two" ]]; then
echo "Passwords do not match." 1>&2
exit 1
fi
if [[ -z "$password_one" ]]; then
echo "Password must not be empty." 1>&2
exit 1
fi
if ! printf '%s' "$password_one" | node "$node_cli" set "$nodered_config"; then
unset password_one password_two
exit 1
fi
unset password_one password_two
restart_reminder
;;
ensure-files)
[[ $# -le 1 ]] || { usage 1>&2; exit 1; }
if [[ "${1:-}" ]]; then
nodered_config="$1"
fi
node "$node_cli" ensure-files "$nodered_config"
;;
*)
usage 1>&2
exit 1
;;
esac
Loading