├── .gitattributes ├── files ├── var │ └── www │ │ ├── a │ │ ├── favicon.png │ │ ├── logo-ipeye.webp │ │ ├── chevron-compact-up.svg │ │ ├── chevron-compact-down.svg │ │ ├── palette-fill.svg │ │ ├── shadows.svg │ │ ├── light-on.svg │ │ ├── light-off.svg │ │ ├── telegram.svg │ │ ├── palette.svg │ │ ├── transparency.svg │ │ ├── ir940.svg │ │ ├── ir850.svg │ │ ├── gear.svg │ │ ├── imp-config.js │ │ └── github.svg │ │ ├── favicon.ico │ │ ├── cgi-bin │ │ ├── info-top.cgi │ │ ├── info-modules.cgi │ │ ├── info-dmesg.cgi │ │ ├── info-netstat.cgi │ │ ├── info-httpd.cgi │ │ ├── p │ │ │ ├── reset-firmware.cgi │ │ │ ├── locale_en.sh │ │ │ ├── footer.cgi │ │ │ ├── mac-address.cgi │ │ │ └── icons.cgi │ │ ├── info-majestic.cgi │ │ ├── info-cron.cgi │ │ ├── firmware-reset.cgi │ │ ├── reboot.cgi │ │ ├── info-overlay.cgi │ │ ├── j │ │ │ ├── sync-time.cgi │ │ │ ├── reset-ntp.cgi │ │ │ ├── color.cgi │ │ │ ├── night.cgi │ │ │ ├── ircut.cgi │ │ │ ├── irled.cgi │ │ │ ├── run.cgi │ │ │ ├── heartbeat.cgi │ │ │ └── imp.cgi │ │ ├── restore.cgi │ │ ├── image.cgi │ │ ├── dl.cgi │ │ ├── info-proc-umap.cgi │ │ ├── majestic-config-compare.cgi │ │ ├── send.cgi │ │ ├── firmware-update.cgi │ │ ├── dl2.cgi │ │ ├── info-log.cgi │ │ ├── config.cgi │ │ ├── info-imp.cgi │ │ ├── info-ipctool.cgi │ │ ├── reset.cgi │ │ ├── network-socks5.cgi │ │ ├── status.cgi │ │ ├── file-manager.cgi │ │ ├── firmware-upload-parts.cgi │ │ ├── admin.cgi │ │ ├── plugin-vtun.cgi │ │ ├── plugin-playonspeaker.cgi │ │ ├── plugin-send2webhook.cgi │ │ ├── plugin-send2yadisk.cgi │ │ ├── console.cgi │ │ ├── firmware.cgi │ │ ├── ssh-keys.cgi │ │ ├── sensor.cgi │ │ ├── plugin-send2ntfy.cgi │ │ ├── plugin-send2ftp.cgi │ │ ├── sdcard.cgi │ │ ├── plugin-send2telegram.cgi │ │ ├── plugin-send2openwall.cgi │ │ ├── config-light.cgi │ │ ├── tools.cgi │ │ ├── time-config.cgi │ │ ├── majestic-config-actions.cgi │ │ ├── users.cgi │ │ ├── plugin-send2email.cgi │ │ ├── webui-settings.cgi │ │ ├── texteditor.cgi │ │ ├── plugin-send2mqtt.cgi │ │ ├── plugin-motion.cgi │ │ ├── plugin-zerotier.cgi │ │ ├── majestic.cgi │ │ ├── network.cgi │ │ └── majestic-endpoints.cgi │ │ ├── index.html │ │ ├── majestic │ │ └── index.html │ │ ├── 401.html │ │ └── wait.html └── usr │ └── sbin │ ├── imp-control.sh │ ├── send2pastebin.sh │ ├── updatewebui.sh │ ├── common-plugins │ ├── color.sh │ ├── irled.sh │ ├── common │ ├── motion.sh │ ├── ircut.sh │ ├── playonspeaker.sh │ ├── snapshot4cron.sh │ ├── send2webhook.sh │ ├── daynight.sh │ ├── send2ntfy.sh │ ├── send2ftp.sh │ ├── sendcoredump.sh │ ├── send2yadisk.sh │ ├── send2mqtt.sh │ ├── send2openwall.sh │ ├── send2email.sh │ ├── send2telegram.sh │ └── updatemajestic.sh ├── .gitignore ├── dev ├── devstrap.sh └── css │ └── main.scss ├── wirebox ├── preview-video.cgi └── plugin-ipeye.cgi ├── LICENSE └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | *.cgi linguist-detectable=false 2 | -------------------------------------------------------------------------------- /files/var/www/a/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIPC/webui/HEAD/files/var/www/a/favicon.png -------------------------------------------------------------------------------- /files/var/www/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIPC/webui/HEAD/files/var/www/favicon.ico -------------------------------------------------------------------------------- /files/var/www/a/logo-ipeye.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIPC/webui/HEAD/files/var/www/a/logo-ipeye.webp -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .~* 3 | src/* 4 | .env 5 | _Deparsed_XSubs.pm 6 | files/var/www/a/SMPTE_Color_Bars.svg 7 | files/var/www/a/SMPTE_Color_Bars_16x9.svg 8 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/info-top.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% page_title="Top processes" %> 4 | <%in p/header.cgi %> 5 | <% ex "top -n 1 -b" %> 6 | <%in p/footer.cgi %> 7 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/info-modules.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% page_title="Modules" %> 4 | <%in p/header.cgi %> 5 | <% ex "lsmod" %> 6 | <% button_refresh %> 7 | <%in p/footer.cgi %> 8 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/info-dmesg.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% page_title="Diagnostic messages" %> 4 | <%in p/header.cgi %> 5 | <% ex "/bin/dmesg" %> 6 | <% button_refresh %> 7 | <% button_download "dmesg" %> 8 | <%in p/footer.cgi %> 9 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/info-netstat.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% page_title="Networking statistics" %> 4 | <%in p/header.cgi %> 5 | <% ex "netstat -a" %> 6 | <% button_refresh %> 7 | <% button_download "netstat" %> 8 | <%in p/footer.cgi %> 9 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/info-httpd.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% page_title="HTTPd" %> 4 | <%in p/header.cgi %> 5 | <% ex "cat /etc/httpd.conf" %> 6 | <% button_restore_from_rom "/etc/httpd.conf" %> 7 | <% ex "/bin/printenv" %> 8 | <%in p/footer.cgi %> 9 | -------------------------------------------------------------------------------- /files/usr/sbin/imp-control.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This script provides a control interface for the libimp_control library. 4 | # It sends commands to the server listening on localhost port 4000. 5 | 6 | # Send the command and parameters to the server 7 | echo "imp_control $*" | nc localhost 4000 8 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/p/reset-firmware.cgi: -------------------------------------------------------------------------------- 1 |
2 |

Reset firmware

3 |

Revert firmware to its original state by wiping out overlay partition. All custom settings and all files stored on overlay partition will be lost!

4 | <% button_reset_firmware %> 5 |
6 | -------------------------------------------------------------------------------- /files/var/www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | OpenIPC 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /files/var/www/a/chevron-compact-up.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /files/var/www/majestic/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | Please open web interface on port 85. 12 | 13 | 14 | -------------------------------------------------------------------------------- /files/var/www/a/chevron-compact-down.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/info-majestic.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% page_title="Majestic config" %> 4 | <%in p/header.cgi %> 5 | <% ex "cat /etc/majestic.yaml" %> 6 |

Edit file

7 | <% button_restore_from_rom "/etc/majestic.yaml" %> 8 | <%in p/footer.cgi %> 9 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/info-cron.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% page_title="Cron settings" %> 4 | <%in p/header.cgi %> 5 | <% ex "cat /etc/crontabs/root" %> 6 |

Cron syntax cheatsheet

7 |

Edit file

8 | <%in p/footer.cgi %> 9 | -------------------------------------------------------------------------------- /files/usr/sbin/send2pastebin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -z "$1" ]; then 4 | echo "Usage: $0 " 5 | exit 1 6 | fi 7 | 8 | file="$1" 9 | if [ ! -f "$file" ]; then 10 | echo "Cannot find file ${file}" 11 | exit 2 12 | fi 13 | 14 | if [ -z "$(cat "$file")" ]; then 15 | echo "File ${file} is empty" 16 | exit 3 17 | fi 18 | 19 | url=$(cat "$file" | nc termbin.com 9999) 20 | echo "$url" 21 | 22 | exit 0 23 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/firmware-reset.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | page_title="Erasing overlay" 5 | c="/usr/sbin/sysupgrade -n" 6 | reboot="true" 7 | %> 8 | <%in p/header.cgi %> 9 |

10 | Go home
11 | Reboot camera
12 | <%in p/footer.cgi %>
13 | 


--------------------------------------------------------------------------------
/files/var/www/cgi-bin/reboot.cgi:
--------------------------------------------------------------------------------
 1 | #!/bin/sh
 2 | umount -a -t nfs -l
 3 | sleep 3
 4 | echo "HTTP/1.1 302 Moved Temporarily
 5 | Date: $(TZ=GMT0 date +'%a, %d %b %Y %T %Z')
 6 | Server: $SERVER_SOFTWARE
 7 | Content-type: text/html; charset=UTF-8
 8 | Cache-Control: no-store
 9 | Pragma: no-cache
10 | Location: /wait.html
11 | Status: 302 Moved Temporarily
12 | "
13 | echo # separate header
14 | echo "I'll be back"
15 | sleep 1
16 | reboot -f


--------------------------------------------------------------------------------
/files/var/www/cgi-bin/info-overlay.cgi:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/haserl
 2 | <%in p/common.cgi %>
 3 | <%
 4 | s=$(df | grep /overlay | xargs | cut -d' ' -f5)
 5 | page_title="Contents of the overlay partition"
 6 | %>
 7 | <%in p/header.cgi %>
 8 | 
9 |
Overlay partition is <%= $s %> full.
10 | <% progressbar "${s/%/}" %> 11 |
12 | <% ex "ls -Rl /overlay/" %> 13 | <%in p/reset-firmware.cgi %> 14 | <%in p/footer.cgi %> 15 | -------------------------------------------------------------------------------- /files/usr/sbin/updatewebui.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | url="https://github.com/openipc/webui/archive/refs/heads/master.zip" 3 | 4 | tmp_zip=$(mktemp -u) 5 | curl -s -L $url -o $tmp_zip 6 | 7 | tmp_dir=$(mktemp -d) 8 | unzip -q -o -d $tmp_dir $tmp_zip 9 | 10 | repo=$(ls $tmp_dir) 11 | rm -f $(find /var/www -type f) 12 | 13 | echo "Copy files to web directory" 14 | cp -rf $tmp_dir/$repo/files/* / 15 | 16 | echo "Delete temporary files" 17 | rm -rf $tmp_dir $tmp_zip 18 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/j/sync-time.cgi: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if /usr/sbin/ntpd -n -q -N; then 4 | payload='{"result":"success","message":"Camera time synchronized with NTP server."}' 5 | else 6 | payload='{"result":"danger","message":"Synchronization failed!"}' 7 | fi 8 | 9 | echo "HTTP/1.1 200 OK 10 | Content-type: application/json 11 | Pragma: no-cache 12 | Expires: $(TZ=GMT0 date +'%a, %d %b %Y %T %Z') 13 | Etag: \"$(cat /proc/sys/kernel/random/uuid)\" 14 | 15 | ${payload} 16 | " 17 | -------------------------------------------------------------------------------- /files/var/www/a/palette-fill.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /files/usr/sbin/common-plugins: -------------------------------------------------------------------------------- 1 | . /usr/sbin/common 2 | 3 | if [ -z "$plugin" ]; then 4 | log "ERROR: No plugin name found." 5 | log "This file should not be called directly!" 6 | quit_clean 2 7 | fi 8 | 9 | CONFIG_FILE="/etc/webui/${plugin}.conf" 10 | 11 | log "Plugin ${plugin} initialized." 12 | 13 | if [ -f "$CONFIG_FILE" ]; then 14 | log "Reading configuration from ${CONFIG_FILE}." 15 | source "$CONFIG_FILE" 16 | else 17 | log "Configuration file ${CONFIG_FILE} not found." 18 | fi 19 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/restore.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | [ -z "$GET_f" ] && set_error_flag "Nothing to restore." 5 | 6 | file=$GET_f 7 | [ ! -f "/rom/${file}" ] && set_error_flag "File /rom/${file} not found!" 8 | 9 | [ -n "$error" ] && redirect_back 10 | 11 | cp "/rom/${file}" "${file}" 12 | if [ $? -eq 0 ]; then 13 | redirect_back "success" "File ${file} restored to firmware defaults." 14 | else 15 | redirect_back "danger" "Cannot restore ${file}!" 16 | fi 17 | %> 18 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/j/reset-ntp.cgi: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if cp /rom/etc/ntp.conf /etc/ntp.conf; then 4 | payload='{"result":"success","message":"Configuration reset to firmware defaults."}' 5 | else 6 | payload='{"result":"danger","message":"Configuration reset to firmware defaults failed!"}' 7 | fi 8 | 9 | echo "HTTP/1.1 200 OK 10 | Content-type: application/json 11 | Pragma: no-cache 12 | Expires: $(TZ=GMT0 date +'%a, %d %b %Y %T %Z') 13 | Etag: \"$(cat /proc/sys/kernel/random/uuid)\" 14 | 15 | ${payload} 16 | " 17 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/image.cgi: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | preview=/tmp/preview.jpg 3 | wget -q -O $preview http://127.0.0.1/image.jpg 4 | if [ ! -f "$preview" ]; then 5 | echo "HTTP/1.0 404" 6 | else 7 | echo "HTTP/1.1 200 OK 8 | Content-type: image/jpeg 9 | Content-Length: $(stat -c%s $preview) 10 | Pragma: no-cache 11 | Date: $(TZ=GMT0 date +'%a, %d %b %Y %T %Z') 12 | Expires: $(TZ=GMT0 date +'%a, %d %b %Y %T %Z') 13 | Etag: \"$(cat /proc/sys/kernel/random/uuid)\" 14 | Connecton: close 15 | " 16 | cat $preview 17 | rm $preview 18 | fi 19 | -------------------------------------------------------------------------------- /dev/devstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$1" ]; then 4 | echo "Usage: $0 " 5 | exit 6 | fi 7 | 8 | IPC_IP="root@192.168.1.$1" 9 | 10 | echo "Copy SSH key" 11 | ssh-copy-id "$IPC_IP" 12 | 13 | echo "Copy dev configs" 14 | scp -O ../files/etc/init.d/S50httpd "${IPC_IP}:/etc/init.d/S50httpd" 15 | 16 | echo "Set env variable for dev Web UI NFS share path" 17 | ssh "$IPC_IP" "fw_setenv devnfs $OPENIPC_WEBUI_DEV_SHARE" 18 | 19 | echo "Reboot" 20 | ssh "$IPC_IP" reboot -f 21 | 22 | echo "Done" 23 | exit 0 24 | -------------------------------------------------------------------------------- /files/var/www/a/shadows.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /files/var/www/a/light-on.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/dl.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | file=$GET_file 5 | if [ "/tmp/webui.log" = "$file" ]; then 6 | fname="webui-$(date +%s).log" 7 | mime="text/plain" 8 | else 9 | fname=$(basename $file) 10 | mime="application/octet-stream" 11 | fi 12 | check_file_exist $file 13 | echo "HTTP/1.0 200 OK 14 | Date: $(time_http) 15 | Server: $SERVER_SOFTWARE 16 | Content-type: ${mime} 17 | Content-Disposition: attachment; filename=${fname} 18 | Content-Length: $(stat -c%s $file) 19 | Cache-Control: no-store 20 | Pragma: no-cache 21 | " 22 | cat $file 23 | %> 24 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/info-proc-umap.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | files=$(ls -1 /proc/umap/) 5 | file=$GET_file 6 | if [ -z "$file" ]; then 7 | file=$(echo $files | awk '{print $1}') 8 | redirect_to "${SCRIPT_NAME}?file=${file}" 9 | fi 10 | page_title="Information from /proc/umap" 11 | %> 12 | <%in p/header.cgi %> 13 |

<% 14 | for f in $files; do 15 | css="btn btn-sm btn-primary" 16 | [ "$f" = "$file" ] && css="${css} active" 17 | echo "${f}" 18 | done 19 | %> 20 |

21 | <% ex "cat /proc/umap/${file}" %> 22 | <% button_refresh %> 23 | <%in p/footer.cgi %> 24 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/majestic-config-compare.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% page_title="Majestic configuration changes" %> 4 | <%in p/header.cgi %> 5 |
6 |
7 | <% 8 | config_file=/etc/majestic.yaml 9 | diff /rom$config_file $config_file >/tmp/majestic.patch 10 | ex "cat /tmp/majestic.patch" 11 | %> 12 |
13 |
14 | 17 |
18 |
19 | <%in p/footer.cgi %> 20 | -------------------------------------------------------------------------------- /wirebox/preview-video.cgi: -------------------------------------------------------------------------------- 1 |
2 | 6 |
7 | 8 | 18 | -------------------------------------------------------------------------------- /files/var/www/a/light-off.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/send.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | target="$GET_to" 5 | if [ -n "$(echo "email ftp openwall telegram yadisk webhook" | sed -n "/\b${target}\b/p")" ]; then 6 | /usr/sbin/snapshot4cron.sh -f >/dev/null 7 | [ "openwall" = "$target" ] && opts="-f" 8 | /usr/sbin/send2${target}.sh ${opts} >/dev/null 9 | redirect_back "success" "Sent to ${target}." 10 | elif [ "pastebin" = "$target" ]; then 11 | if [ "mjlog" = "$GET_file" ]; then 12 | t=$(mktemp) 13 | logread | grep 'user.info majestic' >$t 14 | url=$(/usr/sbin/send2${target}.sh $t) 15 | rm $t 16 | unset t 17 | redirect_to $url 18 | fi 19 | else 20 | redirect_back "danger" "Unknown target ${target}!" 21 | fi 22 | %> 23 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/firmware-update.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | page_title="Upgrading firmware" 5 | c="/usr/sbin/sysupgrade" 6 | reboot="true" 7 | [ "true" = "$POST_fw_kernel" ] && c="${c} -k" 8 | [ "true" = "$POST_fw_rootfs" ] && c="${c} -r" 9 | [ "true" = "$POST_fw_reset" ] && c="${c} -n" 10 | [ "true" = "$POST_fw_noreboot" ] && c="${c} -x" && reboot="false" 11 | [ "true" = "$POST_fw_enforce" ] && c="${c} --force_ver" 12 | %> 13 | <%in p/header.cgi %> 14 |

DO NOT CLOSE, REFRESH, OR NAVIGATE AWAY FROM THIS PAGE UNTIL THE PROCESS IS FINISHED!

15 |
# <%= $c %>
16 |

17 | <%in p/footer.cgi %>
18 | 


--------------------------------------------------------------------------------
/files/var/www/a/telegram.svg:
--------------------------------------------------------------------------------
1 | 
2 | 
3 | 
4 | 


--------------------------------------------------------------------------------
/files/var/www/cgi-bin/dl2.cgi:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/haserl
 2 | <%in p/common.cgi %>
 3 | <%
 4 | file=$(mktemp)
 5 | log="$GET_log"
 6 | case "$log" in
 7 | 	dmesg)
 8 | 		dmesg >$file
 9 | 		 ;;
10 | 	logread)
11 | 		logread >$file
12 | 		 ;;
13 | 	netstat)
14 | 		netstat -a >$file
15 | 		 ;;
16 | 	send2ntfy)
17 | 		send2ntfy.sh -b "If you see this, then your config works" -i false -v >$file
18 | 		;;
19 | 	*)
20 | 		echo "Unknown file."
21 | 		exit 1
22 | 		;;
23 | esac
24 | check_file_exist $file
25 | echo "HTTP/1.0 200 OK
26 | Date: $(time_http)
27 | Server: $SERVER_SOFTWARE
28 | Content-type: text/plain
29 | Content-Disposition: attachment; filename=${log}-$(date +%s).txt
30 | Content-Length: $(stat -c%s $file)
31 | Cache-Control: no-store
32 | Pragma: no-cache
33 | "
34 | cat $file
35 | rm $file
36 | %>
37 | 


--------------------------------------------------------------------------------
/files/usr/sbin/color.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/sh
 2 | 
 3 | # set parameters from cli, if empty
 4 | [ -z "$mode" ] && mode=$1
 5 | 
 6 | MODE_FILE=/tmp/colormode.txt
 7 | 
 8 | switch_to_color() {
 9 | 	curl http://127.0.0.1/night/off
10 | 	echo "Switched to full-color mode"
11 | 	echo "day" >$MODE_FILE
12 | }
13 | 
14 | switch_to_monochrome() {
15 | 	curl http://127.0.0.1/night/on
16 | 	echo "Switched to monochrome mode"
17 | 	echo "night" >$MODE_FILE
18 | }
19 | 
20 | case "$1" in
21 | 	off)
22 | 		switch_to_monochrome
23 | 		;;
24 | 	on)
25 | 		switch_to_color
26 | 		;;
27 | 	~ | toggle)
28 | 		if [ "$(cat $MODE_FILE 2>/dev/null)" = "day" ]; then
29 | 			switch_to_monochrome
30 | 		else
31 | 			switch_to_color
32 | 		fi
33 | 		;;
34 | 	*)
35 | 		echo "Unknown mode"
36 | 		exit 1
37 | 		;;
38 | esac
39 | 
40 | exit 0
41 | 


--------------------------------------------------------------------------------
/files/var/www/cgi-bin/info-log.cgi:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/haserl
 2 | <%in p/common.cgi %>
 3 | <% page_title="Log read" %>
 4 | <%in p/header.cgi %>
 5 | <% ex "/sbin/logread" %>
 6 | <% button_refresh %>
 7 | <% button_download "logread" %>
 8 | 
 9 | <% if [ -z "$(eval echo "DEBUG TRACE" | sed -n "/\b$(yaml-cli -g .system.logLevel)\b/p")" ]; then %>
10 | 
11 |

Send Majectic log to PasteBin

12 |

Please enable DEBUG level of logging in Majectic config to activate the button.

13 |
14 | <% else %> 15 | Send Majectic log to PasteBin 16 | <% fi %> 17 | 18 | <%in p/footer.cgi %> 19 | -------------------------------------------------------------------------------- /files/var/www/a/palette.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /files/var/www/a/transparency.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dev/css/main.scss: -------------------------------------------------------------------------------- 1 | // Functions first 2 | @import "../node_modules/bootstrap/scss/functions"; 3 | 4 | // Variable overrides second 5 | $primary: #900; 6 | $enable-shadows: true; 7 | $prefix: "mo-"; 8 | 9 | // Required Bootstrap imports 10 | @import "../node_modules/bootstrap/scss/variables"; 11 | @import "../node_modules/bootstrap/scss/maps"; 12 | @import "../node_modules/bootstrap/scss/mixins"; 13 | @import "../node_modules/bootstrap/scss/root"; 14 | 15 | // Optional components 16 | @import "../node_modules/bootstrap/scss/utilities"; 17 | @import "../node_modules/bootstrap/scss/reboot"; 18 | @import "../node_modules/bootstrap/scss/containers"; 19 | @import "../node_modules/bootstrap/scss/grid"; 20 | @import "../node_modules/bootstrap/scss/helpers"; 21 | @import "../node_modules/bootstrap/scss/utilities/api"; 22 | 23 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/j/color.cgi: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # parse parameters from query string 4 | [ -n "$QUERY_STRING" ] && eval $(echo "$QUERY_STRING" | sed "s/&/;/g") 5 | 6 | # quit if no mode set 7 | if [ -z "$mode" ]; then 8 | echo "HTTP/1.1 400 Bad Request" 9 | echo # separate headers from content 10 | echo "missing required pin1 parameter" 11 | exit 1 12 | fi 13 | 14 | case "$mode" in 15 | off | on | toggle) 16 | /usr/sbin/color.sh "$mode" 17 | echo "HTTP/1.1 200 OK 18 | Content-type: application/json 19 | Pragma: no-cache 20 | Expires: $(TZ=GMT0 date +'%a, %d %b %Y %T %Z') 21 | Etag: \"$(cat /proc/sys/kernel/random/uuid)\" 22 | 23 | {\"color\":\"${mode}\"} 24 | " 25 | ;; 26 | *) 27 | echo "HTTP/1.1 400 Bad Request" 28 | echo # separate headers from content 29 | echo "unknown mode" 30 | exit 1 31 | ;; 32 | esac 33 | 34 | exit 0 -------------------------------------------------------------------------------- /files/var/www/cgi-bin/j/night.cgi: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # parse parameters from query string 4 | [ -n "$QUERY_STRING" ] && eval $(echo "$QUERY_STRING" | sed "s/&/;/g") 5 | 6 | # quit if no mode set 7 | if [ -z "$mode" ]; then 8 | echo "HTTP/1.1 400 Bad Request" 9 | echo # separate headers from content 10 | echo "missing required mode parameter" 11 | exit 1 12 | fi 13 | 14 | case "$mode" in 15 | day | night | toggle) 16 | /usr/sbin/daynight.sh "$mode" 17 | echo "HTTP/1.1 200 OK 18 | Content-type: application/json 19 | Pragma: no-cache 20 | Expires: $(TZ=GMT0 date +'%a, %d %b %Y %T %Z') 21 | Etag: \"$(cat /proc/sys/kernel/random/uuid)\" 22 | 23 | {\"night\":\"${mode}\"} 24 | " 25 | ;; 26 | *) 27 | echo "HTTP/1.1 400 Bad Request" 28 | echo # separate headers from content 29 | echo "unknown mode" 30 | exit 1 31 | ;; 32 | esac 33 | 34 | exit 0 -------------------------------------------------------------------------------- /files/var/www/cgi-bin/j/ircut.cgi: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # parse parameters from query string 4 | [ -n "$QUERY_STRING" ] && eval $(echo "$QUERY_STRING" | sed "s/&/;/g") 5 | 6 | # quit if no mode set 7 | if [ -z "$mode" ]; then 8 | echo "HTTP/1.1 400 Bad Request" 9 | echo # separate headers from content 10 | echo "missing required pin1 parameter" 11 | exit 1 12 | fi 13 | 14 | case "$mode" in 15 | off | on | toggle) 16 | /usr/sbin/ircut.sh "$mode" $pin1 $pin2 17 | echo "HTTP/1.1 200 OK 18 | Content-type: application/json 19 | Pragma: no-cache 20 | Expires: $(TZ=GMT0 date +'%a, %d %b %Y %T %Z') 21 | Etag: \"$(cat /proc/sys/kernel/random/uuid)\" 22 | 23 | {\"ircut\":\"${mode}\"} 24 | " 25 | ;; 26 | *) 27 | echo "HTTP/1.1 400 Bad Request" 28 | echo # separate headers from content 29 | echo "unknown mode" 30 | exit 1 31 | ;; 32 | esac 33 | 34 | exit 0 -------------------------------------------------------------------------------- /files/var/www/cgi-bin/config.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | Date: <%= $(TZ=GMT0 date +"%a, %d %b %Y %T %Z" --date @$(( $(TZ=GMT0 date +%s) + 1000 ))) %> 3 | Server: <%= $SERVER_SOFTWARE %> 4 | Content-type: application/javascript; charset=UTF-8 5 | Access-Control-Allow-Origin: * 6 | Cache-Control: no-cache 7 | Connection: close 8 | 9 | <% 10 | readconfig() { 11 | local d 12 | local l 13 | local o="" 14 | local name 15 | local value 16 | for l in $(sed -n "/^\../p" p/mj.cgi|cut -d\| -f1); do 17 | d=${l%.*}; d=${d/./}; name=${l##*.} 18 | value=$(yaml-cli -g "$l") 19 | if [ "$o" != "$d" ]; then 20 | [ -n "$o" ] && echo -n "}," 21 | o="$d" 22 | echo -n "\"${d}\":{" 23 | else 24 | echo -n "," 25 | fi 26 | echo -n "\"${name}\":\"${value}\"" 27 | done 28 | } 29 | 30 | echo -n "readConfigYaml({" 31 | readconfig 32 | echo -n "}});" 33 | %> 34 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/info-imp.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | ipm_file="/usr/sbin/imp-control.sh" 5 | [ ! -f "${ipm_file}" ] && redirect_to '/' "danger" $STR_NOT_SUPPORTED 6 | page_title="IMP Control" 7 | commands="aihpf aiagc ains aiaec aivol aigain flip contrast brightness saturation sharpness sinter 8 | temper aecomp aeitmax dpc drc hilight again dgain hue ispmode flicker whitebalance sensorfps 9 | backlightcomp defogstrength framerate gopattr setbitrate setgoplength setqp setqpbounds setqpipdelta 10 | rcmode aemin autozoom frontcrop mask getosdattr getosdgrpattr getgamma getevattr getaeluma getawbct 11 | getafmetrics gettotalgain getaeattr getimpversion getsysversion getcpuinfo getdeviceid getmodelfamily" 12 | %> 13 | <%in p/header.cgi %> 14 | <% for i in $commands; do %> 15 | <% ex "${ipm_file} $i" %> 16 | <% done %> 17 | <% ex "${ipm_file} help" %> 18 | <%in p/footer.cgi %> 19 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/info-ipctool.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | actions="info i2cdetect reginfo" 5 | action=$GET_action 6 | if [ -z "$action" ]; then 7 | action=$(echo $actions | awk '{print $1}') 8 | redirect_to "${SCRIPT_NAME}?action=${action}" 9 | fi 10 | command="ipctool" 11 | page_title="IPC Tool" 12 | if [ "$action" = "info" ]; then 13 | command="${command}" 14 | page_title="${page_title}: Camera Information" 15 | else 16 | command="${command} ${action}" 17 | page_title="${page_title}: ${action}" 18 | fi 19 | # ipctool i2cdump 0x78 0x0 0x3ff 20 | %> 21 | <%in p/header.cgi %> 22 |

<% 23 | for c in $actions; do 24 | css="btn btn-sm btn-primary" 25 | [ "$c" = "$action" ] && css="${css} active" 26 | echo "${c}" 27 | done 28 | %> 29 |

30 | <% ex "${command}" %> 31 | <% button_refresh %> 32 | <%in p/footer.cgi %> 33 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/j/irled.cgi: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # parse parameters from query string 4 | [ -n "$QUERY_STRING" ] && eval $(echo "$QUERY_STRING" | sed "s/&/;/g") 5 | 6 | # quit if no mode set 7 | if [ -z "$mode" ]; then 8 | echo "HTTP/1.1 400 Bad Request" 9 | echo # separate headers from content 10 | echo "missing required mode parameter" 11 | exit 1 12 | fi 13 | 14 | # use ir850 as default LED if not set 15 | [ -z "$type" ] && type="ir850" 16 | 17 | case "$mode" in 18 | off | on | toggle) 19 | /usr/sbin/irled.sh "$mode" "$type" 20 | echo "HTTP/1.1 200 OK 21 | Content-type: application/json 22 | Pragma: no-cache 23 | Expires: $(TZ=GMT0 date +'%a, %d %b %Y %T %Z') 24 | Etag: \"$(cat /proc/sys/kernel/random/uuid)\" 25 | 26 | {\"led_${type}\":\"${mode}\"} 27 | " 28 | ;; 29 | *) 30 | echo "HTTP/1.1 400 Bad Request" 31 | echo # separate headers from content 32 | echo "unknown mode" 33 | exit 1 34 | ;; 35 | esac 36 | 37 | exit 0 -------------------------------------------------------------------------------- /files/var/www/a/ir940.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/reset.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% page_title="Reset things" %> 4 | <%in p/header.cgi %> 5 | 6 |
7 |
8 |
9 |

Reboot camera

10 |

Reboot camera to apply new settings. That will also delete all data on partitions mounted into system memory, e.g. /tmp.

11 | <% button_reboot %> 12 |
13 |
14 |
15 | <%in p/reset-firmware.cgi %> 16 |
17 |
18 |
19 |

Reset Majestic settings

20 |

Revert Majestic configuration file /etc/majestic.yaml to its pristine state. All changes will be lost! 21 | You might want to back up recent configuration before you reset.

22 | <% button_mj_reset %> 23 |
24 |
25 |
26 | 27 | <%in p/footer.cgi %> 28 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/j/run.cgi: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "HTTP/1.1 200 OK 4 | Date: $(TZ=GMT0 date +'%a, %d %b %Y %T %Z') 5 | Server: $SERVER_SOFTWARE 6 | Content-type: text/html; charset=UTF-8 7 | Cache-Control: no-store 8 | Pragma: no-cache 9 | " 10 | 11 | # parse parameters from query string 12 | [ -n "$QUERY_STRING" ] && eval $(echo "$QUERY_STRING" | sed "s/&/;/g") 13 | 14 | # exit if no command sent 15 | [ -z "$cmd" ] && exit 1 16 | 17 | # restore command from Base64 data 18 | c=$(echo $cmd | base64 -d) 19 | 20 | # exit if command is empty 21 | [ -z "$c" ] && echo "No command!" && exit 22 | 23 | prompt() { 24 | echo -e "[$(whoami)@$(hostname) $PWD]# ${1}" 25 | } 26 | 27 | export PATH=/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin 28 | cd /tmp || return 29 | prompt "$c\n" 30 | eval $c 2>&1 31 | 32 | case "$?" in 33 | 126) 34 | echo "-sh: $c: Permission denied" 35 | prompt 36 | ;; 37 | 127) 38 | echo "-sh: $c: not found" 39 | prompt 40 | ;; 41 | 0) 42 | prompt 43 | ;; 44 | *) 45 | echo -e "\nEXIT CODE: $?" 46 | esac 47 | 48 | exit 0 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 OpenIPC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /files/var/www/a/ir850.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /files/usr/sbin/irled.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # set parameters from cli, if empty 4 | [ -z "$mode" ] && mode=$1 5 | [ -z "$type" ] && type=$2 6 | 7 | # set parameters to default values, if empty 8 | [ -z "$type" ] && type="ir850" # most common IR led 9 | 10 | # read LED pin from bootloader environment 11 | pin=$(fw_printenv -n ${type}_led_pin) 12 | 13 | if [ -z "$pin" ]; then 14 | # read LED pin from majestic config 15 | case "$type" in 16 | ir850) 17 | [ -z "$pin" ] && pin=$(cli -g .nightMode.backlightPin) 18 | ;; 19 | ir940) 20 | #[ -z "$pin" ] && pin=$(cli -g .nightMode.backlightPin) 21 | ;; 22 | white) 23 | #[ -z "$pin" ] && pin=$(cli -g .nightMode.backlightPin) 24 | ;; 25 | *) 26 | echo "Unknown LED type" 27 | exit 2 28 | ;; 29 | esac 30 | fi 31 | 32 | if [ -z "$pin" ]; then 33 | echo "Please define ${type} GPIO pin" 34 | echo "fw_setenv ${type}_led_pin " 35 | exit 1 36 | fi 37 | 38 | case "$mode" in 39 | on | 1) 40 | gpio set $pin >/dev/null 41 | ;; 42 | off | 0) 43 | gpio clear $pin >/dev/null 44 | ;; 45 | ~ | toggle) 46 | gpio toggle $pin >/dev/null 47 | ;; 48 | *) 49 | echo "Unknown mode" 50 | exit 3 51 | ;; 52 | esac 53 | 54 | exit 0 55 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/network-socks5.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | plugin="socks5" 5 | page_title="SOCKS5 proxy" 6 | 7 | config_file="${ui_config_dir}/${plugin}.conf" 8 | [ ! -f "$config_file" ] && touch $config_file 9 | 10 | if [ "POST" = "$REQUEST_METHOD" ]; then 11 | tmp_file=/tmp/${plugin}.conf 12 | :>$tmp_file 13 | for v in enabled host port username password; do 14 | eval echo "${plugin}_${v}=\\\"\$POST_${plugin}_${v}\\\"" >>$tmp_file 15 | done 16 | mv $tmp_file $config_file 17 | redirect_to $SCRIPT_NAME 18 | fi 19 | 20 | include $config_file 21 | %> 22 | 23 | <%in p/header.cgi %> 24 | 25 |
26 |
27 |
28 | <% field_hidden "action" "update" %> 29 | <% field_text "socks5_host" "SOCKS5 Host" %> 30 | <% field_text "socks5_port" "SOCKS5 Port" "1080" %> 31 | <% field_text "socks5_username" "SOCKS5 Username" %> 32 | <% field_password "socks5_password" "SOCKS5 Password" %> 33 | <% button_submit %> 34 |
35 |
36 |
37 | <% ex "cat $config_file" %> 38 |
39 |
40 | 41 | <%in p/footer.cgi %> 42 | -------------------------------------------------------------------------------- /files/var/www/401.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Authentication required - OpenIPC 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 |
17 |

Authentication required

18 |

Exhausting, huh?

19 |

Have you tried to use username "root" and password "12345"?

20 |

You can find more useful information in our wiki.

21 |
22 |
23 |
24 |
25 |
26 |

Powered by Web UI, a part of OpenIPC project.

27 |
28 |
29 | 30 | 31 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/status.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% page_title="Device status" %> 4 | <%in p/header.cgi %> 5 | 6 |
7 |
8 |

Camera

9 |
Hardware
10 |
11 |
Processor
12 |
<%= $soc %>
13 |
Family
14 |
<%= $soc_family %>
15 |
Sensor
16 |
<%= $sensor_ini %>
17 |
Flash
18 |
<%= $flash_size %> MB
19 |
20 |
21 | 22 |
23 |

System

24 |
Firmware
25 |
26 |
Version
27 |
<%= "${fw_version}-${fw_variant}" %>
28 |
Build
29 |
<%= $fw_build %>
30 |
Majestic
31 |
<%= $mj_version %>
32 |
Web UI
33 |
<%= $ui_version %>
34 |
U-Boot
35 |
<%= $uboot_version %>
36 |
37 |
38 | 39 |
40 | <% ex "cat /etc/os-release" %> 41 |
42 |
43 | 44 |
45 |
46 |

Resources

47 | <% ex "/usr/bin/uptime" %> 48 | <% ex "df -T" %> 49 | <% ex "cat /proc/meminfo | grep Mem" %> 50 |
51 |
52 | 53 | <%in p/footer.cgi %> 54 | -------------------------------------------------------------------------------- /files/usr/sbin/common: -------------------------------------------------------------------------------- 1 | PID=$$ 2 | LOCK_FILE="/var/run/process-${PID}.pid" 3 | LOG_FILE=/tmp/webui.log 4 | LOG_SIZE_LIMIT=50000 5 | 6 | curl_timeout=100 7 | 8 | echo_c() { 9 | # 31 red, 32 green, 33 yellow, 34 blue, 35 magenta, 36 cyan, 37 white, 38 grey 10 | local t 11 | [ -z "$HASERLVER" ] && t="\e[1;$1m$2\e[0m" || t="$2" 12 | echo -e "$t" 13 | } 14 | 15 | log() { 16 | # poor man's logrotate 17 | if [ -f "$LOG_FILE" ] && [ "$(stat -c%s "$LOG_FILE")" -gt $LOG_SIZE_LIMIT ]; then 18 | # redundant, but calling log() from within log() is wrong! 19 | echo "$(date +"%F %T") [${PID}:${plugin}] Rotate log file" >>"$LOG_FILE" 20 | mv "$LOG_FILE" "${LOG_FILE}.1" 21 | echo "$(date +"%F %T") [${PID}:${plugin}] Log file rotated." >>"$LOG_FILE" 22 | fi 23 | echo "$(date +"%F %T") [${PID}:${plugin}] ${1}" >>"$LOG_FILE" 24 | } 25 | 26 | log_and_run() { 27 | log "$1" 34 28 | run "$1" 29 | } 30 | 31 | quit_clean() { 32 | if [ -f "$LOCK_FILE" ]; then 33 | log "Remove lock file ${LOCK_FILE}." 34 | rm "$LOCK_FILE" 35 | fi 36 | log "Exit [$1]." 37 | exit "$1" 38 | } 39 | 40 | run() { 41 | local r 42 | r=$(eval "$1" >>"$LOG_FILE" 2>&1) 43 | echo "RESULT: ${r}" 44 | } 45 | 46 | singleton() { 47 | log "Check lock file ${LOCK_FILE}." 48 | if [ -f "$LOCK_FILE" ] && ps | grep "^\s*\b$(cat "$LOCK_FILE")\b" >/dev/null; then 49 | log "Another instance running with PID $(cat "$LOCK_FILE")." 50 | exit 1 51 | fi 52 | printf "%d\n" $PID >"$LOCK_FILE" 53 | log "Create lock file ${LOCK_FILE}." 54 | } 55 | -------------------------------------------------------------------------------- /files/var/www/a/gear.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /files/var/www/wait.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Please wait... - OpenIPC 7 | 8 | 32 | 33 | 34 |
35 |

OpenIPC

36 |

Restarting. Please wait...

37 | 38 |
39 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/p/locale_en.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #name:English 3 | 4 | tT_mj_audio="Audio" 5 | tT_mj_cloud="Cloud" 6 | tT_mj_hls="HLS" 7 | tT_mj_image="Image" 8 | tT_mj_ipeye="IPEYE" 9 | tT_mj_isp="ISP" 10 | tT_mj_jpeg="JPEG" 11 | tT_mj_mjpeg="MJPEG" 12 | tT_mj_motionDetect="Alarm" 13 | tT_mj_netip="NETIP" 14 | tT_mj_nightMode="Night Mode" 15 | tT_mj_onvif="ONVIF" 16 | tT_mj_osd="OSD" 17 | tT_mj_outgoing="Outgoing" 18 | tT_mj_records="Recording" 19 | tT_mj_rtsp="RTSP" 20 | tT_mj_system="System" 21 | tT_mj_video0="Video0" 22 | tT_mj_video1="Video1" 23 | tT_mj_watchdog="Watchdog" 24 | tT_mj_youtube="Youtube" 25 | 26 | tT2_mj_cloud="Cloud Support" 27 | tT2_mj_hls="HTTP Live Streaming" 28 | tT2_mj_ipeye="IPEYE Protocol" 29 | tT2_mj_isp="Image Signal Processor" 30 | tT2_js_osd="On-screen Display" 31 | tT2_mj_motionDetect="In-Camera Motion Detection" 32 | tT2_mj_netip="NETIP Protocol" 33 | tT2_mj_onvif="ONVIF Protocol" 34 | tT2_mj_rtsp="Real Time Streaming Protocol" 35 | tT2_mj_video0="Mainstream Video" 36 | tT2_mj_video1="Substream Video" 37 | 38 | t_nav_mj_audio="Audio" 39 | t_nav_mj_cloud="Cloud" 40 | t_nav_mj_hls="HLS" 41 | t_nav_mj_image="Image" 42 | t_nav_mj_isp="ISP" 43 | t_nav_mj_jpeg="JPEG" 44 | t_nav_mj_mjpeg="MJPEG" 45 | t_nav_mj_motionDetect="Motion" 46 | t_nav_mj_netip="NETIP" 47 | t_nav_mj_nightMode="Night Mode" 48 | t_nav_mj_onvif="ONVIF" 49 | t_nav_mj_osd="OSD" 50 | t_nav_mj_records="Recording" 51 | t_nav_mj_rtsp="RTSP" 52 | t_nav_mj_system="System" 53 | t_nav_mj_video0="Video0" 54 | t_nav_mj_video1="Video1" 55 | t_nav_mj_watchdog="Watchdog" 56 | t_nav_mj_youtube="Youtube" 57 | -------------------------------------------------------------------------------- /files/usr/sbin/motion.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | plugin="motion" 4 | 5 | . /usr/sbin/common-plugins 6 | singleton 7 | 8 | STOP_FILE=/tmp/motion.stop 9 | UNSUPPORTED="hi3516cv100 hi3516av100" 10 | 11 | if [ -n "$(echo $UNSUPPORTED | sed -n "/\b$(ipcinfo --family)\b/p")" ]; then 12 | log "Motion detection is not supported on your camera!" 13 | quit_clean 1 14 | fi 15 | 16 | if [ "true" != "$motion_enabled" ]; then 17 | log "Motion detection is disabled in config!" 18 | quit_clean 3 19 | fi 20 | 21 | # throttle execution 22 | [ -z "$motion_throttle" ] && motion_throttle=1 23 | 24 | if [ -f "$STOP_FILE" ]; then 25 | if [ "$(date -r "$STOP_FILE" +%s)" -ge "$(( $(date +%s) - motion_throttle ))" ]; then 26 | log "Too soon for another trigger!" 27 | quit_clean 99 28 | fi 29 | fi 30 | 31 | # check number of the motions detected 32 | if [ "$1" -lt "$motion_sensitivity" ]; then 33 | log "Number of objects is below sensitivity threshold!" 34 | quit_clean 4 35 | fi 36 | 37 | touch "$STOP_FILE" 38 | 39 | # get a fresh snapshot 40 | snapshot4cron.sh -f 41 | if [ $? -ne 0 ]; then 42 | echo "Cannot get a snapshot" 43 | quit_clean 2 44 | fi 45 | 46 | # send alerts 47 | [ "true" = "$motion_send2email" ] && send2email.sh 48 | [ "true" = "$motion_send2ftp" ] && send2ftp.sh 49 | [ "true" = "$motion_send2mqtt" ] && send2mqtt.sh 50 | [ "true" = "$motion_send2ntfy" ] && send2ntfy.sh 51 | [ "true" = "$motion_send2telegram" ] && send2telegram.sh 52 | [ "true" = "$motion_send2webhook" ] && send2webhook.sh 53 | [ "true" = "$motion_send2yadisk" ] && send2yadisk.sh 54 | [ "true" = "$motion_playonspeaker" ] && playonspeaker.sh 55 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/file-manager.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | [ -n "$GET_cd" ] && dir=${GET_cd} 5 | # expand traversed path to a real directory name 6 | dir=$(cd ${dir:-/}; pwd) 7 | # no need for POSIX awkward double root 8 | dir=$(echo $dir | sed s#^//#/#) 9 | %> 10 | <% page_title="File Manager" %> 11 | <%in p/header.cgi %> 12 |

<%= $dir %>

13 | <% 14 | lsfiles=$(ls -al $dir) 15 | IFS=$'\n' 16 | for line in $lsfiles; do 17 | echo "
" 18 | # skip total line 19 | [ -n "$(echo $line | grep ^total)" ] && continue 20 | # skip . 21 | [ -n "$(echo $line | grep \\s\.$)" ] && continue 22 | 23 | name=${line##* }; line=${line% *} 24 | permissions=$(echo $line | awk '{print $1}') 25 | # hardlinks=$(echo $line | awk '{print $2}') 26 | # owner=$(echo $line | awk '{print $3}') 27 | # group=$(echo $line | awk '{print $4}') 28 | filesize=$(echo $line | awk '{print $5}') 29 | timestamp=$(echo $line | awk '{print $6,$7,$8}') 30 | 31 | path=$(echo "${dir}/${name}" | sed s#^//#/#) 32 | echo "
" 33 | if [ -d "${path}" ]; then 34 | echo "${name}" 35 | else 36 | echo "${name}" 37 | fi 38 | echo "
" 39 | echo "
${filesize}
" 40 | echo "
${permissions}
" 41 | echo "
${timestamp}
" 42 | echo "
" 43 | done 44 | IFS=$IFS_ORIG 45 | %> 46 | <%in p/footer.cgi %> 47 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/firmware-upload-parts.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl --upload-limit=5120 --upload-dir=/tmp 2 | <%in p/common.cgi %> 3 | <% 4 | sysupgrade_date=$(ls -lc --full-time /usr/sbin/sysupgrade | xargs | cut -d' ' -f6) 5 | sysupgrade_date=$(time_epoch "$sysupgrade_date") 6 | 7 | file="$POST_parts_file" 8 | file_name="$POST_parts_file_name" 9 | error="" 10 | 11 | case "$POST_parts_type" in 12 | kernel) 13 | maxsize=2097152 14 | magicnum="27051956" 15 | new_sysupgrade_date=$(time_epoch "2021-12-07") 16 | cmd="sysupgrade --kernel=/tmp/${file_name} --force_ver" 17 | ;; 18 | rootfs) 19 | maxsize=5242880 20 | magicnum="68737173" 21 | new_sysupgrade_date=$(time_epoch "2022-02-22") 22 | cmd="sysupgrade --rootfs=/tmp/${file_name} --force_ver --force_all" 23 | ;; 24 | *) 25 | error="Please select type of file and upload it again!" 26 | ;; 27 | esac 28 | 29 | [ -z "$file_name" ] && error="No file found! Did you forget to upload?" 30 | [ ! -r "$file" ] && error="Cannot read uploded file!" 31 | [ "$(stat -c%s $file)" -gt "$maxsize" ] && error="Uploded file is too large! $(stat -c%s $file) > ${maxsize}." 32 | [ "$magicnum" -ne "$(xxd -p -l 4 $file)" ] && error="File magic number does not match. Did you upload a wrong file? $(xxd -p -l 4 $file) != $magicnum" 33 | [ "$sysupgrade_date" -lt "$new_sysupgrade_date" ] && error="This feature requires the latest sysupgrade tool. Please upgrade firmware first." 34 | 35 | if [ -n "$error" ]; then 36 | redirect_back "danger" "$error" 37 | else %> 38 | <%in p/header.cgi %> 39 |
40 | <%
41 | xl "mv $file /tmp/${file_name}"
42 | $cmd
43 | %>
44 | 
45 | Go home 46 | <% fi %> 47 | <%in p/footer.cgi %> 48 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/p/footer.cgi: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | 16 | <% if [ "$debug" -gt 0 ]; then %> 17 | 18 |
19 |
20 |
Debug Info
21 |
22 | <% field_hidden "action" "init" %> 23 | <% button_submit "Re-read environment" %> 24 |
25 | 26 |
27 |
28 | 32 |
33 |
34 | <% ex "cat /tmp/sysinfo.txt" %> 35 |
36 |
37 | <% ex "env | sort" %> 38 |
39 |
40 |
41 |
42 | <% fi %> 43 | 44 | 45 | -------------------------------------------------------------------------------- /files/usr/sbin/ircut.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # set parameters from cli 4 | mode=$1 5 | pin1=$2 6 | pin2=$3 7 | 8 | # read IRCUT pins from bootloader environment 9 | ircut_pins=$(fw_printenv -n ircut_pins) 10 | [ -z "$pin1" ] && pin1=$(echo $ircut_pins | awk '{print $1}') 11 | [ -z "$pin2" ] && pin2=$(echo $ircut_pins | awk '{print $2}') 12 | 13 | # read IRCUT pins from majestic config, if empty 14 | [ -z "$pin1" ] && pin1=$(cli -g .nightMode.irCutPin1) 15 | [ -z "$pin2" ] && pin2=$(cli -g .nightMode.irCutPin2) 16 | 17 | if [ -z "$pin1" ]; then 18 | echo "Please define IRCUT pin" 19 | echo "fw_setenv ircut_pins " 20 | exit 1 21 | fi 22 | 23 | if [ -z "$pin2" ]; then 24 | echo "Unless you have a single GPIO IRCUT driver, please define the second pin:" 25 | echo "fw_setenv ircut_pins " 26 | fi 27 | 28 | MODE_FILE=/tmp/ircutmode.txt 29 | 30 | vendor=$(ipcinfo --vendor) 31 | 32 | ir_filter_off() { 33 | if [ -z "$pin2" ]; then 34 | gpio set "$pin1" 35 | else 36 | gpio set "$pin1" 37 | gpio clear "$pin2" 38 | usleep 10000 39 | gpio clear "$pin1" 40 | fi 41 | echo "IRCUT filter removed" 42 | } 43 | 44 | ir_filter_on() { 45 | if [ -z "$pin2" ]; then 46 | gpio clear "$pin1" 47 | else 48 | gpio clear "$pin1" 49 | gpio set "$pin2" 50 | usleep 10000 51 | gpio clear "$pin2" 52 | fi 53 | echo "IRCUT filter set" 54 | } 55 | 56 | case "$mode" in 57 | 0 | off | night) 58 | ir_filter_off 59 | echo 0 >$MODE_FILE 60 | ;; 61 | 1 | on | day) 62 | ir_filter_on 63 | echo 1 >$MODE_FILE 64 | ;; 65 | ~ | toggle) 66 | if [ "$(cat $MODE_FILE 2>/dev/null)" -eq 0 ]; then 67 | ir_filter_on 68 | echo 1 >$MODE_FILE 69 | else 70 | ir_filter_off 71 | echo 0 >$MODE_FILE 72 | fi 73 | ;; 74 | *) 75 | echo "Unknown mode ${mode}" 76 | exit 1 77 | ;; 78 | esac 79 | 80 | exit 0 -------------------------------------------------------------------------------- /files/var/www/cgi-bin/p/mac-address.cgi: -------------------------------------------------------------------------------- 1 |
2 |

This camera uses MAC address 00:00:23:34:45:66 which is a placeholder.

3 |

You need to replace it with the original MAC address from your stock firmware backup or generate a random valid MAC address.

4 |
5 | 6 |
7 |
8 |
9 |
10 |

Please note that the new MAC address will most likely give the camera a new IP address assigned by the DHCP server!

11 |
12 | 13 | 38 | -------------------------------------------------------------------------------- /files/usr/sbin/playonspeaker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | plugin="speaker" 4 | 5 | . /usr/sbin/common-plugins 6 | 7 | SUPPORTED="goke hisilicon ingenic sigmastar" 8 | if [ -z "$(echo $SUPPORTED | sed -n "/\b$(ipcinfo --vendor)\b/p")" ]; then 9 | log "Playing on speaker is not supported on your camera!" 10 | exit 1 11 | fi 12 | 13 | show_help() { 14 | echo "Usage: $0 [-u url] [-f file] [-v] [-h] 15 | -u url Audio URL. 16 | -f file Audio file. 17 | -v Verbose output. 18 | -h Show this help. 19 | " 20 | exit 0 21 | } 22 | 23 | # override config values with command line arguments 24 | while getopts f:u:vh flag; do 25 | case "$flag" in 26 | f) 27 | speaker_file=$OPTARG 28 | ;; 29 | u) 30 | speaker_url=$OPTARG 31 | ;; 32 | v) 33 | verbose="true" 34 | ;; 35 | h|*) 36 | show_help 37 | ;; 38 | esac 39 | done 40 | 41 | if [ "false" = "$speaker_enabled" ]; then 42 | log "Playing on speaker is disabled in config ${config_file}." 43 | exit 10 44 | fi 45 | 46 | if [ "false" = "$(yaml-cli -g .audio.enabled)" ]; then 47 | log "Playing on speaker is disabled in Majestic." 48 | exit 11 49 | fi 50 | 51 | # validate mandatory values 52 | if [ -z "$speaker_url" ]; then 53 | log "Speaker URL is not set" 54 | exit 12 55 | fi 56 | 57 | if [ -z "$speaker_file" ]; then 58 | log "Audio file is not set" 59 | exit 13 60 | fi 61 | 62 | if [ ! -f "$speaker_file" ]; then 63 | log "Audio file ${speaker_file} not found" 64 | exit 14 65 | fi 66 | 67 | command="curl --verbose" 68 | command="${command} --connect-timeout ${curl_timeout}" 69 | command="${command} --max-time ${curl_timeout} -X POST" 70 | command="${command} -T ${speaker_file}" 71 | command="${command} --url ${speaker_url}" 72 | 73 | log "$command" 74 | eval "$command" >>"$LOG_FILE" 2>&1 75 | 76 | [ "true" = "$verbose" ] && cat "$LOG_FILE" 77 | 78 | exit 0 79 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/admin.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | plugin="admin" 5 | page_title="Admin profile" 6 | params="name email telegram" 7 | 8 | tmp_file=/tmp/${plugin}.conf 9 | config_file="${ui_config_dir}/${plugin}.conf" 10 | [ ! -f "$config_file" ] && touch $config_file 11 | 12 | if [ "POST" = "$REQUEST_METHOD" ]; then 13 | # parse values from parameters 14 | for p in $params; do 15 | eval ${plugin}_${p}=\$POST_${plugin}_${p} 16 | sanitize "${plugin}_${p}" 17 | done; unset p 18 | 19 | [ -z "$admin_name" ] && set_error_flag "Admin name cannot be empty." 20 | [ -z "$admin_email" ] && set_error_flag "Admin email cannot be empty." 21 | # [ -z "$admin_telegram" ] && error="Admin telegram username cannot be empty." 22 | 23 | # add @ to Telegram username, if missed 24 | [ -n "$admin_telegram" ] && [ "${admin_telegram:0:1}" != "@" ] && admin_telegram="@$admin_telegram" 25 | 26 | if [ -z "$error" ]; then 27 | # create temp config file 28 | :>$tmp_file 29 | for p in $params; do 30 | echo "${plugin}_${p}=\"$(eval echo \$${plugin}_${p})\"" >>$tmp_file 31 | done; unset p 32 | mv $tmp_file $config_file 33 | 34 | update_caminfo 35 | redirect_back "success" "Admin profile updated." 36 | fi 37 | else 38 | include $config_file 39 | fi 40 | %> 41 | <%in p/header.cgi %> 42 | 43 |
44 |
45 |

Settings

46 |
47 | <% field_hidden "action" "update" %> 48 | <% field_text "admin_name" "Admin's full name" "will be used for sending emails" %> 49 | <% field_text "admin_email" "Admin's email address" %> 50 | <% field_text "admin_telegram" "Admin's nick on Telegram" %> 51 | <% button_submit %> 52 |
53 |
54 |
55 |

Config file

56 | <% ex "cat $config_file" %> 57 |
58 |
59 | 60 | <%in p/footer.cgi %> 61 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/plugin-vtun.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | plugin="vtun" 5 | plugin_name="Virtual Tunnel" 6 | page_title="Virtual tunnel" 7 | service_file=/etc/init.d/S98vtun 8 | conf_file=/tmp/vtund.conf 9 | env_host=$(fw_printenv -n vtun) 10 | 11 | if [ -n "$POST_action" ] && [ "$POST_action" = "reset" ]; then 12 | killall tunnel 13 | killall vtund 14 | rm $conf_file 15 | fw_setenv vtun 16 | redirect_to "$SCRIPT_NAME" "danger" "Tunnel is down" 17 | fi 18 | 19 | if [ -n "$POST_vtun_host" ]; then 20 | fw_setenv vtun "$POST_vtun_host" 21 | $service_file 22 | redirect_to "$SCRIPT_NAME" "success" "Tunnel is up" 23 | fi 24 | %> 25 | <%in p/header.cgi %> 26 | 27 |
28 |
29 | <% if [ -f "$conf_file" ]; then %> 30 |
31 |

Virtual Tunnel is up

32 |

Use the following credentials to set up remote access via active virtual tunnel:

33 |
34 |
Tunnel ID
35 |
<%= ${network_macaddr//:/} | tr a-z A-Z %>
36 |
Password
37 |
<% grep password $conf_file | xargs | cut -d' ' -f2 | sed 's/;$//' %> 38 |
39 |
40 | <% fi %> 41 | 42 |

Settings

43 |
44 | <% if [ ! -z "$env_host" ]; then %> 45 | <% field_hidden "action" "reset" %> 46 | <% button_submit "Reset configuration" %> 47 | <% else %> 48 | <% field_text "vtun_host" "Virtual Tunnel host" "Your Virtual Tunnel server address." %> 49 | <% button_submit %> 50 | <% fi %> 51 |
52 |
53 |
54 |

Configuration files

55 | <% 56 | [ ! -z "$env_host" ] && ex "echo $env_host" 57 | [ -f "$conf_file" ] && ex "cat $conf_file" 58 | ex "ps | grep tunnel" 59 | ex "ps | grep vtund" 60 | %> 61 |
62 |
63 | 64 | <%in p/footer.cgi %> 65 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/j/heartbeat.cgi: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # shellcheck disable=SC2039 3 | 4 | vendor=$(ipcinfo --vendor) 5 | 6 | soc_temp=$(ipcinfo --temp 2>/dev/null) 7 | if [ -n "$soc_temp" ]; then 8 | soc_temp="${soc_temp}°C" 9 | else 10 | soc_temp="" 11 | fi 12 | 13 | case "$vendor" in 14 | goke) 15 | daynight_value=$(wget -q -O - http://127.0.0.1/metrics/isp | awk '/^isp_again/ {print $2}') 16 | ;; 17 | hisilicon) 18 | daynight_value=$(wget -q -O - http://127.0.0.1/metrics/isp | awk '/^isp_again/ {print $2}') 19 | ;; 20 | ingenic) 21 | # For Ingenic we need to check whether the imp-control system is used or not 22 | # daynight_value=$(wget -q -O - http://127.0.0.1/metrics/isp | awk '/^isp_again/ {print $2}') 23 | daynight_value=$(imp-control.sh gettotalgain) 24 | ;; 25 | sigmastar) 26 | if fw_printenv wlandev | grep -q foscam; then 27 | echo 2 >/sys/devices/virtual/mstar/sar/channel 28 | daynight_value=$(cat /sys/devices/virtual/mstar/sar/value) 29 | else 30 | daynight_value=$(wget -q -O - http://127.0.0.1/metrics/isp | awk '/^isp_again/ {print $2}') 31 | fi 32 | ;; 33 | *) 34 | daynight_value=-1 35 | ;; 36 | esac 37 | 38 | mem_total=$(awk '/MemTotal/ {print $2}' /proc/meminfo) 39 | mem_free=$(awk '/MemFree/ {print $2}' /proc/meminfo) 40 | mem_used=$(( 100 - (mem_free / (mem_total / 100)) )) 41 | overlay_used=$(df | grep /overlay | xargs | cut -d' ' -f5) 42 | uptime=$(awk '{m=$1/60; h=m/60; printf "%sd %sh %sm %ss\n", int(h/24), int(h%24), int(m%60), int($1%60) }' /proc/uptime) 43 | payload=$(printf '{"soc_temp":"%s","time_now":"%s","timezone":"%s","mem_used":"%d","overlay_used":"%d","daynight_value":"%d","uptime":"%s"}' \ 44 | "$soc_temp" "$(date +%s)" "$(cat /etc/timezone)" "$mem_used" "${overlay_used//%/}" "$daynight_value" "$uptime") 45 | 46 | echo "HTTP/1.1 200 OK 47 | Content-type: application/json 48 | Pragma: no-cache 49 | Expires: $(TZ=GMT0 date +'%a, %d %b %Y %T %Z') 50 | Etag: \"$(cat /proc/sys/kernel/random/uuid)\" 51 | 52 | ${payload} 53 | " 54 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/plugin-playonspeaker.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | plugin="speaker" 5 | plugin_name="Play on speaker" 6 | page_title="Play on speaker" 7 | params="enabled url file" 8 | # volume srate codec outputEnabled speakerPin speakerPinInvert 9 | 10 | tmp_file=/tmp/${plugin}.conf 11 | 12 | config_file="${ui_config_dir}/${plugin}.conf" 13 | [ ! -f "$config_file" ] && touch $config_file 14 | 15 | if [ "POST" = "$REQUEST_METHOD" ]; then 16 | # parse values from parameters 17 | for p in $params; do 18 | eval ${plugin}_${p}=\$POST_${plugin}_${p} 19 | sanitize "${plugin}_${p}" 20 | done; unset p 21 | 22 | ### Validation 23 | if [ "true" = "$speaker_enabled" ]; then 24 | [ -z "$speaker_url" ] && set_error_flag "URL cannot be empty." 25 | fi 26 | 27 | if [ -z "$error" ]; then 28 | # create temp config file 29 | :>$tmp_file 30 | for p in $params; do 31 | echo "${plugin}_${p}=\"$(eval echo \$${plugin}_${p})\"" >>$tmp_file 32 | done; unset p 33 | mv $tmp_file $config_file 34 | 35 | update_caminfo 36 | redirect_back "success" "${plugin_name} config updated." 37 | fi 38 | 39 | redirect_to $SCRIPT_NAME 40 | else 41 | include $config_file 42 | 43 | # Default values 44 | [ -z "$speaker_url" ] && speaker_url="http://127.0.0.1/play_audio" 45 | fi 46 | %> 47 | <%in p/header.cgi %> 48 | 49 |
50 |
51 |
52 | <% field_switch "speaker_enabled" "Enable playing on speaker" %> 53 | <% field_text "speaker_url" "URL" %> 54 | <% field_text "speaker_file" "Audio file" "a-law PCM 8000 bps" %> 55 | <% button_submit %> 56 |
57 |
58 |
59 | <% ex "cat $config_file" %> 60 | <% button_webui_log %> 61 |
62 |
63 | 64 | <%in p/footer.cgi %> 65 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/plugin-send2webhook.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | plugin="webhook" 5 | plugin_name="Send to Webhook" 6 | page_title="Send to Webhook" 7 | params="enabled attach_snapshot use_heif url socks5_enabled" 8 | 9 | tmp_file=/tmp/${plugin}.conf 10 | 11 | config_file="${ui_config_dir}/${plugin}.conf" 12 | [ ! -f "$config_file" ] && touch $config_file 13 | 14 | if [ "POST" = "$REQUEST_METHOD" ]; then 15 | # parse values from parameters 16 | for p in $params; do 17 | eval ${plugin}_${p}=\$POST_${plugin}_${p} 18 | sanitize "${plugin}_${p}" 19 | done; unset p 20 | 21 | ### Validation 22 | if [ "true" = "$webhook_enabled" ]; then 23 | [ -z "$webhook_url" ] && set_error_flag "Webhook URL cannot be empty." 24 | fi 25 | 26 | if [ -z "$error" ]; then 27 | # create temp config file 28 | :>$tmp_file 29 | for p in $params; do 30 | echo "${plugin}_${p}=\"$(eval echo \$${plugin}_${p})\"" >>$tmp_file 31 | done; unset p 32 | mv $tmp_file $config_file 33 | 34 | update_caminfo 35 | redirect_back "success" "${plugin_name} config updated." 36 | fi 37 | 38 | redirect_to $SCRIPT_NAME 39 | else 40 | include $config_file 41 | 42 | [ -z "$webhook_attach_snapshot" ] && webhook_attach_snapshot="true" 43 | [ -z "$webhook_use_heif" ] && webhook_use_heif="false" 44 | fi 45 | %> 46 | <%in p/header.cgi %> 47 | 48 |
49 |
50 |
51 | <% field_switch "webhook_enabled" "Enable sending to webhook" %> 52 | <% field_text "webhook_url" "Webhook URL" %> 53 | <% field_switch "webhook_attach_snapshot" "Attach Snapshot" %> 54 | <% field_switch "webhook_use_heif" "Use HEIF format." "Requires H.265 codec on Video0." %> 55 | <% field_switch "webhook_socks5_enabled" "Use SOCKS5" "Configure SOCKS5 access" %> 56 |
57 |
58 | <% ex "cat $config_file" %> 59 | <% button_webui_log %> 60 |
61 |
62 | <% button_submit %> 63 |
64 | 65 | <%in p/footer.cgi %> 66 | -------------------------------------------------------------------------------- /files/usr/sbin/snapshot4cron.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | plugin="snapshot" 4 | 5 | . /usr/sbin/common-plugins 6 | singleton 7 | 8 | show_help() { 9 | echo "Usage: $0 [-v] [-h] [-f] [-r] 10 | -f Saving a new snapshot, no matter what. 11 | -r Use HEIF image format. 12 | -v Verbose output. 13 | -h Show this help. 14 | " 15 | exit 0 16 | } 17 | 18 | get_snapshot() { 19 | log "Trying to save a snapshot." 20 | LIMIT_ATTEMPTS=$(( LIMIT_ATTEMPTS - 1 )) 21 | 22 | command="curl --verbose" 23 | command="${command} --connect-timeout ${curl_timeout}" 24 | command="${command} --max-time ${curl_timeout}" 25 | command="${command} --silent --fail" 26 | command="${command} --url ${snapshot_url}?t=$(date +"%s") --output ${snapshot}" 27 | log "$command" 28 | if $command >>"$LOG_FILE"; then 29 | log "Snapshot saved to ${snapshot}." 30 | quit_clean 0 31 | fi 32 | 33 | if [ "$LIMIT_ATTEMPTS" -le 0 ]; then 34 | log "Maximum amount of retries reached." 35 | quit_clean 2 36 | else 37 | log "${LIMIT_ATTEMPTS} attempts left." 38 | sleep 1 39 | get_snapshot 40 | fi 41 | } 42 | 43 | SECONDS_TO_EXPIRE=120 44 | LIMIT_ATTEMPTS=5 45 | 46 | while getopts fhrv flag; do 47 | case "$flag" in 48 | f) 49 | force="true" 50 | ;; 51 | r) 52 | use_heif="true" 53 | ;; 54 | v) 55 | verbose="true" 56 | ;; 57 | h|*) 58 | show_help 59 | ;; 60 | esac 61 | done 62 | 63 | if [ "true" = "$use_heif" ] && [ "h265" = "$(yaml-cli -g .video0.codec)" ]; then 64 | snapshot="/tmp/snapshot4cron.heif" 65 | snapshot_url="http://127.0.0.1/image.heif" 66 | else 67 | snapshot="/tmp/snapshot4cron.jpg" 68 | snapshot_url="http://127.0.0.1/image.jpg" 69 | fi 70 | 71 | if [ "true" = "$force" ]; then 72 | log "Enforced run." 73 | get_snapshot 74 | elif [ ! -f "$snapshot" ]; then 75 | log "Snapshot not found." 76 | get_snapshot 77 | elif [ "$(date -r "$snapshot" +%s)" -le "$(( $(date +%s) - SECONDS_TO_EXPIRE ))" ]; then 78 | log "Snapshot is expired." 79 | rm $snapshot 80 | get_snapshot 81 | else 82 | log "Snapshot is up to date." 83 | sleep 2 84 | quit_clean 0 85 | fi 86 | 87 | [ "true" = "$verbose" ] && cat "$LOG_FILE" 88 | 89 | exit 0 90 | -------------------------------------------------------------------------------- /files/usr/sbin/send2webhook.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | plugin="webhook" 4 | 5 | . /usr/sbin/common-plugins 6 | 7 | show_help() { 8 | echo "Usage: $0 [-u url] [-v] [-h] 9 | -u url Webhook URL. 10 | -r Use HEIF image format. 11 | -v Verbose output. 12 | -h Show this help. 13 | " 14 | exit 0 15 | } 16 | 17 | # override config values with command line arguments 18 | while getopts u:rvh flag; do 19 | case "$flag" in 20 | r) 21 | webhook_use_heif="true" 22 | ;; 23 | u) 24 | webhook_url=$OPTARG 25 | ;; 26 | v) 27 | verbose="true" 28 | ;; 29 | h|*) 30 | show_help 31 | ;; 32 | esac 33 | done 34 | 35 | if [ "false" = "$webhook_enabled" ]; then 36 | log "Sending to webhook is disabled." 37 | exit 10 38 | fi 39 | 40 | # validate mandatory values 41 | if [ -z "$webhook_url" ]; then 42 | log "Webhook URL not found" 43 | exit 11 44 | fi 45 | 46 | command="curl --verbose" 47 | command="${command} --connect-timeout ${curl_timeout}" 48 | command="${command} --max-time ${curl_timeout} -X POST" 49 | 50 | if [ "true" = "$webhook_attach_snapshot" ]; then 51 | if [ "true" = "$webhoook_use_heif" ] && [ "h265" = "$(yaml-cli -g .video0.codec)" ]; then 52 | snapshot=/tmp/snapshot4cron.heif 53 | snapshot4cron.sh -r 54 | exitcode=$? 55 | else 56 | snapshot=/tmp/snapshot4cron.jpg 57 | snapshot4cron.sh 58 | exitcode=$? 59 | fi 60 | 61 | if [ $exitcode -ne 0 ]; then 62 | log "Cannot get a snapshot. Exit code: $exitcode" 63 | exit 2 64 | fi 65 | 66 | snapshot=/tmp/snapshot4cron.jpg 67 | if [ ! -f "$snapshot" ]; then 68 | log "Cannot find a snapshot" 69 | exit 3 70 | fi 71 | 72 | command="${command} -F 'image=@$snapshot'" 73 | fi 74 | 75 | # SOCK5 proxy, if needed 76 | if [ "true" = "$webhook_socks5_enabled" ]; then 77 | . /etc/webui/socks5.conf 78 | command="${command} --socks5-hostname ${socks5_host}:${socks5_port}" 79 | command="${command} --proxy-user ${socks5_login}:${socks5_password}" 80 | fi 81 | 82 | command="${command} --url ${webhook_url}" 83 | 84 | log "$command" 85 | eval "$command" >>"$LOG_FILE" 2>&1 86 | 87 | [ "true" = "$verbose" ] && cat "$LOG_FILE" 88 | 89 | exit 0 90 | -------------------------------------------------------------------------------- /wirebox/plugin-ipeye.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | plugin="ipeye" 5 | plugin_name="IPEYE" 6 | page_title="IPEYE Cloud" 7 | 8 | ipeye_camera_name=$network_hostname 9 | %> 10 | <%in p/header.cgi %> 11 | 12 |

Attention! This is only a proof of concept for the prospective subsystem of additional services. No real functionality here.

13 | 14 | <% if [ "$(yaml-cli -g .ipeye.enabled)" = "true" ]; then %> 15 |
16 |
17 |

Add a feed

18 |
19 | <% field_text "ipeye_username" "IPEYE cloud username" %> 20 | <% field_password "ipeye_password" "IPEYE cloud password" %> 21 | <% field_text "ipeye_camera_name" "Camera name" %> 22 | <% field_select "ipeye_rtsp_feed" "RTSP feed" "rtsp://${network_address}/stream=0,rtsp://${network_address}/stream=1" %> 23 | <% button_submit "Add camera to the cloud" %> 24 |
25 |
26 |
27 |

Image: IPEYE logo

28 |

www.ipeye.ru

29 |

Don't have an account? Sign-up here

30 |
31 |
32 | 33 | 43 | <% else %> 44 |
45 |

Cannot proceed because IPEYE support is disabled.

46 |

In order to add this camera to the cloud you have to enable IPEYE support first.

47 |
48 | <% field_hidden "mj_ipeye_enabled" "true" %> 49 | <% button_submit "Enable IPEYE Cloud protocol" "warning" %> 50 |
51 |
52 | <% fi %> 53 | 54 | <%in p/footer.cgi %> 55 | -------------------------------------------------------------------------------- /files/var/www/a/imp-config.js: -------------------------------------------------------------------------------- 1 | function callImp(command, value) { 2 | if (["flip", "mirror"].includes(command)) { 3 | command = "flip" 4 | value = 0 5 | if (document.querySelector('#flip').checked) value = (1 << 1) 6 | if (document.querySelector('#mirror').checked) value += 1 7 | } else if (["aiaec", "aihpf"].includes(command)) { 8 | value = (value === 1) ? "on" : "off" 9 | } else if (["ains"].includes(command)) { 10 | if (value === -1) value = "off" 11 | } else if (["setosdpos_x", "setosdpos_y"].includes(command)) { 12 | command = 'setosdpos' 13 | value = '1' + 14 | '+' + document.querySelector('#setosdpos_x').value + 15 | '+' + document.querySelector('#setosdpos_y').value + 16 | '+1087+75'; 17 | } else if (["whitebalance_mode", "whitebalance_rgain", "whitebalance_bgain"].includes(command)) { 18 | command = 'whitebalance' 19 | value = document.querySelector('#whitebalance_mode').value + 20 | '+' + document.querySelector('#whitebalance_rgain').value + 21 | '+' + document.querySelector('#whitebalance_bgain').value; 22 | } 23 | 24 | const xhr = new XMLHttpRequest(); 25 | xhr.open('GET', '/cgi-bin/j/imp.cgi?cmd=' + command + '&val=' + value); 26 | xhr.send(); 27 | 28 | document.querySelector('#savechanges').classList.remove('d-none'); 29 | } 30 | 31 | // numbers 32 | document.querySelectorAll('input[type=number]').forEach(el => { 33 | el.autocomplete = "off" 34 | el.addEventListener('change', ev => callImp(ev.target.name, ev.target.value)) 35 | }); 36 | 37 | // checkboxes 38 | document.querySelectorAll('input[type=checkbox]').forEach(el => { 39 | el.autocomplete = "off" 40 | el.addEventListener('change', ev => callImp(ev.target.name, ev.target.checked ? 1 : 0)) 41 | }); 42 | 43 | // radios 44 | document.querySelectorAll('input[type=radio]').forEach(el => { 45 | el.autocomplete = "off" 46 | el.addEventListener('change', ev => callImp(ev.target.name, ev.target.value)) 47 | }); 48 | 49 | // ranges 50 | document.querySelectorAll('input[type=range]').forEach(el => { 51 | el.addEventListener('change', ev => callImp(ev.target.id.replace('-range', ''), ev.target.value)) 52 | }); 53 | 54 | // selects 55 | document.querySelectorAll('select').forEach(el => { 56 | el.addEventListener('change', ev => callImp(ev.target.id, ev.target.value)) 57 | }); -------------------------------------------------------------------------------- /files/var/www/cgi-bin/plugin-send2yadisk.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | plugin="yadisk" 5 | plugin_name="Send to Yandex Disk" 6 | page_title="Send to Yandex Disk" 7 | params="enabled username password path use_heif socks5_enabled" 8 | 9 | tmp_file=/tmp/${plugin}.conf 10 | 11 | config_file="${ui_config_dir}/${plugin}.conf" 12 | [ ! -f "$config_file" ] && touch $config_file 13 | 14 | if [ "POST" = "$REQUEST_METHOD" ]; then 15 | # parse values from parameters 16 | for p in $params; do 17 | eval ${plugin}_${p}=\$POST_${plugin}_${p} 18 | sanitize "${plugin}_${p}" 19 | done; unset p 20 | 21 | ### Validation 22 | if [ "true" = "$email_enabled" ]; then 23 | [ -z "$yadisk_username" ] && set_error_flag "Yandex Disk username cannot be empty." 24 | [ -z "$yadisk_password" ] && set_error_flag "Yandex Disk password cannot be empty." 25 | fi 26 | 27 | if [ -z "$error" ]; then 28 | # create temp config file 29 | :>$tmp_file 30 | for p in $params; do 31 | echo "${plugin}_${p}=\"$(eval echo \$${plugin}_${p})\"" >>$tmp_file 32 | done; unset p 33 | mv $tmp_file $config_file 34 | 35 | update_caminfo 36 | redirect_back "success" "${plugin_name} config updated." 37 | fi 38 | 39 | redirect_to $SCRIPT_NAME 40 | else 41 | include $config_file 42 | 43 | # Default values 44 | [ -z "$yadisk_use_heif" ] && yadisk_use_heif="false" 45 | fi 46 | %> 47 | <%in p/header.cgi %> 48 | 49 |
50 |
51 |
52 | <% field_switch "yadisk_enabled" "Enable Yandex Disk bot" %> 53 | <% field_text "yadisk_username" "Yandex Disk username" %> 54 | <% field_password "yadisk_password" "Yandex Disk password" "A dedicated password for application. Create it here." %> 55 |
56 |
57 | <% field_text "yadisk_path" "Yandex Disk path" %> 58 | <% field_switch "yandex_use_heif" "Use HEIF format." "Requires H.265 codec on Video0." %> 59 | <% field_switch "yadisk_socks5_enabled" "Use SOCKS5" "Configure SOCKS5 access" %> 60 |
61 |
62 | <% ex "cat $config_file" %> 63 | <% button_webui_log %> 64 |
65 |
66 | <% button_submit %> 67 |
68 | 69 | <%in p/footer.cgi %> 70 | -------------------------------------------------------------------------------- /files/usr/sbin/daynight.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | plugin="daynight" 4 | 5 | . /usr/sbin/common-plugins 6 | singleton 7 | 8 | STOP_FILE=/tmp/daynight.stop 9 | MODE_FILE=/tmp/nightmode.txt 10 | 11 | vendor=$(ipcinfo --vendor) 12 | 13 | switch_to_day() { 14 | /usr/sbin/color.sh on 15 | /usr/sbin/irled.sh off 16 | /usr/sbin/ircut.sh on 17 | echo "Switched to day mode" 18 | echo "day" >$MODE_FILE 19 | } 20 | 21 | switch_to_night() { 22 | /usr/sbin/color.sh off 23 | /usr/sbin/irled.sh on 24 | /usr/sbin/ircut.sh off 25 | echo "Switched to night mode" 26 | echo "night" >$MODE_FILE 27 | } 28 | 29 | # determine luminance of the scene 30 | reversed=0 31 | case "$vendor" in 32 | goke) 33 | value=$(wget -q -O - http://127.0.0.1/metrics/isp | awk '/^isp_again/ {print $2}') 34 | ;; 35 | hisilicon) 36 | value=$(wget -q -O - http://127.0.0.1/metrics/isp | awk '/^isp_again/ {print $2}') 37 | ;; 38 | ingenic) 39 | # For Ingenic we need to check whether the imp-control system is used or not 40 | # value=$(wget -q -O - http://127.0.0.1/metrics/isp | awk '/^isp_again/ {print $2}') 41 | value=$(imp-control.sh gettotalgain) 42 | reversed=1 43 | ;; 44 | sigmastar) 45 | value=$(wget -q -O - http://127.0.0.1/metrics/isp | awk '/^isp_again/ {print $2}') 46 | # Below is an alternative way to obtain data from the hardware light sensor 47 | # GPIO78, PAD_SAR_GPIO0 -> channel 0 48 | # GPIO79, PAD_SAR_GPIO1 -> channel 1 49 | # GPIO80, PAD_SAR_GPIO2 -> channel 2 50 | # GPIO81, PAD_SAR_GPIO3 -> channel 3 51 | # echo 2 >/sys/devices/virtual/mstar/sar/channel 52 | # value=$(cat /sys/devices/virtual/mstar/sar/value) 53 | ;; 54 | *) 55 | echo "vendor is not supported" 56 | exit 1 57 | ;; 58 | esac 59 | 60 | case "$1" in 61 | night) 62 | switch_to_night 63 | ;; 64 | day) 65 | switch_to_day 66 | ;; 67 | ~ | toggle) 68 | if [ "$(cat $MODE_FILE 2>/dev/null)" = "day" ]; then 69 | switch_to_night 70 | else 71 | switch_to_day 72 | fi 73 | ;; 74 | *) 75 | day_night_max=$(fw_printenv -n day_night_max || echo 2400) 76 | day_night_min=$(fw_printenv -n day_night_min || echo 1200) 77 | 78 | echo "$day_night_min - $value - $day_night_max" 79 | 80 | if [ "$reversed" -eq 0 ]; then 81 | if [ "$value" -lt "$day_night_min" ]; then 82 | switch_to_day 83 | elif [ "$value" -gt "$day_night_max" ]; then 84 | switch_to_night 85 | fi 86 | else 87 | if [ "$value" -gt "$day_night_max" ]; then 88 | switch_to_night 89 | elif [ "$value" -lt "$day_night_min" ]; then 90 | switch_to_day 91 | fi 92 | fi 93 | ;; 94 | esac 95 | 96 | exit 0 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![OpenIPC logo][1] 2 | 3 | WebUI 4 | ====== 5 | 6 | WebUI is a web interface for [OpenIPC Firmware][2], 7 | and is available on port 80 of your camera. 8 | 9 | Web interface uses system credentials for access. Default username is _root_, 10 | and password is _12345_. You will be asked to change the password at the first login. 11 | Please note that this will also affect your login via ssh! 12 | 13 | ### Support 14 | 15 | OpenIPC offers two levels of support. 16 | 17 | - Free support through the community via [chat][3]. 18 | - Paid commercial support directly from the team of developers. 19 | 20 | Please consider subscribing for paid commercial support if you intend to use our 21 | product for business. As a paid customer, you will get technical support and 22 | maintenance services directly from our skilled team. Your bug reports and 23 | feature requests will get prioritized attention and expedited solutions. It's a 24 | win-win strategy for both parties, that would contribute to the stability your 25 | business, and help core developers to work on the project full-time. 26 | 27 | If you have any specific questions concerning our project, feel free to 28 | [contact us](mailto:dev@openipc.org). 29 | 30 | ### Participating and Contribution 31 | 32 | If you like what we do, and willing to intensify the development, please 33 | consider participating. 34 | 35 | You can improve existing code and send us patches. You can add new features 36 | missing from our code. 37 | 38 | Remember that you write for embedded linux thus please keep 39 | your code as small and optimized as possible. Avoid using extra libraries like 40 | jQuery, pure JavaScript is quite enough. Use valid HTML5 code. Avoid using 41 | deprecated tags and attributes. 42 | 43 | You can help us to write a better documentation, proofread and correct our 44 | websites. 45 | 46 | You can just donate some money to cover the cost of development and long-term 47 | maintaining of what we believe is going to be the most stable, flexible, and 48 | open IP Network Camera Framework for users like yourself. 49 | 50 | You can make a financial contribution to the project at [Open Collective][4]. 51 | 52 | Thank you. 53 | 54 |

Open Collective donate button

55 | 56 | [1]: https://openipc.org/assets/openipc-logo-black.svg 57 | [2]: https://github.com/openipc/firmware 58 | [3]: https://openipc.org/#telegram-chat-groups 59 | [4]: https://opencollective.com/openipc/contribute/backer-14335/checkout 60 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/console.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | page_title="Web console" 5 | cmd="$FORM_cmd" 6 | %> 7 | <%in p/header.cgi %> 8 | 9 |
10 |
11 |
/tmp#
12 | 13 |
14 |
15 |

16 | 
17 | 18 | 82 | <%in p/footer.cgi %> 83 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/j/imp.cgi: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # shellcheck disable=SC2039 3 | 4 | bad_request() { 5 | echo "HTTP/1.1 400 Bad Request" 6 | echo # separate headers from content 7 | echo "$1" 8 | exit 1 9 | } 10 | 11 | we_are_good() { 12 | echo "we are good" 13 | } 14 | 15 | unknown_command() { 16 | bad_request "unknown command" 17 | } 18 | 19 | unknown_value() { 20 | bad_request "unknown value" 21 | } 22 | 23 | urldecode() { 24 | local i="${*//+/ }" 25 | echo -e "${i//%/\\x}" 26 | } 27 | 28 | # parse parameters from query string 29 | [ -n "$QUERY_STRING" ] && eval $(echo "$QUERY_STRING" | sed "s/&/;/g") 30 | 31 | # quit if no command sent 32 | [ -z "$cmd" ] && bad_request "missing required parameter cmd" 33 | 34 | val="$(urldecode "$val")" 35 | 36 | # check lower limit 37 | case "$cmd" in 38 | aivol | aovol) 39 | [ "$val" -lt -30 ] && unknown_value 40 | ;; 41 | ains) 42 | [ "$val" -lt -1 ] && unknown_value 43 | ;; 44 | aecomp | aialc | aigain | aogain | brightness | contrast | defogstrength | dpc | drc | flicker | flip | hilight | hue | ispmode | saturation | setosdalpha | sharpness | sinter | temper) 45 | [ "$val" -lt -0 ] && unknown_value 46 | ;; 47 | *) ;; 48 | esac 49 | 50 | # check upper limit 51 | case "$cmd" in 52 | ispmode) 53 | [ "$val" -gt 1 ] && unknown_value 54 | ;; 55 | flicker) 56 | [ "$val" -gt 2 ] && unknown_value 57 | ;; 58 | ains | flip) 59 | [ "$val" -gt 3 ] && unknown_value 60 | ;; 61 | aialc) 62 | [ "$val" -gt 7 ] && unknown_value 63 | ;; 64 | hilight) 65 | [ "$val" -gt 10 ] && unknown_value 66 | ;; 67 | aigain | aogain) 68 | [ "$val" -gt 31 ] && unknown_value 69 | ;; 70 | aivol | aovol) 71 | [ "$val" -gt 120 ] && unknown_value 72 | ;; 73 | aecomp | brightness | contrast | defogstrength | dpc | drc | hue | saturation | setosdalpha | sharpness | sinter | temper) 74 | [ "$val" -gt 255 ] && unknown_value 75 | ;; 76 | *) ;; 77 | 78 | esac 79 | 80 | # check non-numeric values 81 | case "$cmd" in 82 | aihpf | aiaec | aiagc) 83 | case "$val" in 84 | on | off) 85 | we_are_good 86 | ;; 87 | *) 88 | unknown_value 89 | ;; 90 | esac 91 | ;; 92 | *) ;; 93 | esac 94 | 95 | # save to temp config 96 | sed -i "/^$cmd/d" /tmp/imp.conf 97 | echo "$cmd $val" >> /tmp/imp.conf 98 | 99 | command="/usr/sbin/imp-control.sh $cmd $val" 100 | result=$($command) 101 | 102 | echo "HTTP/1.1 200 OK 103 | Content-type: application/json 104 | Pragma: no-cache 105 | Expires: $(TZ=GMT0 date +'%a, %d %b %Y %T %Z') 106 | Etag: \"$(cat /proc/sys/kernel/random/uuid)\" 107 | 108 | {\"command\":\"${command}\",\"result\":\"${result}\"} 109 | " 110 | 111 | exit 0 112 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/firmware.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | page_title="Firmware" 5 | if [ -n "$network_gateway" ]; then 6 | case "$soc" in 7 | # Ingenic firmware does not correspond to SoC model 8 | t10*) 9 | url="https://github.com/OpenIPC/firmware/releases/download/latest/openipc.t10-lite-nor.tgz" 10 | ;; 11 | t20*) 12 | url="https://github.com/OpenIPC/firmware/releases/download/latest/openipc.t20-lite-nor.tgz" 13 | ;; 14 | t21*) 15 | url="https://github.com/OpenIPC/firmware/releases/download/latest/openipc.t21-lite-nor.tgz" 16 | ;; 17 | t31*) 18 | url="https://github.com/OpenIPC/firmware/releases/download/latest/openipc.t31-line-nor.tgz" 19 | ;; 20 | *) 21 | url="https://github.com/OpenIPC/firmware/releases/download/latest/openipc.${soc}-${flash_type}-${fw_variant}.tgz" 22 | ;; 23 | esac 24 | fw_date=$(date -D "%a, %d %b %Y %T GMT" +"2.4.%m.%d" --date "$(curl -ILs "$url" | grep Last-Modified | cut -d' ' -f2-)") 25 | else 26 | fw_date="- no access to GitHub -" 27 | fi 28 | fw_kernel="true" 29 | fw_rootfs="true" 30 | %> 31 | <%in p/header.cgi %> 32 | 33 |
34 |
35 |

Version

36 |
37 |
Installed
38 |
<%= $fw_version %>
39 |
On GitHub
40 |
<%= $fw_date %>
41 |
42 |
43 |
44 |

Upgrade

45 | <% if [ -n "$network_gateway" ]; then %> 46 |
47 | <% field_checkbox "fw_kernel" "Upgrade kernel." %> 48 | <% field_checkbox "fw_rootfs" "Upgrade rootfs." %> 49 | <% field_checkbox "fw_reset" "Reset firmware." %> 50 | <% field_checkbox "fw_noreboot" "Do not reboot after upgrade." %> 51 | <% field_checkbox "fw_enforce" "Install even if matches the existing version." %> 52 | <% button_submit "Install update from GitHub" "warning" %> 53 |
54 | <% else %> 55 |

Upgrading requires access to GitHub.

56 | <% fi %> 57 |
58 |
59 |

Upload Kernel & RootFS

60 |
61 | <% field_file "parts_file" "Binary file" %> 62 | <% field_select "parts_type" "Type of the binary file" "kernel,rootfs" %> 63 |

Destructive! Make sure you know what you are doing.

64 | <% button_submit "Upload file" "danger" %> 65 |
66 |
67 |
68 | 69 | <%in p/footer.cgi %> 70 | -------------------------------------------------------------------------------- /files/usr/sbin/send2ntfy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | plugin="ntfy" 4 | 5 | . /usr/sbin/common-plugins 6 | 7 | show_help() { 8 | echo "Usage: $0 [-s server_url] [-p priority] [-t title] [-b body] [-u user -l login] [-i bool] [-v] [-h] 9 | By default the saved values will be used unless specified 10 | OPT Name Description Saved Value 11 | -s server URL or IP of server (including port and topic) $ntfy_url 12 | -p priority (min low default high max) $ntfy_msg_priority 13 | -t title title for notification $ntfy_msg_title 14 | -b body notification body $ntfy_msg_body 15 | -u user $ntfy_username 16 | -l login $ntfy_password 17 | -i image attach image (true/false) $ntfy_attach_snapshot 18 | -v Verbose output. 19 | -h Show this help. 20 | " 21 | exit 0 22 | } 23 | 24 | # override config values with command line arguments 25 | while getopts s:p:t:b:u:l:i:vh flag; do 26 | case "$flag" in 27 | s) 28 | ntfy_url=$OPTARG 29 | ;; 30 | p) 31 | ntfy_msg_priority=$OPTARG 32 | ;; 33 | t) 34 | ntfy_msg_title=$OPTARG 35 | ;; 36 | u) 37 | ntfy_user=$OPTARG 38 | ;; 39 | l) 40 | ntfy_password=$OPTARG 41 | ;; 42 | b) 43 | ntfy_msg_body=$OPTARG 44 | ;; 45 | i) 46 | ntfy_attach_snapshot=$OPTARG 47 | ;; 48 | v) 49 | verbose="true" 50 | ;; 51 | h|*) 52 | show_help 53 | ;; 54 | esac 55 | done 56 | 57 | [ "false" = "$ntfy_enabled" ] && log "Sending to NTFY is disabled." && exit 10 58 | 59 | # validate mandatory values 60 | [ -z "$ntfy_url" ] && log "NTFY url not found in config" && exit 11 61 | 62 | # assign default values if not set 63 | [ -z "$ntfy_msg_body" ] && ntfy_msg_body="test message" 64 | 65 | command="curl --silent --verbose -XPOST" 66 | command="${command} --connect-timeout ${curl_timeout}" 67 | command="${command} --max-time ${curl_timeout}" 68 | 69 | if [ ! -z "$ntfy_username" ] && [ ! -z "$ntfy_password" ]; then # if login is specified add it 70 | command="${command} -u $ntfy_username:$ntfy_password" 71 | fi 72 | 73 | if [ ! -z "$ntfy_msg_title" ]; then # if title is specified add it 74 | command="${command} -H \"Title:$ntfy_msg_title\"" 75 | fi 76 | command="${command} -H \"X-Priority: $ntfy_msg_priority\"" 77 | command="${command} -H \"Message: ${ntfy_msg_body}\"" 78 | 79 | if [ "true" == "$ntfy_attach_snapshot" ]; then 80 | snapshot=/tmp/snapshot4cron.jpg 81 | snapshot4cron.sh 82 | command="${command} -T ${snapshot} -H \"Filename: snapshot.jpg\"" 83 | fi 84 | 85 | command="${command} ${ntfy_url}" 86 | 87 | log "$command" 88 | logcontent=$(eval "$command" 2>&1 ) 89 | echo "$logcontent" >>"$LOG_FILE" 90 | 91 | [ "true" = "$verbose" ] && echo "$command"\n"$logcontent" 92 | 93 | exit 0 94 | 95 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/ssh-keys.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | page_title="SSH key" 5 | 6 | function readKey() { 7 | [ -n "$(fw_printenv -n key_${1})" ] && alert "$(fw_printenv -n key_${1})" "secondary" "style=\"overflow-wrap: anywhere;\"" 8 | } 9 | 10 | function saveKey() { 11 | if [ -n "$(fw_printenv key_${1})" ]; then 12 | flash_save "danger" "${1} key already in backup. You need to delete it before saving a new key." 13 | else 14 | fw_setenv key_${1} $(dropbearconvert dropbear openssh /etc/dropbear/dropbear_${1}_host_key - 2>/dev/null | base64 | tr -d '\n') 15 | fi 16 | } 17 | 18 | function restoreKey() { 19 | if [ -z "$(fw_printenv key_${1})" ]; then 20 | flash_save "danger" "${1} key is not in the environment." 21 | else 22 | fw_printenv -n key_${1} | base64 -d | dropbearconvert openssh dropbear - /etc/dropbear/dropbear_${1}_host_key 23 | flash_save "success" "${1} key restored from environment." 24 | fi 25 | } 26 | 27 | function deleteKey() { 28 | if [ -z "$(fw_printenv key_${1})" ]; then 29 | flash_save "danger" "${1} Cannot find saved SSH key." 30 | else 31 | fw_setenv key_${1} 32 | flash_save "success" "${1} key deleted from environment." 33 | fi 34 | } 35 | 36 | case "$POST_action" in 37 | backup) 38 | saveKey "ed25519" 39 | redirect_back 40 | ;; 41 | restore) 42 | restoreKey "ed25519" 43 | redirect_back 44 | ;; 45 | delete) 46 | deleteKey "ed25519" 47 | redirect_back 48 | ;; 49 | *) 50 | %> 51 | <%in p/header.cgi %> 52 | 53 |
54 |
55 |

Key Backup

56 |
57 | <% field_hidden "action" "backup" %> 58 |

You can back up your existing SSH key into firmware environment and restore them later, after overlay wiping.

59 | <% button_submit "Backup SSH key" "danger" %> 60 |
61 |
62 |
63 |

Key Restore

64 |

Restoring previously saved SSH key from firmware environment will let you keep exsiting client's authentication.

65 |
66 | <% field_hidden "action" "restore" %> 67 | <% button_submit "Restore SSH key from backup" "danger" %> 68 |
69 |
70 |
71 |

Key Delete

72 |

You can delete saved key from firmware environment, e.g. to replace them with a new key.

73 |
74 | <% field_hidden "action" "delete" %> 75 | <% button_submit "Delete SSH key backup." "danger" %> 76 |
77 |
78 |
79 | 80 | <% readKey "ed25519" %> 81 | 82 | <%in p/footer.cgi %> 83 | <% esac %> 84 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/sensor.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl --upload-limit=200 --upload-dir=/tmp 2 | <%in p/common.cgi %> 3 | <% 4 | page_title="Sensor Driver and Config" 5 | 6 | if [ "POST" = "$REQUEST_METHOD" ]; then 7 | error="" 8 | 9 | if [ -n "$POST_sensor_driver_file" ]; then 10 | type="driver" 11 | file="$POST_sensor_driver_file" 12 | file_name="$POST_sensor_driver_file_name" 13 | file_path="$POST_sensor_driver_file_path" 14 | 15 | if [ -z "$file_name" ]; then 16 | error="No file found! Did you forget to upload?" 17 | elif [ "hisilicon" = "$soc_vendor" ] && [ "7f454c460101" != $(xxd -p -l 6 $file) ]; then 18 | error="File magic number does not match. Did you upload a wrong file?" 19 | elif [ -f "/usr/lib/sensors/${file_name}" ]; then 20 | error="File already exists!" 21 | fi 22 | fi 23 | 24 | if [ -n "$POST_sensor_config_file" ]; then 25 | type="config" 26 | file="$POST_sensor_config_file" 27 | file_name="$POST_sensor_config_file_name" 28 | file_path="$POST_sensor_config_file_path" 29 | 30 | if [ -z "$file_name" ]; then 31 | error="No file found! Did you forget to upload?" 32 | elif [ "hisilicon" = "$soc_vendor" ] && [ -n $(grep "\[sensor\]" $file) ]; then 33 | error="File magic number does not match. Did you upload a wrong file?" 34 | elif [ -f "/etc/sensors/${file_name}" ]; then 35 | error="File already exists!" 36 | fi 37 | fi 38 | 39 | if [ -z "$error" ]; then 40 | case "$type" in 41 | driver) 42 | mv "$file_path" "/usr/lib/sensors/${file_name}" 43 | redirect_to $SCRIPT_NAME "success" "Sensor driver uploaded." 44 | ;; 45 | config) 46 | mv "$file_path" "/etc/sensors/${file_name}" 47 | redirect_to $SCRIPT_NAME "success" "Sensor config uploaded." 48 | ;; 49 | esac 50 | fi 51 | fi 52 | %> 53 | <%in p/header.cgi %> 54 | 55 | <% [ -n "$error" ] && report_error "$error" %> 56 | 57 |
58 |
59 |

Sensor Drivers

60 | <% ex "ls /usr/lib/sensors/" %> 61 |
62 |
63 |

Upload sensor driver

64 |
65 | <% field_file "sensor_driver_file" "Sensor driver file" %> 66 | <% button_submit "Upload file" %> 67 |
68 |
69 |
70 |

Sensor Configs

71 | <% ex "ls /etc/sensors/" %> 72 |
73 |
74 |

Upload sensor config

75 |
76 | <% field_file "sensor_config_file" "Sensor config file" %> 77 | <% button_submit "Upload file" %> 78 |
79 |
80 |
81 | 82 | <%in p/footer.cgi %> 83 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/plugin-send2ntfy.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | plugin="ntfy" 5 | plugin_name="Send to NTFY" 6 | page_title="Send to NTFY" 7 | params="enabled attach_snapshot msg_title msg_body msg_priority url username password" 8 | 9 | tmp_file=/tmp/${plugin}.conf 10 | 11 | config_file="${ui_config_dir}/${plugin}.conf" 12 | [ ! -f "$config_file" ] && touch $config_file 13 | 14 | if [ "POST" = "$REQUEST_METHOD" ]; then 15 | # parse values from parameters 16 | for p in $params; do 17 | eval ${plugin}_${p}=\$POST_${plugin}_${p} 18 | sanitize "${plugin}_${p}" 19 | done; unset p 20 | 21 | ### Normalization 22 | msg_body="$(echo "$msg_body" | tr "\r?\n" " ")" 23 | 24 | ### Validation 25 | if [ "true" = "$ntfy_enabled" ]; then 26 | [ -z "$ntfy_url" ] && set_error_flag "Server URL cannot be empty." 27 | fi 28 | 29 | if [ -z "$error" ]; then 30 | # create temp config file 31 | :>$tmp_file 32 | for p in $params; do 33 | echo "${plugin}_${p}=\"$(eval echo \$${plugin}_${p})\"" >>$tmp_file 34 | done; unset p 35 | mv $tmp_file $config_file 36 | 37 | update_caminfo 38 | redirect_back "success" "${plugin_name} config updated." 39 | fi 40 | 41 | redirect_to $SCRIPT_NAME 42 | else 43 | include $config_file 44 | 45 | # Default values 46 | [ -z "$ntfy_attach_snapshot" ] && ntfy_attach_snapshot="true" 47 | [ -z "$ntfy_msg_title" ] && ntfy_msg_title="OpenIPC Notify" 48 | [ -z "$ntfy_msg_body" ] && ntfy_msg_body="Motion detected!\n Is it friend or foe?" 49 | [ -z "$ntfy_msg_priority" ] && ntfy_msg_priority="default" 50 | fi 51 | %> 52 | <%in p/header.cgi %> 53 | 54 |
55 | <% field_switch "ntfy_enabled" "Enable sending notification" %> 56 |
57 |
58 | <% field_text "ntfy_url" "NTFY server URL (IP or domain) and topic" "example: http://192.168.1.10:3000/test or https://ntfy.sh/test"%> 59 | <% field_select "ntfy_msg_priority" "Priority" "min low default high urgent" %> 60 | <% field_text "ntfy_username" "NTFY username" %> 61 | <% field_password "ntfy_password" "NTFY password" %> 62 |
63 |
64 | <% field_text "ntfy_msg_title" "Title" %> 65 | <% field_text "ntfy_msg_body" "Message text" "Use \n for line breaks" %> 66 | <% field_switch "ntfy_attach_snapshot" "Attach snapshot" %> 67 |
68 |
69 | <% ex "cat $config_file" %> 70 | <% button_webui_log %> 71 |
72 |
73 | <% button_submit %> 74 |
75 | 76 |

Test

77 |

Send a test message to check parameters.

78 | Test Now 79 | 80 | <%in p/footer.cgi %> 81 | 82 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/plugin-send2ftp.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | plugin="ftp" 5 | plugin_name="Send to FTP" 6 | page_title="Send to FTP" 7 | params="enabled host username password path port socks5_enabled template use_heif" 8 | 9 | tmp_file=/tmp/${plugin}.conf 10 | 11 | config_file="${ui_config_dir}/${plugin}.conf" 12 | [ ! -f "$config_file" ] && touch $config_file 13 | 14 | if [ "POST" = "$REQUEST_METHOD" ]; then 15 | # parse values from parameters 16 | for p in $params; do 17 | eval ${plugin}_${p}=\$POST_${plugin}_${p} 18 | sanitize "${plugin}_${p}" 19 | done; unset p 20 | 21 | ### Validation 22 | if [ "true" = "$ftp_enabled" ]; then 23 | [ "true" = "$ftp_send2ftp" ] && [ -z "$ftp_ftphost" ] && set_error_flag "FTP address cannot be empty." 24 | [ "true" = "$ftp_send2tftp" ] && [ -z "$ftp_tftphost" ] && set_error_flag "TFTP address cannot be empty." 25 | [ "true" = "$ftp_save4web" ] && [ -z "$ftp_localpath" ] && set_error_flag "Local path cannot be empty." 26 | fi 27 | [ -z "$ftp_template" ] && ftp_template="Screenshot-%Y%m%d-%H%M%S.jpg" 28 | 29 | if [ -z "$error" ]; then 30 | # create temp config file 31 | :>$tmp_file 32 | for p in $params; do 33 | echo "${plugin}_${p}=\"$(eval echo \$${plugin}_${p})\"" >>$tmp_file 34 | done; unset p 35 | mv $tmp_file $config_file 36 | 37 | update_caminfo 38 | redirect_back "success" "${plugin_name} config updated." 39 | fi 40 | 41 | redirect_to $SCRIPT_NAME 42 | else 43 | include $config_file 44 | 45 | # Default values 46 | [ -z "$ftp_port" ] && ftp_port="21" 47 | [ -z "$ftp_template" ] && ftp_template="${network_hostname}-%Y%m%d-%H%M%S.jpg" 48 | [ -z "$ftp_use_heif" ] && ftp_use_heif="false" 49 | fi 50 | %> 51 | <%in p/header.cgi %> 52 | 53 |
54 | <% field_switch "ftp_enabled" "Enable sending to FTP server" %> 55 |
56 |
57 | <% field_text "ftp_host" "FTP host" %> 58 | <% field_text "ftp_port" "FTP port" %> 59 | <% field_text "ftp_username" "FTP username" %> 60 | <% field_password "ftp_password" "FTP password" %> 61 |
62 |
63 | <% field_text "ftp_path" "FTP path" "relative to FTP root directory" %> 64 | <% field_text "ftp_template" "File template" "Supports strftime() format." %> 65 | <% field_switch "ftp_use_heif" "Use HEIF image format" "Requires H.265 codec on Video0." %> 66 | <% field_switch "ftp_socks5_enabled" "Use SOCKS5" "Configure SOCKS5 access" %> 67 |
68 |
69 | <% ex "cat $config_file" %> 70 | <% button_webui_log %> 71 |
72 |
73 | <% button_submit %> 74 |
75 | 76 | <%in p/footer.cgi %> 77 | -------------------------------------------------------------------------------- /files/usr/sbin/send2ftp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | plugin="ftp" 4 | 5 | . /usr/sbin/common-plugins 6 | 7 | show_help() { 8 | echo "Usage: $0 [-h host] [-p port] [-u username] [-P password] [-d path] [-f file] [-v] [-h] 9 | -s host FTP server FQDN or IP address. 10 | -p port FTP server port. 11 | -d path Directory on server, relative to FTP root. 12 | -f file File to upload. 13 | -u username FTP username. 14 | -P password FTP password. 15 | -r Use HEIF image format. 16 | -v Verbose output. 17 | -h Show this help. 18 | " 19 | exit 0 20 | } 21 | 22 | # override config values with command line arguments 23 | while getopts d:f:p:P:rs:u:vh flag; do 24 | case "$flag" in 25 | d) 26 | ftp_path=$OPTARG 27 | ;; 28 | f) 29 | ftp_file=$OPTARG 30 | ;; 31 | p) 32 | ftp_port=$OPTARG 33 | ;; 34 | P) 35 | ftp_password=$OPTARG 36 | ;; 37 | r) 38 | ftp_use_heif="true" 39 | ;; 40 | s) 41 | ftp_host=$OPTARG 42 | ;; 43 | u) 44 | ftp_username=$OPTARG 45 | ;; 46 | v) 47 | verbose="true" 48 | ;; 49 | h|*) 50 | show_help 51 | ;; 52 | esac 53 | done 54 | 55 | if [ "false" = "$ftp_enabled" ]; then 56 | log "Sending to FTP is disabled." 57 | exit 10 58 | fi 59 | 60 | # validate mandatory values 61 | if [ -z "$ftp_host" ]; then 62 | log "FTP host not found" 63 | exit 11 64 | fi 65 | 66 | if [ -z "$ftp_port" ]; then 67 | log "FTP port not found" 68 | exit 12 69 | fi 70 | 71 | if [ -z "$ftp_file" ]; then 72 | if [ "true" = "$ftp_use_heif" ] && [ "h265" = "$(yaml-cli -g .video0.codec)" ]; then 73 | snapshot=/tmp/snapshot4cron.heif 74 | snapshot4cron.sh -r 75 | else 76 | snapshot=/tmp/snapshot4cron.jpg 77 | snapshot4cron.sh 78 | fi 79 | # [ $? -ne 0 ] && echo "Cannot get a snapshot" && exit 2 80 | [ ! -f "$snapshot" ] && log "Cannot find a snapshot" && exit 3 81 | 82 | ftp_file=$snapshot 83 | fi 84 | 85 | command="curl --verbose" 86 | command="${command} --connect-timeout ${curl_timeout}" 87 | command="${command} --max-time ${curl_timeout}" 88 | 89 | # SOCK5 proxy, if needed 90 | if [ "true" = "$ftp_socks5_enabled" ]; then 91 | . /etc/webui/socks5.conf 92 | command="${command} --socks5-hostname ${socks5_host}:${socks5_port}" 93 | command="${command} --proxy-user ${socks5_login}:${socks5_password}" 94 | fi 95 | 96 | command="${command} --url ftp://" 97 | [ -n "$ftp_username" ] && [ -n "$ftp_password" ] && command="${command}${ftp_username}:${ftp_password}" 98 | command="${command}@${ftp_host}:${ftp_port}" 99 | [ -n "$ftp_path" ] && command="${command}/${ftp_path// /%20}" 100 | command="${command}/$(date +"$ftp_template")" 101 | command="${command} --upload-file ${ftp_file}" 102 | command="${command} --ftp-create-dirs" 103 | 104 | log "$command" 105 | eval "$command" >>"$LOG_FILE" 2>&1 106 | 107 | [ "true" = "$verbose" ] && cat "$LOG_FILE" 108 | 109 | exit 0 110 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/sdcard.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% page_title="SD Card" %> 4 | <%in p/header.cgi %> 5 | <% 6 | ls /dev/mmc* >/dev/null 2>&1 7 | if [ $? -ne 0 ]; then 8 | %> 9 |
10 |

Does this camera support SD Card?

11 |

Your camera does not have an SD Card slot or SD Card is not inserted.

12 |
13 | <% 14 | else 15 | card_device="/dev/mmcblk0" 16 | card_partition="${card_device}p1" 17 | mount_point="${card_partition//dev/mnt}" 18 | error="" 19 | _o="" 20 | 21 | if [ -n "$POST_doFormatCard" ]; then 22 | %> 23 |
24 |

ATTENTION! SD Card formatting takes time.

25 |

Please do not refresh this page. Wait until partition formatting is finished!

26 |
27 | <% 28 | if [ "$(grep $card_partition /etc/mtab)" ]; then 29 | _c="umount $card_partition" 30 | _o="${_o}\n${_c}\n$($_c 2>&1)" 31 | [ $? -ne 0 ] && error="Cannot unmount SD Card partition." 32 | fi 33 | 34 | if [ -z "$error" ]; then 35 | _c="echo -e 'o\nn\np\n1\n\n\nt\n6\nw'|fdisk $card_device" 36 | _o="${_o}\n${_c}\n$($_c 2>&1)" 37 | [ $? -ne 0 ] && error="Cannot create an SD Card partition." 38 | fi 39 | 40 | if [ -z "$error" ]; then 41 | _c="mkfs.vfat -v -n OpenIPC $card_partition" 42 | _o="${_o}\n${_c}\n$($_c 2>&1)" 43 | [ $? -ne 0 ] && error="Cannot format SD Card partition." 44 | fi 45 | 46 | if [ -z "$error" ] && [ ! -d "$mount_point" ]; then 47 | _c="mkdir -p $mount_point" 48 | _o="${_o}\n${_c}\n$($_c 2>&1)" 49 | [ $? -ne 0 ] && error="Cannot create SD Card mount point." 50 | fi 51 | 52 | if [ -z "$error" ]; then 53 | _c="mount $card_partition $mount_point" 54 | _o="${_o}\n${_c}\n$($_c 2>&1)" 55 | [ $? -ne 0 ] && error="Cannot re-mount SD Card partition." 56 | fi 57 | 58 | if [ -n "$error" ]; then 59 | report_error "$error" 60 | [ -n "$_c" ] && report_command_info "$_c" "$_o" 61 | else 62 | report_log "$_o" 63 | fi 64 | %> 65 | Go home 66 | <% 67 | else 68 | %> 69 |

SD card partitions

70 | <% 71 | partitions=$(df -h | grep 'dev/mmc') 72 | echo "
${partitions}
" 73 | 74 | if [ -n "$partitions" ]; then 75 | %> 76 |

Browse files on these partitions

77 |
78 | <% 79 | IFS=$'\n' 80 | for i in $partitions; do 81 | # _mount="${i##* }" 82 | _mount=$(echo $i | awk '{print $6}') 83 | echo "${_mount}" 84 | unset _mount 85 | done 86 | IFS=$IFS_ORIG 87 | unset _partitions 88 | %> 89 |
90 | <% 91 | fi 92 | %> 93 |

Format SD card

94 |
95 |

ATTENTION! Formatting will destroy all data on the SD Card.

96 |

Make sure you have a backup copy if you are going to use the data in the future.

97 |
98 | <% field_hidden "doFormatCard" "true" %> 99 | <% button_submit "Format SD Card" "danger" %> 100 |
101 |
102 | <% 103 | fi 104 | fi 105 | %> 106 | <%in p/footer.cgi %> 107 | -------------------------------------------------------------------------------- /files/var/www/a/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /files/usr/sbin/sendcoredump.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | config_file=/etc/coredump.conf 4 | admin_file=/etc/webui/admin.conf 5 | core_file=dump.core 6 | info_file=info.txt 7 | 8 | LOG_FILE=/root/coredump.log 9 | :>"$LOG_FILE" 10 | 11 | log() { 12 | local txt 13 | txt="$(date +"%F %T") [${PID}] ${1}" 14 | echo "$txt" >>"$LOG_FILE" 15 | [ "1" != "$quiet" ] && echo "$txt" 16 | } 17 | 18 | log "Majectic crashed" 19 | 20 | if [ ! -f "$config_file" ]; then 21 | log "Config file ${config_file} not found." 22 | exit 1 23 | fi 24 | . $config_file 25 | 26 | if [ ! -f "$admin_file" ]; then 27 | log "Admin config file ${admin_file} not found." 28 | exit 2 29 | fi 30 | . $admin_file 31 | 32 | if [ "true" != "$coredump_enabled" ]; then 33 | log "Core dump not enabled." 34 | exit 3 35 | fi 36 | 37 | log "Stopping watchdog" 38 | rmmod wdt 39 | log "done" 40 | 41 | cd /tmp || return 42 | 43 | log "Dumping core" 44 | cat /dev/stdin >"$core_file" 45 | log "done" 46 | 47 | bundle_name=$(ifconfig -a | grep HWaddr | sed s/.*HWaddr// | sed "s/[: ]//g" | uniq)-$(date +"%Y%m%d-%H%M%S").tgz 48 | 49 | # FIXME: can be read from /tmp/sysinfo.txt 50 | soc=$(ipcinfo --chip-name) 51 | family=$(ipcinfo --family) 52 | vendor=$(ipcinfo --vendor) 53 | sensor=$(ipcinfo --long-sensor) 54 | mac=$(ipcinfo --xm-mac) 55 | os=$(cat /etc/os-release) 56 | mj=$(majestic -v) 57 | 58 | :>"$info_file" 59 | echo " 60 | Date: $(TZ=GMT0 date) 61 | Name: ${admin_name} 62 | Email: ${admin_email} 63 | Telegram: ${admin_telegram} 64 | 65 | Hardware: 66 | --------- 67 | SoC: ${soc} 68 | Family: ${family} 69 | Vendor: ${vendor} 70 | Sensor: ${sensor} 71 | MAC: ${mac} 72 | 73 | Firmware: 74 | --------- 75 | ${os} 76 | MAJESTIC_VERSION=\"${mj}\" 77 | " >>$info_file 78 | 79 | cat /etc/majestic.yaml >majestic.yaml 80 | 81 | log "Creating bundle" 82 | tar c -h "$core_file" "$info_file" majestic.yaml | gzip >"$bundle_name" 83 | log "done" 84 | 85 | rm "$core_file" "$info_file" majestic.yaml 86 | 87 | if [ "true" = "$coredump_send2devs" ]; then 88 | log "Sending to S3 bucket" 89 | curl --silent --verbose "https://majdumps.s3.eu-north-1.amazonaws.com/${bundle_name}" \ 90 | --upload-file "$bundle_name" >>"$LOG_FILE" 91 | log "done" 92 | fi 93 | 94 | if [ "true" = "$coredump_send2tftp" ]; then 95 | log "Sending to TFTP server" 96 | tftp -p -l "$bundle_name" $coredump_tftphost >>"$LOG_FILE" 97 | log "done" 98 | fi 99 | 100 | if [ "true" = "$coredump_send2ftp" ]; then 101 | log "Sending to FTP server" 102 | curl --silent --verbose "ftp://${coredump_ftphost}/${coredump_ftppath}/" \ 103 | --upload-file "$bundle_name" --user "${coredump_ftpuser}:${coredump_ftppass}" \ 104 | --ftp-create-dirs >>"$LOG_FILE" 105 | log "done" 106 | fi 107 | 108 | if [ "true" = "$coredump_save4web" ]; then 109 | [ -z "$coredump_localpath" ] && coredump_localpath="/root" 110 | [ ! -d "$coredump_localpath" ] && mkdir -p "$coredump_localpath" 111 | log "Saving locally to ${coredump_localpath}/coredump.tgz" 112 | mv "$bundle_name" "${coredump_localpath}/coredump.tgz" 113 | log "done" 114 | else 115 | rm "$bundle_name" 116 | fi 117 | 118 | [ "1" = "$verbose" ] && cat "$LOG_FILE" 119 | 120 | log "All done. Rebooting..." 121 | umount -a -t nfs -l 122 | reboot -f 123 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/plugin-send2telegram.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | plugin="telegram" 5 | plugin_name="Send to Telegram" 6 | page_title="Send to Telegram" 7 | params="enabled token as_attachment as_photo use_heif channel caption socks5_enabled" 8 | 9 | tmp_file=/tmp/${plugin}.conf 10 | 11 | config_file="${ui_config_dir}/${plugin}.conf" 12 | [ ! -f "$config_file" ] && touch $config_file 13 | 14 | if [ "POST" = "$REQUEST_METHOD" ]; then 15 | # parse values from parameters 16 | for p in $params; do 17 | eval ${plugin}_${p}=\$POST_${plugin}_${p} 18 | sanitize "${plugin}_${p}" 19 | done; unset p 20 | 21 | ### Validation 22 | if [ "true" = "$telegram_enabled" ]; then 23 | [ -z "$telegram_token" ] && set_error_flag "Telegram token cannot be empty." 24 | [ -z "$telegram_channel" ] && set_error_flag "Telegram channel cannot be empty." 25 | fi 26 | 27 | if [ -z "$error" ]; then 28 | # create temp config file 29 | :>$tmp_file 30 | for p in $params; do 31 | echo "${plugin}_${p}=\"$(eval echo \$${plugin}_${p})\"" >>$tmp_file 32 | done; unset p 33 | mv $tmp_file $config_file 34 | 35 | update_caminfo 36 | redirect_back "success" "${plugin_name} config updated." 37 | fi 38 | 39 | redirect_to $SCRIPT_NAME 40 | else 41 | include $config_file 42 | 43 | # Default values 44 | [ -z "$telegram_caption" ] && telegram_caption="%hostname, %datetime" 45 | [ -z "$telegram_use_heif" ] && telegram_use_heif="false" 46 | fi 47 | %> 48 | <%in p/header.cgi %> 49 | 50 |
51 | <% field_switch "telegram_enabled" "Enable sending to Telegram" %> 52 |
53 |
54 | <% field_text "telegram_token" "Token" "Your Telegram Bot authentication token." %> 55 | <% field_text "telegram_channel" "Chat ID" "Numeric ID of the channel you want the bot to post images to." %> 56 | <% field_text "telegram_caption" "Photo caption" "Available variables: %hostname, %datetime, %soctemp." %> 57 |
58 |
59 | <% field_switch "telegram_as_attachment" "Send as attachment." %> 60 | <% field_switch "telegram_as_photo" "Send as photo." %> 61 | <% field_switch "telegram_use_heif" "Use HEIF format." "Requires H.265 codec on Video0." %> 62 | <% field_switch "telegram_socks5_enabled" "Use SOCKS5" "Configure SOCKS5 access" %> 63 |
64 |
65 | <% ex "cat $config_file" %> 66 | <% button_webui_log %> 67 |
68 |
69 | <% button_submit %> 70 |
71 | 72 | <% if [ -z "$telegram_token" ]; then %> 73 |
74 |
To create a channel for your Telegram bot:
75 |
    76 |
  1. Start a chat with @BotFather
  2. 77 |
  3. Enter /start to start a session.
  4. 78 |
  5. Enter /newbot to create a new bot.
  6. 79 |
  7. Give your bot channel a name, e.g. cool_cam_bot.
  8. 80 |
  9. Give your bot a username, e.g. CoolCamBot.
  10. 81 |
  11. Copy the token assigned to your new bot by the BotFather, and paste it to the form.
  12. 82 |
83 |
84 | <% fi %> 85 | 86 | <%in p/footer.cgi %> 87 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/plugin-send2openwall.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | plugin="openwall" 5 | plugin_name="Send to OpenWall" 6 | page_title="Send to OpenWall" 7 | params="caption enabled interval use_heif socks5_enabled" 8 | 9 | tmp_file=/tmp/${plugin}.conf 10 | 11 | config_file="${ui_config_dir}/${plugin}.conf" 12 | [ ! -f "$config_file" ] && touch $config_file 13 | 14 | if [ "POST" = "$REQUEST_METHOD" ]; then 15 | # parse values from parameters 16 | for p in $params; do 17 | eval ${plugin}_${p}=\$POST_${plugin}_${p} 18 | sanitize "${plugin}_${p}" 19 | done; unset p 20 | 21 | ### Validation 22 | if [ "true" = "$openwall_enabled" ]; then 23 | [ "$openwall_interval" -lt "15" ] && set_error_flag "Keep interval at 15 minutes or longer." 24 | fi 25 | 26 | if [ -z "$error" ]; then 27 | # create temp config file 28 | :>$tmp_file 29 | for p in $params; do 30 | echo "${plugin}_${p}=\"$(eval echo \$${plugin}_${p})\"" >>$tmp_file 31 | done; unset p 32 | mv $tmp_file $config_file 33 | 34 | # Disable/enable cron job 35 | cp /etc/crontabs/root /tmp/crontabs.tmp 36 | sed -i /send2openwall\.sh/d /tmp/crontabs.tmp 37 | [ "true" = "$openwall_enabled" ] && 38 | echo "*/${openwall_interval} * * * * /usr/sbin/send2openwall.sh" >>/tmp/crontabs.tmp 39 | mv /tmp/crontabs.tmp /etc/crontabs/root 40 | 41 | update_caminfo 42 | redirect_back "success" "${plugin_name} config updated." 43 | fi 44 | 45 | redirect_to $SCRIPT_NAME 46 | else 47 | include $config_file 48 | 49 | # Default values 50 | [ -z "$openwall_interval" ] && openwall_interval="15" 51 | [ -z "$openwall_use_heif" ] && openwall_use_heif="false" 52 | fi 53 | %> 54 | <%in p/header.cgi %> 55 | 56 |
57 |

This plugin allows you to share images from your OpenIPC camera on the Open Wall 58 | page of our website. But that's not all. It's a metrics agent with meaning. The images you share will allow us to determine 59 | the quality of images from different cameras. We also collect your MAC address, SoC model, sensor model, flash chip size, 60 | firmware version, and camera uptime to do this.

61 |
62 | 63 |
64 |
65 |
66 | <% field_switch "openwall_enabled" "Enable sending to OpenWall" %> 67 | <% field_select "openwall_interval" "Interval, minutes" "15,30,60" "Time between submissions. 15 minutes or longer." %> 68 | <% field_text "openwall_caption" "Caption" "Location or short description." %> 69 | <% field_switch "openwall_use_heif" "Use HEIF format." "Requires H.265 codec on Video0." %> 70 | <% field_switch "openwall_socks5_enabled" "Use SOCKS5" "Configure SOCKS5 access." %> 71 |
72 |
73 | <% ex "cat $config_file" %> 74 |
75 |
76 | <% ex "grep send2openwall /etc/crontabs/root" %> 77 | <% button_webui_log %> 78 |
79 |
80 | <% button_submit %> 81 |
82 | 83 | <% if [ "h265" != "$(yaml-cli -g .video0.codec)" ]; then %> 84 | 88 | <% fi %> 89 | 90 | <%in p/footer.cgi %> 91 | -------------------------------------------------------------------------------- /files/usr/sbin/send2yadisk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | plugin="yadisk" 4 | 5 | . /usr/sbin/common-plugins 6 | 7 | show_help() { 8 | echo "Usage: $0 [-u username] [-P password] [-v] [-h] 9 | -d path Directory on server. 10 | -f file File to upload. 11 | -u username Yandex Disk username. 12 | -P password Yandex Disk username. 13 | -r Use HEIF image format. 14 | -v Verbose output. 15 | -h Show this help. 16 | " 17 | exit 0 18 | } 19 | 20 | # override config values with command line arguments 21 | while getopts d:f:P:ru:vh flag; do 22 | case "$flag" in 23 | d) 24 | yadisk_path=$OPTARG 25 | ;; 26 | f) 27 | yadisk_file=$OPTARG 28 | ;; 29 | P) 30 | yadisk_password=$OPTARG 31 | ;; 32 | r) 33 | yadisk_use_heif="true" 34 | ;; 35 | u) 36 | yadisk_username=$OPTARG 37 | ;; 38 | v) 39 | verbose="true" 40 | ;; 41 | h|*) 42 | show_help 43 | ;; 44 | esac 45 | done 46 | 47 | if [ "false" = "$yadisk_enabled" ]; then 48 | log "Sending to Yandex Disk is disabled." 49 | exit 10 50 | fi 51 | 52 | if [ -z "$yadisk_file" ]; then 53 | if [ "true" = "$yadisk_use_heif" ] && [ "h265" = "$(yaml-cli -g .video0.codec)" ]; then 54 | snapshot=/tmp/snapshot4cron.heif 55 | snapshot4cron.sh -r 56 | else 57 | snapshot=/tmp/snapshot4cron.jpg 58 | snapshot4cron.sh 59 | fi 60 | 61 | if [ ! -f "$snapshot" ]; then 62 | log "Cannot find a snapshot" 63 | exit 3 64 | fi 65 | 66 | yadisk_file=$snapshot 67 | fi 68 | 69 | # validate mandatory values 70 | if [ -z "$yadisk_username" ]; then 71 | log "Yandex Disk username not found" 72 | exit 11 73 | fi 74 | 75 | if [ -z "$yadisk_password" ]; then 76 | log "Yandex Disk password not found" 77 | exit 12 78 | fi 79 | 80 | command="curl --verbose" 81 | command="${command} --connect-timeout ${curl_timeout}" 82 | command="${command} --max-time ${curl_timeout}" 83 | 84 | # Yandex Disk credentials 85 | command="${command} --user '${yadisk_username}:${yadisk_password}'" 86 | 87 | # SOCK5 proxy, if needed 88 | if [ "true" = "$yadisk_socks5_enabled" ]; then 89 | . /etc/webui/socks5.conf 90 | command="${command} --socks5-hostname ${socks5_host}:${socks5_port}" 91 | command="${command} --proxy-user ${socks5_login}:${socks5_password}" 92 | fi 93 | 94 | # create path to destination directory 95 | url="https://webdav.yandex.ru" 96 | subdirs="${yadisk_path// /_}" # prevent splitting by whitespaces 97 | subdirs="$(echo "$yadisk_path" | sed "s/[^\/]$/\//")" # add final slash if missing 98 | suburl="" 99 | while [ -n "$subdirs" ]; do 100 | subdir="${subdirs%%/*}" 101 | subdir="${subdir// /%20}" # convert each space into %20 102 | if [ -n "$subdir" ]; then 103 | suburl="${suburl}/${subdir}" 104 | _command="${command} --request MKCOL ${url}/${_url}/ " # disposable subcommand 105 | log "$_command" 106 | eval "$_command" >>"$LOG_FILE" 2>&1 107 | fi 108 | subdirs="${subdirs#*/}" 109 | done; unset _command 110 | 111 | # upload file 112 | url="${url}${_url}/$(TZ=$(cat /etc/TZ) date +"%G%m%d-%H%M%S").jpg" 113 | command="${command} --url ${url}" 114 | command="${command} --request PUT" 115 | command="${command} --upload-file ${snapshot}" 116 | 117 | log "$command" 118 | eval "$command" >>"$LOG_FILE" 2>&1 119 | 120 | [ "true" = "$verbose" ] && cat "$LOG_FILE" 121 | 122 | exit 0 123 | -------------------------------------------------------------------------------- /files/usr/sbin/send2mqtt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | plugin="mqtt" 4 | 5 | . /usr/sbin/common-plugins 6 | 7 | show_help() { 8 | echo "Usage: $0 [-t topic] [-m message] [-s] [-v] [-h] 9 | -t topic MQTT topic. 10 | -m message Message playload. 11 | -s Send a snapshot. 12 | -r Use HEIF image format. 13 | -v Verbose output. 14 | -h Show this help. 15 | " 16 | exit 0 17 | } 18 | 19 | # override config values with command line arguments 20 | while getopts m:rst:vh flag; do 21 | case "$flag" in 22 | m) 23 | mqtt_message=$OPTARG 24 | ;; 25 | r) 26 | mqtt_use_heif="true" 27 | ;; 28 | s) 29 | mqtt_send_snap="true" 30 | ;; 31 | t) 32 | mqtt_topic=$OPTARG 33 | ;; 34 | v) 35 | verbose="true" 36 | ;; 37 | h|*) 38 | show_help 39 | ;; 40 | esac 41 | done 42 | 43 | if [ "false" = "$mqtt_enabled" ]; then 44 | log "Sending to MQTT broker is disabled." 45 | exit 10 46 | fi 47 | 48 | # validate mandatory values 49 | if [ -z "$mqtt_host" ]; then 50 | log "MQTT broker host not found in config" 51 | exit 11 52 | fi 53 | 54 | if [ -z "$mqtt_port" ]; then 55 | log "MQTT broker port not found in config" 56 | exit 12 57 | fi 58 | 59 | if [ -z "$mqtt_topic" ]; then 60 | log "MQTT topic not found" 61 | exit 13 62 | fi 63 | 64 | if [ -z "$mqtt_message" ]; then 65 | log "MQTT message template not found" 66 | exit 14 67 | fi 68 | 69 | if [ "true" = "$mqtt_send_snap" ] && [ -z "$mqtt_snap_topic" ]; then 70 | log "MQTT topic for sending snapshot not found in config" 71 | exit 15 72 | fi 73 | 74 | # assign default values if not set 75 | [ -z "$mqtt_client_id" ] && mqtt_client_id="${network_hostname}" 76 | 77 | # parse strftime templates 78 | mqtt_message=$(date +"$mqtt_message") 79 | 80 | command="mosquitto_pub" 81 | command="${command} -h ${mqtt_host}" 82 | command="${command} -p ${mqtt_port}" 83 | command="${command} -i ${mqtt_client_id}" 84 | 85 | # MQTT credentials, if given 86 | [ -n "$mqtt_username" ] && command="${command} -u ${mqtt_username}" 87 | [ -n "$mqtt_password" ] && command="${command} -P ${mqtt_password}" 88 | 89 | # SOCK5 proxy, if needed 90 | if [ "true" = "$mqtt_socks5_enabled" ]; then 91 | . /etc/webui/socks5.conf 92 | socks_opts="--proxy socks5h://${socks5_login}:${socks5_password}@${socks5_host}:${socks5_port}" 93 | fi 94 | command="${command} ${socks_opts}" 95 | 96 | # send text message 97 | command1="${command} -t ${mqtt_topic} -m \"${mqtt_message}\"" 98 | log "$command1" 99 | eval "$command1" >>"$LOG_FILE" 2>&1 100 | 101 | # send file 102 | if [ "true" = "$mqtt_send_snap" ]; then 103 | if [ "true" = "$mqtt_use_heif" ] && [ "h265" = "$(yaml-cli -g .video0.codec)" ]; then 104 | snapshot=/tmp/snapshot4cron.heif 105 | snapshot4cron.sh -r 106 | else 107 | snapshot=/tmp/snapshot4cron.jpg 108 | snapshot4cron.sh 109 | fi 110 | exitcode=$? 111 | if [ $exitcode -ne 0 ]; then 112 | log "Cannot get a snapshot. Exit code: $exitcode" 113 | exit 2 114 | fi 115 | snapshot=/tmp/snapshot4cron.jpg 116 | if [ ! -f "$snapshot" ]; then 117 | log "Cannot find a snapshot" 118 | exit 3 119 | fi 120 | mqtt_file=$snapshot 121 | command2="${command} -t ${mqtt_snap_topic} -f \"${mqtt_file}\"" 122 | log "$command2" 123 | eval "$command2" >>"$LOG_FILE" 2>&1 124 | fi 125 | 126 | [ "true" = "$verbose" ] && cat "$LOG_FILE" 127 | 128 | exit 0 129 | -------------------------------------------------------------------------------- /files/usr/sbin/send2openwall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | plugin="openwall" 4 | 5 | . /usr/sbin/common-plugins 6 | 7 | show_help() { 8 | echo "Usage: $0 [-v] [-h] [-f] 9 | -f Force send. 10 | -r Use HEIF image format. 11 | -v Verbose output. 12 | -h Show this help. 13 | " 14 | exit 0 15 | } 16 | 17 | # default values 18 | flash_size=$(awk '{sum+=sprintf("0x%s", $2);} END{print sum/1048576;}' /proc/mtd) 19 | fw_variant=$(grep "BUILD_OPTION" /etc/os-release | cut -d= -f2 | tr -d /\"/); [ -z "$fw_variant" ] && fw_variant="lite" 20 | fw_version=$(grep "OPENIPC_VERSION" /etc/os-release | cut -d= -f2 | tr -d /\"/) 21 | 22 | network_hostname=$(hostname -s) 23 | network_default_interface=$(ip r | sed -nE '/default/s/.+dev (\w+).+?/\1/p' | head -n 1) 24 | [ -z "$network_default_interface" ] && network_default_interface=$(ip r | sed -nE 's/.+dev (\w+).+?/\1/p' | head -n 1) 25 | network_macaddr=$(cat "/sys/class/net/${network_default_interface}/address") 26 | 27 | sensor=$(ipcinfo --short-sensor) 28 | [ -z "$sensor" ] && sensor=$(fw_printenv -n sensor | cut -d_ -f1) 29 | 30 | #sensor_config=$(yaml-cli -g .isp.sensorConfig) 31 | soc=$(ipcinfo --chip-name) 32 | [ "sigmastar" = "$(ipcinfo -v)" ] && soc=$(fw_printenv -n soc) 33 | 34 | soc_temperature=$(ipcinfo --temp) 35 | streamer=$(basename "$(ipcinfo --streamer)") 36 | uptime=$(uptime | sed -r 's/^.+ up ([^,]+), .+$/\1/') 37 | 38 | # override config values with command line arguments 39 | while getopts frvh flag; do 40 | case "$flag" in 41 | f) 42 | force="true" 43 | ;; 44 | r) 45 | use_heif="true" 46 | ;; 47 | v) 48 | verbose="true" 49 | ;; 50 | h|*) 51 | show_help 52 | ;; 53 | esac 54 | done 55 | 56 | if [ "false" = "$openwall_enabled" ] && [ "true" != "$force" ]; then 57 | log "Sending to OpenIPC Wall is disabled." 58 | exit 10 59 | fi 60 | 61 | if [ "true" = "$openwall_use_heif" ] && [ "h265" = "$(yaml-cli -g .video0.codec)" ]; then 62 | snapshot=/tmp/snapshot4cron.heif 63 | snapshot4cron.sh -r 64 | else 65 | snapshot=/tmp/snapshot4cron.jpg 66 | snapshot4cron.sh 67 | # [ $? -ne 0 ] && echo "Cannot get a snapshot" && exit 2 68 | fi 69 | [ ! -f "$snapshot" ] && log "Cannot find a snapshot" && exit 3 70 | 71 | # validate mandatory values 72 | [ ! -f "$snapshot" ] && log "Snapshot file not found" && exit 11 73 | [ -z "$network_macaddr" ] && log "MAC address not found" && exit 12 74 | 75 | command="curl --verbose" 76 | command="${command} --connect-timeout ${curl_timeout}" 77 | command="${command} --max-time ${curl_timeout}" 78 | 79 | # SOCK5 proxy, if needed 80 | if [ "true" = "$openwall_socks5_enabled" ]; then 81 | . /etc/webui/socks5.conf 82 | command="${command} --socks5-hostname ${socks5_host}:${socks5_port}" 83 | command="${command} --proxy-user ${socks5_login}:${socks5_password}" 84 | fi 85 | 86 | command="${command} --url https://openipc.org/snapshots" 87 | command="${command} -F 'mac_address=${network_macaddr}'" 88 | command="${command} -F 'firmware=${fw_version}-${fw_variant}'" 89 | command="${command} -F 'flash_size=${flash_size}'" 90 | command="${command} -F 'hostname=${network_hostname}'" 91 | command="${command} -F 'caption=${openwall_caption}'" 92 | command="${command} -F 'sensor=${sensor}'" 93 | # command="${command} -F 'sensor_config=${sensor_config}'" 94 | command="${command} -F 'soc=${soc}'" 95 | command="${command} -F 'soc_temperature=${soc_temperature}'" 96 | command="${command} -F 'streamer=${streamer}'" 97 | command="${command} -F 'uptime=${uptime}'" 98 | command="${command} -F 'file=@${snapshot}'" 99 | 100 | log "$command" 101 | eval "$command" >>"$LOG_FILE" 2>&1 102 | 103 | [ "true" = "$verbose" ] && cat "$LOG_FILE" 104 | 105 | exit 0 106 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/p/icons.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <% 3 | svg_tag=" -------------------------------------------------------------------------------- /files/usr/sbin/send2email.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | plugin="email" 4 | 5 | . /usr/sbin/common-plugins 6 | 7 | show_help() { 8 | echo "Usage: $0 [-f address] [-t address] [-s subject] [-b body] [-v] [-h] 9 | -f address Sender's email address 10 | -t address Recipient's email address 11 | -r Use HEIF image format. 12 | -s subject Subject line. 13 | -b body Letter body. 14 | -v Verbose output. 15 | -h Show this help. 16 | " 17 | exit 0 18 | } 19 | 20 | # override config values with command line arguments 21 | while getopts b:f:rs:t:vh flag; do 22 | case "$flag" in 23 | b) 24 | email_body=$OPTARG 25 | ;; 26 | f) 27 | email_from_address=$OPTARG 28 | ;; 29 | r) 30 | email_use_heif="true" 31 | ;; 32 | s) 33 | email_subject=$OPTARG 34 | ;; 35 | t) 36 | email_to_address=$OPTARG 37 | ;; 38 | v) 39 | verbose="true" 40 | ;; 41 | h|*) 42 | show_help 43 | ;; 44 | esac 45 | done 46 | 47 | [ "false" = "$email_enabled" ] && log "Sending to email is disabled." && exit 10 48 | 49 | # validate mandatory values 50 | [ -z "$email_smtp_host" ] && log "SMTP host not found in config" && exit 11 51 | [ -z "$email_smtp_port" ] && log "SMTP port not found in config" && exit 12 52 | [ -z "$email_from_address" ] && log "Sender's email address not found" && exit 13 53 | [ -z "$email_to_address" ] && log "Recipient's email address not found" && exit 14 54 | 55 | # assign default values if not set 56 | #[ -z "$email_from_name" ] && email_from_name="OpenIPC Camera" 57 | #[ -z "$email_to_name" ] && email_to_name="OpenIPC Camera Admin" 58 | #[ -z "$email_subject" ] && email_subject="Snapshot from OpenIPC Camera" 59 | 60 | command="curl --silent --verbose" 61 | command="${command} --connect-timeout ${curl_timeout}" 62 | command="${command} --max-time ${curl_timeout}" 63 | 64 | if [ "true" = "$email_smtp_use_ssl" ]; then 65 | command="${command} --ssl --url smtps://" 66 | else 67 | command="${command} --url smtp://" 68 | fi 69 | command="${command}${email_smtp_host}:${email_smtp_port}" 70 | 71 | command="${command} --mail-from ${email_from_address}" 72 | command="${command} --mail-rcpt ${email_to_address}" 73 | command="${command} --user '${email_smtp_username}:${email_smtp_password}'" 74 | 75 | if [ "true" = "$email_attach_snapshot" ]; then 76 | if [ "true" = "$email_use_heif" ] && [ "h265" = "$(yaml-cli -g .video0.codec)" ]; then 77 | snapshot=/tmp/snapshot4cron.heif 78 | snapshot4cron.sh -r 79 | else 80 | snapshot=/tmp/snapshot4cron.jpg 81 | snapshot4cron.sh 82 | fi 83 | exitcode=$? 84 | [ $exitcode -ne 0 ] && log "Cannot get a snapshot. Exit code: $exitcode" && exit 2 85 | [ ! -f "$snapshot" ] && log "Cannot find a snapshot" && exit 3 86 | 87 | email_body="$(date -R)" 88 | command="${command} -H 'Subject: ${email_subject}'" 89 | command="${command} -H 'From: "${email_from_name}" <${email_from_address}>'" 90 | command="${command} -H 'To: "${email_to_name}" <${email_to_address}>'" 91 | command="${command} -F '=(;type=multipart/mixed'" 92 | command="${command} -F '=${email_body};type=text/plain'" 93 | command="${command} -F 'file=@${snapshot};type=image/jpeg;encoder=base64'" 94 | command="${command} -F '=)'" 95 | else 96 | email_file="/tmp/email.$$.txt" 97 | { 98 | echo "From: ${email_from_name} <${email_from_address}>" 99 | echo "To: ${email_to_name} <${email_to_address}>" 100 | echo "Subject: ${email_subject}" 101 | echo "Date: $(date -R)" 102 | echo "" 103 | echo "${email_body}" 104 | } >>$email_file 105 | command="${command} --upload-file ${email_file}" 106 | fi 107 | 108 | log "$command" 109 | eval "$command" >>"$LOG_FILE" 2>&1 110 | 111 | [ "true" = "$verbose" ] && cat "$LOG_FILE" 112 | 113 | [ -f ${email_file} ] && rm -f ${email_file} 114 | 115 | exit 0 116 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/config-light.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | page_title="Illumination" 5 | if [ "POST" = "$REQUEST_METHOD" ]; then 6 | error="" 7 | 8 | if [ -n "$POST_day_night_threshold" ]; then 9 | if [ -n "$POST_day_night_tolerance" ]; then 10 | day_night_max=$(( $POST_day_night_threshold + $POST_day_night_tolerance )) 11 | day_night_min=$(( $POST_day_night_threshold - $POST_day_night_tolerance )) 12 | fi 13 | fi 14 | 15 | [ -z "$day_night_min" ] && day_night_min=400 16 | [ -z "$day_night_max" ] && day_night_max=600 17 | 18 | # save values to env 19 | update_uboot_env ir850_led_pin $POST_ir850_led_pin 20 | update_uboot_env ir940_led_pin $POST_ir940_led_pin 21 | update_uboot_env white_led_pin $POST_white_led_pin 22 | update_uboot_env day_night_min $day_night_min 23 | update_uboot_env day_night_max $day_night_max 24 | update_uboot_env ircut_pins "$POST_ircut_pin1 $POST_ircut_pin2" 25 | 26 | # update Majestic config 27 | cli -s .nightMode.irCutPin1 $ircut_pin1 28 | cli -s .nightMode.irCutPin2 $ircut_pin2 29 | # take the first non-empty LED pin and use as backlight pin in majestic 30 | backlight_pin=$(echo "$POST_ir850_led_pin $POST_ir940_led_pin $POST_white_led_pin" | awk '{print $1}') 31 | cli -s .nightMode.backlightPin $backlight_pin 32 | fi 33 | 34 | # read data from env 35 | ir850_led_pin=$(fw_printenv -n ir850_led_pin) 36 | ir940_led_pin=$(fw_printenv -n ir940_led_pin) 37 | white_led_pin=$(fw_printenv -n white_led_pin) 38 | day_night_min=$(fw_printenv -n day_night_min) 39 | day_night_max=$(fw_printenv -n day_night_max) 40 | ircut_pins=$(fw_printenv -n ircut_pins) 41 | ircut_pin1=$(echo $ircut_pins | awk '{print $1}') 42 | ircut_pin2=$(echo $ircut_pins | awk '{print $2}') 43 | 44 | ircut_pin1=$(echo $ircut_pins | awk '{print $1}') 45 | ircut_pin2=$(echo $ircut_pins | awk '{print $2}') 46 | 47 | # reuse Majestic values is not found in env 48 | if [ -z "$ir850_led_pin" ]; then 49 | ir850_led_pin=$(cli -g .nightMode.backlightPin) 50 | fi 51 | 52 | if [ -z "$ircut_pins" ]; then 53 | ircut_pin1=$(cli -g .nightMode.irCutPin1) 54 | ircut_pin2=$(cli -g .nightMode.irCutPin2) 55 | ircut_pins="$ircut_pin1 $ircut_pin2" 56 | fi 57 | 58 | # calculate threshold and tolerance from min and max limits 59 | if [ -n "$day_night_min" ]; then 60 | if [ -n "$day_night_max" ]; then 61 | day_night_tolerance=$(( ($day_night_max - $day_night_min) / 2 )) 62 | day_night_threshold=$(( $day_night_min + $day_night_tolerance )) 63 | fi 64 | fi 65 | 66 | [ -z "$day_night_threshold" ] && day_night_threshold=500 67 | [ -z "$day_night_tolerance" ] && day_night_tolerance=100 68 | %> 69 | <%in p/header.cgi %> 70 | 71 |
72 |
73 |
74 | <% field_number "ir850_led_pin" "850 nm IR LED GPIO pin" %> 75 | <% field_number "ir940_led_pin" "940 nm IR LED GPIO pin" %> 76 | <% field_number "white_led_pin" "White Light LED GPIO pin" %> 77 | <% field_number "day_night_threshold" "Day/Night Trigger Threshold" %> 78 | <% field_number "day_night_tolerance" "Day/Night Tolerance" %> 79 | <% field_number "ircut_pin1" "IR CUT filter GPIO pin 1" %> 80 | <% field_number "ircut_pin2" "IR CUT filter GPIO pin 2" %> 81 |
82 |
83 |

Environment settings

84 |
 85 | ir850_led_pin: <%= $ir850_led_pin %>
 86 | ir940_led_pin: <%= $ir940_led_pin %>
 87 | white_led_pin: <%= $white_led_pin %>
 88 | day_night_min: <%= $day_night_min %>
 89 | day_night_max: <%= $day_night_max %>
 90 | ircut_pins: <%= $ircut_pins %>
 91 | 
92 |
93 |
94 | <% button_webui_log %> 95 |
96 |
97 | <% button_submit %> 98 | 99 | 100 | <%in p/footer.cgi %> 101 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/tools.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | page_title="Monitoring tools" 5 | tools_action="ping" 6 | tools_target="4.2.2.1" 7 | tools_interface="auto" 8 | tools_packet_size="56" # 56-1500 for ping, 38-32768 for trace 9 | tools_duration="5" 10 | %> 11 | <%in p/header.cgi %> 12 |
13 |
14 |

Ping Quality

15 |
16 | <% field_select "tools_action" "Action" "ping,trace" %> 17 | <% field_text "tools_target" "Target FQDN or IP address" %> 18 | <% field_select "tools_interface" "Network interface" "auto,${interfaces}" %> 19 | <% field_number "tools_packet_size" "Packet size" "56,65535,1" "Bytes" %> 20 | <% field_number "tools_duration" "Number of packets" "1,30,1" %> 21 | <% button_submit "Run" %> 22 |
23 |
24 |
25 |
26 |
27 |
28 | 29 | 101 | <%in p/footer.cgi %> 102 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/time-config.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | plugin="time" 5 | page_title="Time" 6 | 7 | config_file="${ui_config_dir}/${plugin}.conf" 8 | [ ! -f "$config_file" ] && touch $config_file 9 | 10 | seq=$(seq 0 3) 11 | 12 | if [ "POST" = "$REQUEST_METHOD" ]; then 13 | case "$POST_action" in 14 | reset) 15 | cp /rom/etc/ntp.conf /etc/ntp.conf 16 | redirect_back "success" "Configuration reset to firmware defaults." 17 | ;; 18 | update) 19 | # check for mandatory data 20 | [ -z "$POST_tz_name" ] && redirect_to $SCRIPT_NAME "warning" "Empty timezone name. Skipping." 21 | [ -z "$POST_tz_data" ] && redirect_to $SCRIPT_NAME "warning" "Empty timezone value. Skipping." 22 | 23 | [ "$tz_data" != "$POST_tz_data" ] && echo "${POST_tz_data}" >/etc/TZ 24 | [ "$tz_name" != "$POST_tz_name" ] && echo "${POST_tz_name}" >/etc/timezone 25 | 26 | tmp_file=/tmp/ntp.conf 27 | :>$tmp_file 28 | for i in $seq; do 29 | eval s="\$POST_ntp_server_${i}" 30 | [ -n "$s" ] && echo "server ${s} iburst" >>$tmp_file 31 | done 32 | unset i; unset s 33 | mv $tmp_file /etc/ntp.conf 34 | redirect_back "success" "Configuration updated." 35 | ;; 36 | esac 37 | 38 | update_caminfo 39 | redirect_to $SCRIPT_NAME "success" "Timezone updated." 40 | fi 41 | %> 42 | 43 | <%in p/header.cgi %> 44 | 45 |
46 | <% field_hidden "action" "update" %> 47 | 48 |
49 |
50 |

Time Zone

51 | 52 |

53 | 54 | 55 | Start typing the name of the nearest large city in the box above then select from available variants. 56 |

57 |

58 | 59 | 60 | Control string of the timezone selected above. Read-only field, only for monitoring. 61 |

62 |

Pick up timezone from browser

63 |
64 |
65 |

Time Synchronization

66 | <% 67 | for i in $seq; do 68 | x=$(expr $i + 1) 69 | eval ntp_server_${i}="$(sed -n ${x}p /etc/ntp.conf | cut -d' ' -f2)" 70 | field_text "ntp_server_${i}" "NTP Server $(( i + 1 ))" 71 | done; unset i; unset x 72 | %> 73 |
74 |
75 | <% ex "cat /etc/timezone" %> 76 | <% ex "cat /etc/TZ" %> 77 | <%# ex "echo \$TZ" %> 78 | <% ex "cat /etc/ntp.conf" %> 79 |

Sync time

80 |
81 |
82 | <% if [ "$(diff -q -- "/rom${config_file}" "$config_file")" ]; then %> 83 | 84 | <% field_hidden "action" "reset" %> 85 | <% button_submit "Restore firmware defaults" "danger" %> 86 | 87 | <% fi %> 88 |
89 |
90 | 91 | <% button_submit %> 92 | 93 | 94 | 95 | 108 | <%in p/footer.cgi %> 109 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/majestic-config-actions.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl --upload-limit=20 --upload-dir=/tmp 2 | <%in p/common.cgi %> 3 | <% 4 | config_file=/etc/majestic.yaml 5 | config_file_fw=/rom/etc/majestic.yaml 6 | 7 | if [ "POST" = "$REQUEST_METHOD" ]; then 8 | case "$POST_action" in 9 | backup) 10 | echo "HTTP/1.0 200 OK 11 | Date: $(time_http) 12 | Server: $SERVER_SOFTWARE 13 | Content-type: text/plain 14 | Content-Disposition: attachment; filename=majestic.yaml 15 | Content-Length: $(stat -c%s $config_file) 16 | Cache-Control: no-store 17 | Pragma: no-cache 18 | " 19 | cat $config_file 20 | ;; 21 | patch) 22 | patch_file=/tmp/majestic.patch 23 | diff $config_file_fw $config_file >$patch_file 24 | echo "HTTP/1.0 200 OK 25 | Date: $(time_http) 26 | Server: $SERVER_SOFTWARE 27 | Content-type: text/plain 28 | Content-Disposition: attachment; filename=majestic.$(time_epoch).patch 29 | Content-Length: $(stat -c%s $patch_file) 30 | Cache-Control: no-store 31 | Pragma: no-cache 32 | " 33 | cat $patch_file 34 | rm $patch_file 35 | ;; 36 | reset) 37 | /usr/sbin/sysreset.sh -m 38 | redirect_back 39 | ;; 40 | restore) 41 | magicnum="23206d616a6573746963" 42 | file="$POST_mj_restore_file" 43 | file_name="$POST_mj_restore_file_name" 44 | file_path="$POST_mj_restore_file_path" 45 | error="" 46 | [ -z "$file_name" ] && error="No file found! Did you forget to upload?" 47 | [ ! -r "$file" ] && error="Cannot read uploded file!" 48 | [ "$(stat -c%s $file)" -gt "$maxsize" ] && error="Uploded file is too large! $(stat -c%s $file) > ${maxsize}." 49 | #[ "$magicnum" -ne "$(xxd -p -l 10 $file)" ] && error="File magic number does not match. Did you upload a wrong file? $(xxd -p -l 10 $file) != $magicnum" 50 | if [ -z "$error" ]; then 51 | # yaml-cli -i $POST_upfile -o /tmp/majestic.yaml # FIXME: sanitize 52 | mv $file_path /etc/majestic.yaml 53 | redirect_to $SCRIPT_NAME 54 | fi 55 | ;; 56 | esac 57 | fi 58 | %> 59 | 60 | <% page_title="Majestic Maintenance" %> 61 | <%in p/header.cgi %> 62 | 63 |
64 |
65 |

Backup config

66 |

Download recent majestic.yaml to preserve changes you made to the default configuration.

67 |
68 | <% field_hidden "action" "backup" %> 69 | <% button_submit "Download config" %> 70 |
71 |
72 |
73 |

Restore config

74 |

Restore custom Majestic configuration from a saved copy of majestic.yaml file.

75 |
76 | <% field_hidden "action" "restore" %> 77 | <% field_file "mj_restore_file" "Backup file" "majestic.yaml" %> 78 | <% button_submit "Upload config" "warning" %> 79 |
80 |
81 |
82 |

Review difference

83 |

Compare recent majestic.yaml with the one supplied with the firmware.

84 | Review changes 85 |
86 |
87 |

Export as patch

88 |

Export changes made to majestic.yaml in a form of a patch file.

89 |
90 | <% field_hidden "action" "patch" %> 91 | <% button_submit "Download patch file" %> 92 |
93 |
94 |
95 |

Reset

96 | <% if [ "$(diff -q $config_file_fw $config_file)" ]; then %> 97 |

Reset Majestic configuration to its original state, as supplied with the firmware.

98 | <% button_mj_reset %> 99 | <% else %> 100 |

There is nothing to reset. Recent Majestic configuration does not differ from the one supplied with the firmware.

101 | <% fi %> 102 |
103 |
104 | 105 | <%in p/footer.cgi %> 106 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/users.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | plugin="users" 5 | plugin_name="Users" 6 | page_title="Users" 7 | 8 | conf_file=/tmp/passwd 9 | 10 | if [ -n "$POST_action" ] && [ "$POST_action" = "create" ]; then 11 | user_name="$POST_user_name" 12 | user_name_new="$POST_user_name_new" 13 | user_password="$POST_user_password" 14 | user_full_name="$POST_user_full_name" 15 | user_home="$POST_user_home" 16 | user_shell="$POST_user_shell" 17 | user_group="$POST_user_group" 18 | 19 | [ -n "$user_name_new" ] && user_name=$user_name_new 20 | 21 | [ -z "$user_name" ] && set_error_flag "User name cannot be empty." 22 | [ -z "$user_password" ] && set_error_flag "User password cannot be empty." 23 | 24 | if [ -z "$error" ]; then 25 | if grep -q "^${user_name}:" /etc/passwd; then 26 | flash_append "warning" "User ${user_name} found." 27 | else 28 | adduser ${user_name} -h ${user_home:-/dev/null} -s ${user_shell:-/bin/false} -G ${user_group:-users} -D -g "${user_full_name}" 29 | if [ $? -eq 0 ]; then 30 | flash_append "success" "User ${user_name} created." 31 | else 32 | set_error_flag "Failed to create user ${user_name}." 33 | fi 34 | fi 35 | 36 | if [ -z "$error" ]; then 37 | result=$(echo "${user_name}:${user_password}" | chpasswd 2>&1) 38 | if [ $? -eq 0 ]; then 39 | flash_append "success" "Password for ${user_name} set." 40 | redirect_back 41 | else 42 | flash_append "danger" "$result" 43 | fi 44 | fi 45 | fi 46 | fi 47 | 48 | users=$(awk 'BEGIN { FS = ":" } ; { if ($3 > 1000) print $1 }' /etc/passwd) 49 | 50 | [ -z "$user_home" ] && user_home="/dev/null" 51 | [ -z "$user_shell" ] && user_shell="/bin/false" 52 | [ -z "$user_group" ] && user_group="users" 53 | %> 54 | 55 | <%in p/header.cgi %> 56 | 57 |
58 |
59 |

Settings

60 |
61 | <% field_hidden "action" "create" %> 62 | <% field_select "user_name" "Username" "$users" "Create a new user" %> 63 | <% field_text "user_name_new" "Username" "Select an existing user" %> 64 | <% field_password "user_password" "Password" %> 65 | <% field_text "user_full_name" "Full name" %> 66 | <% field_text "user_home" "Home directory" %> 67 | <% field_text "user_shell" "Shell" %> 68 | <% field_text "user_group" "Group" %> 69 | <% button_submit %> 70 |
71 |
72 |
73 |

Configuration files

74 | <% ex "cat /etc/passwd" %> 75 | <% ex "cat /etc/shadow" %> 76 | <% ex "cat /etc/group" %> 77 |
78 |
79 | 80 | 115 | 116 | <%in p/footer.cgi %> 117 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/plugin-send2email.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | plugin="email" 5 | plugin_name="Send to email" 6 | page_title="Send to email" 7 | params="enabled attach_snapshot use_heif from_name from_address to_name to_address subject body smtp_host smtp_port smtp_username smtp_password smtp_use_ssl socks5_enabled" 8 | 9 | tmp_file=/tmp/${plugin}.conf 10 | 11 | config_file="${ui_config_dir}/${plugin}.conf" 12 | [ ! -f "$config_file" ] && touch $config_file 13 | 14 | if [ "POST" = "$REQUEST_METHOD" ]; then 15 | # parse values from parameters 16 | for p in $params; do 17 | eval ${plugin}_${p}=\$POST_${plugin}_${p} 18 | sanitize "${plugin}_${p}" 19 | done; unset p 20 | 21 | ### Normalization 22 | email_body="$(echo "$email_body" | tr "\r?\n" " ")" 23 | 24 | ### Validation 25 | if [ "true" = "$email_enabled" ]; then 26 | [ -z "$email_smtp_host" ] && set_error_flag "SMTP host cannot be empty." 27 | [ -z "$email_from_address" ] && set_error_flag "Sender email address cannot be empty." 28 | [ -z "$email_from_name" ] && set_error_flag "Sender name cannot be empty." 29 | [ -z "$email_to_address" ] && set_error_flag "Recipient email address cannot be empty." 30 | [ -z "$email_to_name" ] && set_error_flag "Recipient name cannot be empty." 31 | fi 32 | 33 | if [ -z "$error" ]; then 34 | # create temp config file 35 | :>$tmp_file 36 | for p in $params; do 37 | echo "${plugin}_${p}=\"$(eval echo \$${plugin}_${p})\"" >>$tmp_file 38 | done; unset p 39 | mv $tmp_file $config_file 40 | 41 | update_caminfo 42 | redirect_back "success" "${plugin_name} config updated." 43 | fi 44 | 45 | redirect_to $SCRIPT_NAME 46 | else 47 | include $config_file 48 | 49 | # Default values 50 | [ -z "$email_attach_snapshot" ] && email_attach_snapshot="true" 51 | [ -z "$email_use_heif" ] && email_use_heif="false" 52 | [ -z "$email_smtp_port" ] && email_smtp_port="25" 53 | [ -z "$email_from_name" ] && email_from_name="Camera ${network_hostname}" 54 | [ -z "$email_to_name" ] && email_to_name="Camera admin" 55 | # [ -z "$email_subject" ] && email_subject="Snapshot from ${network_hostname}" 56 | fi 57 | %> 58 | <%in p/header.cgi %> 59 | 60 |
61 | <% field_switch "email_enabled" "Enable sending to email" %> 62 |
63 |
64 | <% field_text "email_smtp_host" "SMTP host" %> 65 | <% field_text "email_smtp_port" "SMTP port" %> 66 | <% field_switch "email_smtp_use_ssl" "Use TLS/SSL" %> 67 | <% field_text "email_smtp_username" "SMTP username" %> 68 | <% field_password "email_smtp_password" "SMTP password" %> 69 | <% field_text "email_from_name" "Sender's name" %> 70 | <% field_text "email_from_address" "Sender's address" "Use an email address where bounce reports can be sent to." %> 71 |
72 |
73 | <% field_text "email_to_name" "Recipient's name" %> 74 | <% field_text "email_to_address" "Recipient's address" %> 75 | <% field_text "email_subject" "Email subject" %> 76 | <% field_textarea "email_body" "Email text" "Line breaks will be replaced with whitespace." %> 77 | <% field_switch "email_attach_snapshot" "Attach snapshot" %> 78 | <% field_switch "email_use_heif" "Use HEIF image format" "Requires H.265 codec on Video0." %> 79 | <% # field_switch "email_socks5_enabled" "Use SOCKS5" "Configure SOCKS5 access" %> 80 |
81 |
82 | <% ex "cat $config_file" %> 83 | <% button_webui_log %> 84 |
85 |
86 | <% button_submit %> 87 |
88 | 89 | 101 | 102 | <%in p/footer.cgi %> 103 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/webui-settings.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl --upload-limit=100 --upload-dir=/tmp 2 | <%in p/common.cgi %> 3 | <% 4 | plugin="webui" 5 | plugin_name="User interface settings" 6 | page_title="Web Interface Settings" 7 | 8 | tmp_file=/tmp/${plugin}.conf 9 | 10 | config_file="${ui_config_dir}/${plugin}.conf" 11 | [ ! -f "$config_file" ] && touch $config_file 12 | 13 | locale_file=/etc/webui/locale 14 | 15 | if [ "POST" = "$REQUEST_METHOD" ]; then 16 | case "$POST_action" in 17 | access) 18 | new_password="$POST_ui_password_new" 19 | [ -z "$new_password" ] && redirect_to $SCRIPT_NAME "danger" "Password cannot be empty!" 20 | 21 | echo "root:${new_password}" | chpasswd 22 | update_caminfo 23 | 24 | redirect_to "/" "success" "Password updated." 25 | ;; 26 | 27 | interface) 28 | params="level theme" 29 | for p in $params; do 30 | eval ${plugin}_${p}=\$POST_${plugin}_${p} 31 | sanitize "${plugin}_${p}" 32 | done; unset p 33 | 34 | [ -z "$webui_level" ] && webui_level="user" 35 | 36 | if [ -z "$error" ]; then 37 | # create temp config file 38 | :>$tmp_file 39 | for p in $params; do 40 | echo "${plugin}_${p}=\"$(eval echo \$${plugin}_${p})\"" >>$tmp_file 41 | done; unset p 42 | mv $tmp_file $config_file 43 | 44 | update_caminfo 45 | redirect_back "success" "${plugin_name} config updated." 46 | fi 47 | ;; 48 | 49 | locale) 50 | locale="$POST_ui_language" # set language. 51 | # upload new language and switch to it. overrides aboveset language. 52 | fn="$POST_ui_locale_file_name" 53 | if [ -n "$fn" ]; then 54 | mv "$POST_ui_locale_file_path" /var/www/lang/$fn 55 | locale=${fn%%.*} 56 | fi; unset fn 57 | # save new language settings and reload locale 58 | [ -z "$locale" ] && locale="en" 59 | echo "$locale" >$locale_file 60 | reload_locale 61 | update_caminfo 62 | redirect_to $SCRIPT_NAME "success" "Locale updated." 63 | ;; 64 | 65 | *) 66 | redirect_to $SCRIPT_NAME "danger" "UNKNOWN ACTION: $POST_action" 67 | ;; 68 | esac 69 | fi 70 | 71 | page_title="Web Interface Settings" 72 | 73 | # data for form fields 74 | ui_username="$USER" 75 | ui_language="$locale" 76 | 77 | ui_locales="en|English" 78 | if [ -d /var/www/lang/ ]; then 79 | for i in $(ls -1 /var/www/lang/); do 80 | code="$(basename $i)" 81 | code="${code%%.sh}" 82 | name="$(sed -n 2p $i|sed "s/ /_/g"|cut -d: -f2)" 83 | ui_locales="${ui_locales},${code}|${name}" 84 | done 85 | fi 86 | %> 87 | <%in p/header.cgi %> 88 | 89 |
90 |
91 |

Access

92 |
93 | <% field_hidden "action" "access" %> 94 |

95 | 96 | 97 |

98 | <% field_password "ui_password_new" "Password" %> 99 | <% button_submit %> 100 |
101 |
102 |
103 |

Interface Details

104 |
105 | <% field_hidden "action" "interface" %> 106 | <% field_select "webui_level" "Level" "user,expert" %> 107 | <% field_select "webui_theme" "Theme" "light,dark" %> 108 | <% button_submit %> 109 |
110 |
111 | 122 |
123 |

Configuration

124 | <% 125 | ex "cat /etc/httpd.conf" 126 | #ex "echo \$locale" 127 | #ex "cat $locale_file" 128 | #ex "ls /var/www/lang/" 129 | ex "cat $config_file" 130 | %> 131 |
132 |
133 | 134 | <%in p/footer.cgi %> 135 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/texteditor.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | if [ "POST" = "$REQUEST_METHOD" ]; then 5 | editor_file="$POST_editor_file" 6 | editor_text="$POST_editor_text" 7 | editor_backup="$POST_editor_backup" 8 | 9 | # strip carriage return (\u000D) characters 10 | editor_text=$(echo "$editor_text" | sed s/\\r//g) 11 | 12 | case "$POST_action" in 13 | restore) 14 | if [ ! -f "$editor_file" ]; then 15 | redirect_to "${SCRIPT_NAME}?f=${editor_file}" "danger" "File not found!" 16 | elif [ ! -f "$editor_file.backup" ]; then 17 | redirect_to "${SCRIPT_NAME}?f=${editor_file}" "danger" "File not found!" 18 | else 19 | mv "$editor_file.backup" "$editor_file" 20 | redirect_to "${SCRIPT_NAME}?f=${editor_file}" "success" "File restored from backup." 21 | fi 22 | ;; 23 | save) 24 | if [ -z "$editor_text" ]; then 25 | flash_save "warning" "Empty payload. File not saved!" 26 | else 27 | if [ -n "$editor_backup" ]; then 28 | cp "$editor_file" "${editor_file}.backup" 29 | else 30 | [ -f "${editor_file}.backup" ] && rm "${editor_file}.backup" 31 | fi 32 | echo "$editor_text" >"$editor_file" 33 | redirect_to "${SCRIPT_NAME}?f=${editor_file}" "success" "File saved." 34 | fi 35 | ;; 36 | *) 37 | flash_save "danger" "UNKNOWN ACTION: $POST_action" 38 | ;; 39 | esac 40 | else 41 | editor_file="$GET_f" 42 | if [ ! -f "$editor_file" ]; then 43 | flash_save "danger" "File not found!" 44 | elif [ -n "$editor_file" ]; then 45 | if [ "b" = "$( (cat -v "$editor_file" | grep -q "\^@") && echo "b" )" ]; then 46 | flash_save "danger" "Not a text file!" 47 | elif [ "$(stat -c%s $editor_file)" -gt "102400" ]; then 48 | flash_save "danger" "Uploded file is too large!" 49 | else 50 | editor_text="$(cat $editor_file | sed "s/&/\&/g;s//\>/g;s/\"/\"/g")" 51 | fi 52 | fi 53 | fi 54 | 55 | page_title="Text editor" 56 | %> 57 | <%in p/header.cgi %> 58 | 59 | 67 | 68 |
69 |
70 |
71 | <% field_hidden "action" "save" %> 72 | <% field_hidden "editor_file" "$editor_file" %> 73 | <% field_textedit "editor_text" "$editor_file" "File content" %> 74 |

75 | 76 | 77 |

78 | <% button_submit %> 79 |
80 |
81 | 82 |
83 | <% ex "cat -t $editor_file" %> 84 |
85 | 86 | <% if [ -f "${editor_file}.backup" ]; then %> 87 |
88 | <% ex "cat -t ${editor_file}.backup" %> 89 |
90 | <% field_hidden "action" "restore" %> 91 | <% field_hidden "editor_file" "$editor_file" %> 92 | <% button_submit "Restore" "danger" %> 93 |
94 |
95 |
96 |

Changes against previous version

97 | <% 98 | # it's ugly but shows non-printed characters (^M/^I) 99 | _n=$(basename $editor_file) 100 | cat -t $editor_file >/tmp/${_n}.np 101 | cat -t ${editor_file}.backup >/tmp/${_n}.backup.np 102 | pre "$(diff -s -d -U0 /tmp/${_n}.backup.np -L ${editor_file}.backup /tmp/${_n}.np -L $editor_file)" 103 | rm /tmp/${_n}.np /tmp/${_n}.backup.np 104 | unset _n 105 | %> 106 |
107 | <% fi %> 108 |
109 | 110 | <%in p/footer.cgi %> 111 | -------------------------------------------------------------------------------- /files/usr/sbin/send2telegram.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | plugin="telegram" 4 | 5 | . /usr/sbin/common-plugins 6 | 7 | show_help() { 8 | echo "Usage: $0 [-t token] [-c channel] [-m message] [-p photo] [-s] [-b] [-v] [-h] 9 | -t token Telegram bot token. See https://t.me/botfather if you need one. 10 | -c channel Telegram channel ID. See https://gist.github.com/mraaroncruz/e76d19f7d61d59419002db54030ebe35 11 | -m message Message text. 12 | -p photo Path to photo file. 13 | -i Send inline. 14 | -a Send as attachment. 15 | -r Use HEIF image format. 16 | -s Disable notification. 17 | -v Verbose output. 18 | -h Show this help. 19 | " 20 | exit 0 21 | } 22 | 23 | # default values 24 | telegram_disable_notification=false 25 | 26 | # override config values with command line arguments 27 | while getopts ac:im:p:rst:vh flag; do 28 | case "$flag" in 29 | a) 30 | telegram_as_attachment="true" 31 | ;; 32 | c) 33 | telegram_channel=$OPTARG 34 | ;; 35 | i) 36 | telegram_as_photo="true" 37 | ;; 38 | m) 39 | telegram_message=$OPTARG 40 | ;; 41 | p) 42 | telegram_photo=$OPTARG 43 | ;; 44 | r) 45 | teleram_use_heif="true" 46 | ;; 47 | s) 48 | telegram_disable_notification=true 49 | ;; 50 | t) 51 | telegram_token=$OPTARG 52 | ;; 53 | v) 54 | verbose="true" 55 | ;; 56 | h|*) 57 | show_help 58 | ;; 59 | esac 60 | done 61 | 62 | if [ "false" = "$telegram_enabled" ]; then 63 | log "Sending to Telegram is disabled." 64 | exit 10 65 | fi 66 | 67 | # validate mandatory values 68 | if [ -z "$telegram_token" ]; then 69 | log "Telegram token not found" 70 | exit 11 71 | fi 72 | 73 | if [ -z "$telegram_channel" ]; then 74 | log "Telegram channel not found" 75 | exit 12 76 | fi 77 | 78 | if [ -z "$telegram_message" ]; then 79 | telegram_message="$(echo "$telegram_caption" | sed "s/%hostname/$(hostname -s)/;s/%datetime/$(date +"%F %T")/;s/%soctemp/$(ipcinfo --temp)/")" 80 | 81 | if [ -z "$telegram_photo" ]; then 82 | if [ "true" = "$telegram_use_heif" ] && [ "h265" = "$(yaml-cli -g .video0.codec)" ]; then 83 | snapshot=/tmp/snapshot4cron.heif 84 | snapshot4cron.sh -r 85 | else 86 | snapshot=/tmp/snapshot4cron.jpg 87 | snapshot4cron.sh 88 | fi 89 | 90 | if [ ! -f "$snapshot" ]; then 91 | log "Cannot find a snapshot" 92 | exit 3 93 | fi 94 | 95 | telegram_photo=$snapshot 96 | fi 97 | fi 98 | 99 | command="curl --verbose" 100 | command="${command} --connect-timeout ${curl_timeout}" 101 | command="${command} --max-time ${curl_timeout}" 102 | 103 | # SOCK5 proxy, if needed 104 | if [ "true" = "$telegram_socks5_enabled" ]; then 105 | . /etc/webui/socks5.conf 106 | command="${command} --socks5-hostname ${socks5_host}:${socks5_port}" 107 | command="${command} --proxy-user ${socks5_login}:${socks5_password}" 108 | fi 109 | 110 | command="${command} -H 'Content-Type: multipart/form-data'" 111 | command="${command} -F 'chat_id=${telegram_channel}'" 112 | command="${command} -F 'disable_notification=${telegram_disable_notification}'" 113 | command="${command} --url https://api.telegram.org/bot${telegram_token}/" 114 | 115 | if [ -n "$telegram_photo" ]; then 116 | if [ "true" = "$telegram_as_attachment" ]; then 117 | command1="$command" 118 | command1="${command1}sendDocument" 119 | command1="${command1} -F 'document=@${telegram_photo}'" 120 | command1="${command1} -F 'caption=${telegram_message}'" 121 | log "$command1" 122 | eval "$command1" >>"$LOG_FILE" 2>&1 123 | elif [ "true" = "$telegram_as_photo" ]; then 124 | command2="$command" 125 | command2="${command2}sendPhoto" 126 | command2="${command2} -F 'photo=@${telegram_photo}'" 127 | command2="${command2} -F 'caption=${telegram_message}'" 128 | log "$command2" 129 | eval "$command2" >>"$LOG_FILE" 2>&1 130 | else 131 | command3="$command" 132 | command3="${command3}sendMessage" 133 | command3="${command3} -F 'text=Please select a method of sending (inline photo or file attachmnet).'" 134 | log "$command3" 135 | eval "$command3" >>"$LOG_FILE" 2>&1 136 | fi 137 | else 138 | command4="$command" 139 | command4="${command4}sendMessage" 140 | command4="${command4} -F 'text=${telegram_message}'" 141 | log "$command4" 142 | eval "$command4" >>"$LOG_FILE" 2>&1 143 | fi 144 | 145 | [ "true" = "$verbose" ] && cat "$LOG_FILE" 146 | 147 | exit 0 148 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/plugin-send2mqtt.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | plugin="mqtt" 5 | plugin_name="MQTT client" 6 | page_title="MQTT client" 7 | params="enabled host port client_id username password topic message send_snap snap_topic use_heif use_ssl" 8 | 9 | [ ! -f /usr/bin/mosquitto_pub ] && redirect_to "/" "danger" "MQTT client is not a part of your firmware." 10 | 11 | tmp_file=/tmp/${plugin}.conf 12 | 13 | config_file="${ui_config_dir}/${plugin}.conf" 14 | [ ! -f "$config_file" ] && touch $config_file 15 | 16 | if [ "POST" = "$REQUEST_METHOD" ]; then 17 | # parse values from parameters 18 | for p in $params; do 19 | eval ${plugin}_${p}=\$POST_${plugin}_${p} 20 | sanitize "${plugin}_${p}" 21 | done; unset p 22 | 23 | ### Validation 24 | if [ "true" = "$mqtt_enabled" ]; then 25 | [ -z "$mqtt_host" ] && set_error_flag "MQTT broker host cannot be empty." 26 | [ -z "$mqtt_port" ] && set_error_flag "MQTT port cannot be empty." 27 | # [ -z "$mqtt_username" ] && set_error_flag "MQTT username cannot be empty." 28 | # [ -z "$mqtt_password" ] && set_error_flag "MQTT password cannot be empty." 29 | [ -z "$mqtt_topic" ] && flash_append "danger" "MQTT topic cannot be empty." 30 | [ -z "$mqtt_message" ] && flash_append "danger" "MQTT message cannot be empty." 31 | fi 32 | 33 | if [ "${mqtt_topic:0:1}" = "/" ] || [ "${mqtt_snap_topic:0:1}" = "/" ]; then 34 | set_error_flag "MQTT topic should not start with a slash." 35 | fi 36 | 37 | if [ "$mqtt_topic" != "${mqtt_topic// /}" ] || [ "$mqtt_snap_topic" != "${mqtt_snap_topic// /}" ]; then 38 | set_error_flag "MQTT topic should not contain spaces." 39 | fi 40 | 41 | if [ -n "$(echo $mqtt_topic | sed -r -n /[^a-zA-Z0-9/]/p)" ] || [ -n "$(echo $mqtt_snap_topic | sed -r -n /[^a-zA-Z0-9/]/p)" ]; then 42 | set_error_flag "MQTT topic should not include non-ASCII characters." 43 | fi 44 | 45 | if [ "true" = "$mqtt_send_snap" ] && [ -z "$mqtt_snap_topic" ]; then 46 | set_error_flag "MQTT topic for snapshot should not be empty." 47 | fi 48 | 49 | if [ -z "$error" ]; then 50 | # create temp config file 51 | :>$tmp_file 52 | for p in $params; do 53 | echo "${plugin}_${p}=\"$(eval echo \$${plugin}_${p})\"" >>$tmp_file 54 | done; unset p 55 | mv $tmp_file $config_file 56 | 57 | update_caminfo 58 | redirect_back "success" "${plugin_name} config updated." 59 | fi 60 | 61 | redirect_to $SCRIPT_NAME 62 | else 63 | include $config_file 64 | 65 | # Default values 66 | [ -z "$mqtt_client_id" ] && mqtt_client_id="${network_macaddr//:/}" 67 | [ -z "$mqtt_port" ] && mqtt_port="1883" 68 | [ -z "$mqtt_topic" ] && mqtt_topic="openipc/${mqtt_client_id}" 69 | [ -z "$mqtt_message" ] && mqtt_message="" 70 | [ -z "$mqtt_use_heif" ] && mqtt_use_heif="false" 71 | fi 72 | %> 73 | <%in p/header.cgi %> 74 | 75 |
76 | <% field_switch "mqtt_enabled" "Enable MQTT client" %> 77 |
78 |
79 | <% field_text "mqtt_host" "MQTT broker host" %> 80 | <% field_switch "mqtt_use_ssl" "Use SSL" %> 81 | <% field_text "mqtt_port" "MQTT broker port" %> 82 | <% field_text "mqtt_client_id" "MQTT client ID" %> 83 | <% field_text "mqtt_username" "MQTT broker username" %> 84 | <% field_password "mqtt_password" "MQTT broker password" %> 85 |
86 |
87 | <% field_text "mqtt_topic" "MQTT topic" %> 88 | <% field_textarea "mqtt_message" "MQTT message" "Supports strftime() format." %> 89 | <% field_switch "mqtt_send_snap" "Send a snapshot" %> 90 | <% field_switch "mqtt_use_heif" "Use HEIF image format" "Requires H.265 codec on Video0." %> 91 | <% field_text "mqtt_snap_topic" "MQTT topic to send the snapshot to" %> 92 | <% field_switch "mqtt_socks5_enabled" "Use SOCKS5" "Configure SOCKS5 access" %> 93 |
94 |
95 | <% ex "cat $config_file" %> 96 | <% button_webui_log %> 97 |
98 |
99 | <% button_submit %> 100 |
101 | 102 | 113 | 114 | <%in p/footer.cgi %> 115 | -------------------------------------------------------------------------------- /files/usr/sbin/updatemajestic.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | . /usr/sbin/common 4 | 5 | clean_quit() { 6 | [ -f "$mj_meta_file" ] && rm "$mj_meta_file" 7 | exit "$1" 8 | } 9 | 10 | print_usage() { 11 | echo "Usage: $0 [-v] [-f] [-h] 12 | -f Install even if same version. 13 | -v Verbose output. 14 | -h Show this help. 15 | " 16 | exit 0 17 | } 18 | 19 | # default 20 | curl_opts="--silent --insecure --location --fail" # --write-out %{http_code} 21 | 22 | # override config values with command line arguments 23 | while getopts b:fvh flag; do 24 | case "$flag" in 25 | b) 26 | branch=$OPTARG 27 | ;; 28 | f) 29 | enforce=1 30 | ;; 31 | v) 32 | verbose=1 33 | curl_opts="${curl_opts} --verbose" 34 | v_opts="-v" 35 | ;; 36 | h|*) 37 | print_usage 38 | ;; 39 | esac 40 | done 41 | 42 | check_flash_memory_size() { 43 | if [ "$(awk '{sum+=sprintf("0x%s", $2);} END{print sum/1048576;}' /proc/mtd)" -lt 16 ]; then 44 | echo_c 31 "Flash memory is smaller than 16MB. Aborting." 45 | exit 1 46 | fi 47 | } 48 | 49 | get_system_info() { 50 | # system 51 | fw_build=$(grep "GITHUB_VERSION" /etc/os-release | cut -d= -f2 | tr -d /\"/) 52 | fw_variant=$(grep "BUILD_OPTION" /etc/os-release | cut -d= -f2 | tr -d /\"/) 53 | fw_version=$(grep "OPENIPC_VERSION" /etc/os-release | cut -d= -f2 | tr -d /\"/) 54 | overlay_root=$(mount | grep upperdir= | sed -r 's/^.*upperdir=([a-z\/]+).+$/\1/') 55 | soc=$(ipcinfo --chip-name) 56 | soc_family=$(ipcinfo --family) 57 | soc_vendor=$(ipcinfo --vendor) 58 | 59 | # majestic 60 | mj_bin_file=/usr/bin/majestic 61 | mj_url="http://openipc.s3-eu-west-1.amazonaws.com/majestic.${soc_family}.${fw_variant:-lite}.master.tar.bz2" 62 | mj_version=$($mj_bin_file -v) 63 | 64 | # majestic in firmware 65 | mj_filesize_fw=$(ls -s $mj_bin_file | xargs | cut -d' ' -f1) 66 | 67 | # majestic in overlay 68 | mj_bin_file_ol="${overlay_root}${mj_bin_file}" 69 | [ -f "$mj_bin_file_ol" ] && mj_filesize_ol=$(ls -s "$mj_bin_file_ol" | xargs | cut -d' ' -f1) 70 | 71 | # majestic online 72 | #mj_meta_file=/tmp/mj_meta.txt 73 | mj_meta_file=$(mktemp) 74 | mj_meta_url=${mj_url//.bz2/.meta} 75 | 76 | echo_c 37 "Retrieving update info" 77 | echo_c 38 "from ${mj_meta_url}" 78 | log_and_run "curl $curl_opts --url $mj_meta_url --output $mj_meta_file" 79 | if [ $? -ne 0 ]; then 80 | echo_c 31 "Cannot retrieve ${mj_meta_url} file. Aborting." 81 | clean_quit 2 82 | fi 83 | 84 | echo_c 37 "\nComparing versions" 85 | mj_version_new=$(sed -n 1p "$mj_meta_file") 86 | echo_c 38 "Installed: $mj_version\nAvailable: $mj_version_new\n" 87 | if [ "$mj_version_new" = "$mj_version" ]; then 88 | echo_c 32 "Update is the same version!" 89 | if [ "1" = "$enforce" ]; then 90 | echo_c 33 "Enforced re-installation." 91 | else 92 | echo_c 37 "Nothing to update. Quitting..." 93 | clean_quit 3 94 | fi 95 | fi 96 | echo 97 | } 98 | 99 | check_space() { 100 | # NB! size in bytes, but since blocks are 1024 bytes each, we are safe here for now. 101 | # Rounding up by priming, since $(()) sucks at floats. 102 | mj_filesize_new=$(( ($(sed -n 2p "$mj_meta_file") + 1024) / 1024 )) 103 | 104 | # space available for update 105 | # NB! sizes are in allocated blocks. 106 | free_space=$(df | grep /overlay | xargs | cut -d' ' -f4) 107 | available_space=$(( ${free_space:=0} + ${mj_filesize_ol:=0} - 1 )) 108 | 109 | if [ "$mj_filesize_new" -gt "$available_space" ]; then 110 | echo_c 31 "Not enough space to update Majestic!" 111 | echo_c 37 "Update requires ${mj_filesize_new}K, but only ${available_space}K is available." 112 | if [ "$mj_filesize_ol" -ge 1 ]; then 113 | echo_c 37 "(${free_space}K of unallocated space plus ${mj_filesize_ol:=0}K Majestic in overlay)" 114 | fi 115 | clean_quit 4 116 | fi 117 | } 118 | 119 | update_majectic() { 120 | echo_c 37 "Updating Majestic" 121 | echo_c 38 "from ${mj_url}" 122 | 123 | echo_c 35 "Killing Majestic process" 124 | log_and_run "killall majestic" 125 | sleep 2 126 | 127 | # remove Majestic from overlay 128 | if [ -f "$mj_bin_file_ol" ]; then 129 | echo_c 37 "Deleting existing Majestic from overlay" 130 | log_and_run "rm $mj_bin_file_ol && mount -o remount /" 131 | fi 132 | 133 | # retrieve new version 134 | log_and_run "curl $curl_opts --url $mj_url --output - | bunzip2 | tar x $v_opts ./majestic -C /tmp/" 135 | if [ $? -ne 0 ]; then 136 | echo_c 31 "Cannot retrieve update from server." 137 | clean_quit 5 138 | fi 139 | 140 | # install new version 141 | log_and_run "mv /tmp/majestic $mj_bin_file" 142 | if [ $? -ne 0 ]; then 143 | echo_c 31 "Cannot replace $mj_bin_file." 144 | clean_quit 6 145 | fi 146 | } 147 | 148 | echo_c 37 "Majestic Updater\n" 149 | 150 | check_flash_memory_size 151 | 152 | get_system_info 153 | check_space 154 | update_majectic 155 | 156 | echo_c 37 "Done." 157 | echo_c 32 "Majestic $($mj_bin_file -v) installed in overlay.\n" 158 | echo_c 37 "Unconditional reboot" 159 | umount -a -t nfs -l 160 | reboot -f 161 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/plugin-motion.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | plugin="motion" 5 | plugin_name="Motion guard" 6 | page_title="Motion guard" 7 | params="enabled sensitivity send2email send2ftp send2mqtt send2telegram send2webhook send2ntfy send2yadisk playonspeaker throttle" 8 | 9 | [ -n "$(echo "$mj_hide_motionDetect" | sed -n "/\b${soc_family}\b/p")" ] && redirect_to "/" "danger" "Motion detection is not supported on your camera." 10 | 11 | tmp_file=/tmp/${plugin} 12 | 13 | config_file="${ui_config_dir}/${plugin}.conf" 14 | [ ! -f "$config_file" ] && touch $config_file 15 | 16 | if [ "POST" = "$REQUEST_METHOD" ]; then 17 | # parse values from parameters 18 | for p in $params; do 19 | eval ${plugin}_${p}=\$POST_${plugin}_${p} 20 | sanitize "${plugin}_${p}" 21 | done; unset p 22 | 23 | ### Validation 24 | if [ "true" = "$motion_enabled" ]; then 25 | [ "false" = "$motion_send2email" ] && \ 26 | [ "false" = "$motion_send2ftp" ] && \ 27 | [ "false" = "$motion_send2mqtt" ] && \ 28 | [ "false" = "$motion_send2telegram" ] && \ 29 | [ "false" = "$motion_send2webhook" ] && \ 30 | [ "false" = "$motion_send2yadisk" ] && \ 31 | [ "false" = "$motion_playonspeaker" ] && \ 32 | [ "false" = "$motion_send2ntfy" ] && \ 33 | set_error_flag "You need to select at least one method of notification" 34 | fi 35 | 36 | if [ -z "$error" ]; then 37 | # create temp config file 38 | :>$tmp_file 39 | for p in $params; do 40 | echo "${plugin}_${p}=\"$(eval echo \$${plugin}_${p})\"" >>$tmp_file 41 | done; unset p 42 | mv $tmp_file $config_file 43 | 44 | update_caminfo 45 | redirect_to "$SCRIPT_NAME" 46 | fi 47 | else 48 | include $config_file 49 | 50 | # Default values 51 | [ -z "$motion_sensitivity" ] && motion_sensitivity=1 52 | [ -z "$motion_throttle" ] && motion_throttle=10 53 | fi 54 | %> 55 | <%in p/header.cgi %> 56 | 57 |
58 |
59 |
60 | <% field_switch "motion_enabled" "Enable motion guard" %> 61 | <% field_range "motion_sensitivity" "Minimum number of objects" "1,30,1" %> 62 | <% field_range "motion_throttle" "Delay between notifications, sec." "1,30,1" %> 63 |
64 |
65 |
Actions
66 | 92 |
93 |
94 | <% [ -f $config_file ] && ex "cat $config_file" %> 95 |
96 |
97 | 98 | <% button_submit %> 99 |
100 | 101 | 110 | 111 | <%in p/footer.cgi %> 112 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/plugin-zerotier.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | plugin="zerotier" 5 | plugin_name="ZeroTier" 6 | page_title="ZeroTier" 7 | params="enabled nwid" 8 | config_file="${ui_config_dir}/${plugin}.conf" 9 | service_file=/etc/init.d/S90zerotier 10 | tmp_file=/tmp/${plugin}.conf 11 | zt_cli_bin=/usr/sbin/zerotier-cli 12 | zt_one_bin=/usr/sbin/zerotier-one 13 | 14 | [ ! -f "$zt_cli_bin" ] && redirect_to "/" "danger" "ZerotierOne client is not a part of your firmware." 15 | [ ! -f "$zt_one_bin" ] && redirect_to "/" "danger" "${zt_one_bin} file not found." 16 | [ ! -f "$service_file" ] && redirect_to "/" "danger" "${service_file} file not found." 17 | [ ! -f "$config_file" ] && touch $config_file 18 | 19 | include $config_file 20 | 21 | [ -n "$zerotier_nwid" ] && zt_network_config_file="/var/lib/zerotier-one/networks.d/${zerotier_nwid}.conf" 22 | 23 | if [ "POST" = "$REQUEST_METHOD" ]; then 24 | case "$POST_action" in 25 | create) 26 | # parse values from parameters 27 | for p in $params; do 28 | eval ${plugin}_${p}=\$POST_${plugin}_${p} 29 | sanitize "${plugin}_${p}" 30 | done; unset p 31 | 32 | ### Validation 33 | if [ "true" = "$zerotier_enabled" ]; then 34 | [ -z "$zerotier_nwid" ] && set_error_flag "ZeroTier Network ID cannot be empty." 35 | [ "${#zerotier_nwid}" -ne "16" ] && set_error_flag "ZeroTier Network ID should be 16 digits long." 36 | fi 37 | 38 | if [ -z "$error" ]; then 39 | # create temp config file 40 | :>$tmp_file 41 | for p in $params; do 42 | echo "${plugin}_${p}=\"$(eval echo \$${plugin}_${p})\"" >>$tmp_file 43 | done; unset p 44 | mv $tmp_file $config_file 45 | 46 | update_caminfo 47 | redirect_back "success" "${plugin_name} config updated." 48 | fi 49 | ;; 50 | start|open) 51 | $service_file start >&2 52 | redirect_back # "success" "Sevice is up" 53 | ;; 54 | stop|close) 55 | $service_file stop >&2 56 | redirect_back # "danger" "Service is down" 57 | ;; 58 | join) 59 | $zt_cli_bin join $zerotier_nwid >&2 60 | while [ -z $(grep nwid "$zt_network_config_file") ]; do sleep 1; done 61 | redirect_back 62 | ;; 63 | leave) 64 | $zt_cli_bin leave $zerotier_nwid >&2 65 | redirect_back 66 | ;; 67 | *) 68 | redirect_back "danger" "Unknown action $POST_action!" 69 | esac 70 | fi 71 | %> 72 | <%in p/header.cgi %> 73 | 74 |
75 |
76 |

Settings

77 | 78 |
79 | <% field_hidden "action" "create" %> 80 | <% field_switch "zerotier_enabled" "Enable ZeroTier network on restart" %> 81 | <% field_text "zerotier_nwid" "ZeroTier Network ID" "Don't have it? Get one at my.zerotier.com" %> 82 | <% button_submit %> 83 |
84 | 85 |
86 | 87 | <% zerotier-cli info >/dev/null; if [ $? -eq 0 ]; then %> 88 |
89 |
ZeroTier Tunnel is open
90 | 91 | <% if [ -f "$zt_network_config_file" ]; then %> 92 | <% zt_id="$(grep ^nwid= ${zt_network_config_file} | cut -d= -f2)" %> 93 | <% zt_name="$(grep ^n= ${zt_network_config_file} | cut -d= -f2)" %> 94 | <% if [ -n "$zt_id" ] && [ -n "$zt_name" ]; then %> 95 |

Use the following credentials to set up remote access via active virtual tunnel:

96 |
97 |
NWID: <%= $zt_id %> 98 |
Name: <%= $zt_name %> 99 |
100 |
101 | <% field_hidden "action" "leave" %> 102 | <% button_submit "Leave network" "danger" %> 103 |
104 | <% fi %> 105 | <% else %> 106 |
107 |
108 |
109 | <% field_hidden "action" "join" %> 110 | <% button_submit "Join network" %> 111 |
112 |
113 |
114 |
115 | <% field_hidden "action" "stop" %> 116 | <% button_submit "Close tunnel" "danger" %> 117 |
118 |
119 |
120 | <% fi %> 121 |
122 | <% else %> 123 |
124 |

ZeroTier Tunnel is closed

125 |
126 | <% field_hidden "action" "start" %> 127 | <% button_submit "Open tunnel" %> 128 |
129 |
130 | <% fi %> 131 |
132 | 133 |
134 |

Configuration files

135 | <% 136 | [ -f "$service_file" ] && ex "cat $service_file" 137 | [ -f "$config_file" ] && ex "cat $config_file" 138 | [ -f "$zt_network_config_file" ] && ex "cat $zt_network_config_file" 139 | ex "ps | grep zerotier" 140 | %> 141 |
142 |
143 | 144 | <%in p/footer.cgi %> 145 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/majestic.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | [ ! -f "/rom/${mj_bin_file}" ] && redirect_to '/' "danger" $STR_NOT_SUPPORTED 5 | 6 | update_meta() { 7 | # re-download metafile if older than 1 hour 8 | mj_meta_url="http://openipc.s3-eu-west-1.amazonaws.com/majestic.${soc_family}.${fw_variant}.master.tar.meta" 9 | 10 | if [ -f "$mj_meta_file" ]; then 11 | mj_meta_file_timestamp=$(time_epoch "$(ls -lc --full-time $mj_meta_file | xargs | cut -d' ' -f6,7)") 12 | mj_meta_file_expiration=$(( $(time_epoch) + 3600 )) 13 | [ "$mj_meta_file_timestamp" -le "$mj_meta_file_expiration" ] && return 14 | rm $mj_meta_file 15 | fi 16 | 17 | [ "200" = $(curl $mj_meta_url -s -f -w %{http_code} -o /dev/null) ] && curl -s $mj_meta_url -o $mj_meta_file 18 | } 19 | 20 | page_title="Majestic" 21 | mj_meta_file=/tmp/mj_meta.txt 22 | 23 | # NB! sizes are in allocated blocks. 24 | mj_filesize_fw=$(ls -s $mj_bin_file | xargs | cut -d' ' -f1) 25 | 26 | mj_bin_file_ol="${overlay_root}${mj_bin_file}" 27 | [ -f "$mj_bin_file_ol" ] && mj_filesize_ol=$(ls -s $mj_bin_file_ol | xargs | cut -d' ' -f1) 28 | 29 | free_space=$(df | grep /overlay | xargs | cut -d' ' -f4) 30 | available_space=$(( ${free_space:=0} + ${mj_filesize_ol:=0} - 1 )) 31 | 32 | if [ "POST" = "$REQUEST_METHOD" ]; then 33 | case "$POST_action" in 34 | rmmj) 35 | [ -f "$mj_bin_file_ol" ] && rm $mj_bin_file_ol && mount -oremount / 36 | redirect_back "success" "Majestic reverted to bundled version." 37 | ;; 38 | update) 39 | [ -z "$network_gateway" ] && redirect_to "danger" "Updating requires an internet connection!" 40 | update_meta 41 | mj_filesize_new=$(( ($(cat $mj_meta_file | sed -n 2p) + 1024) / 1024 )) 42 | [ "$mj_filesize_new" -gt "$available_space" ] && redirect_back "danger" "Not enough space to update Majestic. ${mj_filesize_new} KB > ${available_space} KB." 43 | curl --silent --insecure --location -o - http://openipc.s3-eu-west-1.amazonaws.com/majestic.${soc_family}.${fw_variant}.master.tar.bz2 | bunzip2 | tar -x majestic -C /usr/bin 44 | [ $? -ne 0 ] && redirect_back "error" "Cannot retrieve update from server." 45 | redirect_to "reboot.cgi" 46 | ;; 47 | esac 48 | fi 49 | 50 | mj_version_fw=$(/rom${mj_bin_file} -v) 51 | mj_version_ol="- not installed in overlay -" 52 | [ -f "$mj_bin_file_ol" ] && mj_version_ol=$($mj_bin_file_ol -v) 53 | 54 | if [ -n "$network_gateway" ]; then 55 | update_meta 56 | if [ -f "$mj_meta_file" ]; then 57 | # parse version, date and file size 58 | if [ "$(wc -l $mj_meta_file | cut -d' ' -f1)" = "1" ]; then 59 | mj_filesize_new=$(sed -n 1p $mj_meta_file) 60 | else 61 | mj_version_new=$(sed -n 1p $mj_meta_file) 62 | mj_filesize_new=$(sed -n 2p $mj_meta_file) 63 | fi 64 | # NB! size in bytes, but since blocks are 1024 bytes each, we are safe here for now. 65 | mj_filesize_new=$(( ($mj_filesize_new + 1024) / 1024 )) # Rounding up by priming, since $(()) sucks at floats. 66 | else 67 | mj_version_new="unavailable" 68 | fi 69 | else 70 | mj_version_new="- no access to S3 bucket -" 71 | fi 72 | %> 73 | <%in p/header.cgi %> 74 | 75 |
76 |
77 |

Version

78 |
79 |
Bundled
80 |
<%= $mj_version_fw %>
81 |
In overlay
82 |
<%= $mj_version_ol %>
83 |
On GitHub
84 |
<%= $mj_version_new %>
85 |
86 |
87 |
88 |

Configuration

89 | <% if [ -z "$(diff /rom/etc/majestic.yaml /etc/majestic.yaml)" ]; then %> 90 |

Majestic uses original configuration.

91 |

Make changes.

92 | <% else %> 93 |

Majestic uses custom configuration.

94 |

See difference

95 | <% fi %> 96 |
97 |
98 | <% if [ -n "$network_gateway" ]; then %> 99 |

Update

100 | <% if [ "$mj_version_new" = "$mj_version_ol" ] || [ -z "$mj_version_ol" -a "$mj_version_new" = "$mj_version_fw" ]; then %> 101 |
102 |

Nothing to update.

103 |

Latest version is already installed.

104 |
105 | <% else %> 106 | <% if [ -f "$mj_meta_file" ]; then %> 107 | <% if [ "$mj_filesize_new" -le "$available_space" ]; then %> 108 |
109 | <% field_hidden "action" "update" %> 110 | <% button_submit "Install update" "warning" %> 111 |
112 | <% else %> 113 |
114 |

Not enough space to update Majestic!

115 |

Update requires <%= $mj_filesize_new %>K, but only <%= $available_space %>K is available 116 | <% if [ "$mj_filesize_ol" -ge "1" ]; then %> 117 | (<%= $free_space %>K of unallocated space plus <%= ${mj_filesize_ol:=0} %>K size of Majestic installed in overlay) 118 | <% fi %> 119 | .

120 |
121 | <% fi %> 122 | <% fi %> 123 | <% fi %> 124 | <% else %> 125 |

Upgrading requires access to Amazon S3.

126 | <% fi %> 127 | <% if [ -f "$mj_bin_file_ol" ]; then %> 128 |
129 |

More recent version of Majestic found in overlay partition. It takes <%= $mj_filesize_ol %> KB of space.

130 |
131 | <% field_hidden "action" "rmmj" %> 132 | <% button_submit "Revert to bundled version" "warning" %> 133 |
134 |
135 | <% fi %> 136 |
137 |
138 | 139 | <%in p/footer.cgi %> 140 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/network.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | plugin="network" 5 | page_title="Network settings" 6 | params="address dhcp dns_1 dns_2 gateway hostname netmask interface wifi_device wifi_ssid wifi_password" 7 | tmp_file=/tmp/${plugin}.conf 8 | 9 | network_wifi_device="$(fw_printenv -n wlandev)" 10 | network_wifi_ssid="$(fw_printenv -n wlanssid)" 11 | network_wifi_password="$(fw_printenv -n wlanpass)" 12 | 13 | profiles="$(echo unknown-device && grep -r '$1..=' /etc/wireless | cut -d '"' -f 4 | sort | grep -e ${soc} -e ${soc_family} -e generic)" 14 | 15 | if [ "POST" = "$REQUEST_METHOD" ]; then 16 | case "$POST_action" in 17 | changemac) 18 | if echo "$POST_mac_address" | grep -Eiq '^([0-9a-f]{2}[:-]){5}([0-9a-f]{2})$'; then 19 | fw_setenv ethaddr $POST_mac_address 20 | update_caminfo 21 | redirect_to "reboot.cgi" 22 | else 23 | redirect_back "warning" "${POST_mac_address} is as invalid MAC address." 24 | fi 25 | ;; 26 | reset) 27 | /usr/sbin/sysreset.sh -n 28 | redirect_back 29 | ;; 30 | update) 31 | # parse values from parameters 32 | for p in $params; do 33 | eval ${plugin}_${p}=\$POST_${plugin}_${p} 34 | sanitize "${plugin}_${p}" 35 | done; unset p 36 | 37 | #network_interface=$(echo $network_interfaces | cut -d' ' -f1) 38 | 39 | [ -z "$network_interface" ] && set_error_flag "Default network interface cannot be empty." 40 | 41 | if [ "wlan0" = "$network_interface" ]; then 42 | [ -z "$network_wifi_device" ] && set_error_flag "WLAN Device cannot be empty." 43 | [ -z "$network_wifi_ssid" ] && set_error_flag"WLAN SSID cannot be empty." 44 | [ -z "$network_wifi_password" ] && set_error_flag "WLAN Password cannot be empty." 45 | fi 46 | 47 | if [ "false" = "$network_dhcp" ]; then 48 | network_mode="static" 49 | [ -z "$network_address" ] && set_error_flag "IP address cannot be empty." 50 | [ -z "$network_netmask" ] && set_error_flag "Networking mask cannot be empty." 51 | else 52 | network_mode="dhcp" 53 | fi 54 | 55 | if [ -z "$error" ]; then 56 | command="setnetiface.sh" 57 | command="${command} -i $network_interface" 58 | command="${command} -m $network_mode" 59 | command="${command} -h $network_hostname" 60 | 61 | if [ "wlan0" = "$network_interface" ]; then 62 | command="${command} -r $network_wifi_device" 63 | command="${command} -s $network_wifi_ssid" 64 | command="${command} -p $network_wifi_password" 65 | fi 66 | 67 | if [ "dhcp" != "$network_mode" ]; then 68 | command="${command} -a $network_address" 69 | command="${command} -n $network_netmask" 70 | [ -n "$network_gateway" ] && command="${command} -g $network_gateway" 71 | [ -n "$network_dns_1" ] && command="${command} -d $network_dns_1" 72 | [ -n "$network_dns_2" ] && command="${command},${network_dns_2}" 73 | fi 74 | 75 | echo "$command" >>/tmp/webui.log 76 | eval "$command" >/dev/null 2>&1 77 | 78 | update_caminfo 79 | redirect_back "success" "Network settings updated." 80 | fi 81 | ;; 82 | esac 83 | fi 84 | %> 85 | <%in p/header.cgi %> 86 | 87 |
88 |
89 |
90 | <% field_hidden "action" "update" %> 91 | <% field_text "network_hostname" "Hostname" %> 92 | <% field_select "network_interface" "Network interface" "eth0 wlan0" %> 93 | <% field_select "network_wifi_device" "WLAN Device" "$profiles" %> 94 | <% field_text "network_wifi_ssid" "WLAN SSID" %> 95 | <% field_text "network_wifi_password" "WLAN Password" %> 96 | 97 | <% field_switch "network_dhcp" "Use DHCP" %> 98 | <% field_text "network_address" "IP Address" %> 99 | <% field_text "network_netmask" "IP Netmask" %> 100 | <% field_text "network_gateway" "Gateway" %> 101 | <% field_text "network_dns_1" "DNS 1" %> 102 | <% field_text "network_dns_2" "DNS 2" %> 103 | <% button_submit %> 104 |
105 | 106 |
107 |
Reset network configuration
108 |

Restore the config file bundled with firmware. All changes to the default configuration will be lost!

109 |
110 | <% field_hidden "action" "reset" %> 111 | <% button_submit "Reset config" "danger" %> 112 |
113 |
114 |
115 |
116 | <% ex "cat /etc/hostname" %> 117 | <% ex "cat /etc/hosts" %> 118 | <% ex "cat /etc/network/interfaces" %> 119 | <% for i in $(ls -1 /etc/network/interfaces.d/); do %> 120 | <% ls /sys/class/net | grep -q $i && ex "cat /etc/network/interfaces.d/$i" %> 121 | <% done %> 122 | <% ex "ip address" %> 123 | <% ex "ip route list" %> 124 | <% [ -f /etc/resolv.conf ] && ex "cat /etc/resolv.conf" %> 125 |
126 |
127 | 128 | 154 | 155 | <%in p/footer.cgi %> 156 | -------------------------------------------------------------------------------- /files/var/www/cgi-bin/majestic-endpoints.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | page_title="Majestic Endpoints" 5 | %> 6 | <%in p/header.cgi %> 7 |
8 |
9 |

Video

10 |
11 |
http://<%= $network_address %>/mjpeg
12 |
MJPEG video stream.
13 |
http://<%= $network_address %>/video.mp4
14 |
fMP4 video stream.
15 |
rtsp://username:password@<%= $network_address %>/stream=0
16 |
RTSP main stream (video0).
17 |
rtsp://username:password@<%= $network_address %>/stream=1
18 |
RTSP substream (video1).
19 |
http://<%= $network_address %>/hls
20 |
HLS live-streaming in web browser.
21 |
http://<%= $network_address %>/webrtc
22 |
WebRTC live-streaming in web browser.
23 |
http://<%= $network_address %>/mjpeg.html
24 |
MJPEG & MP3 live-streaming in web browser.
25 |
26 |
27 |
28 |

Audio

29 |
30 |
http://<%= $network_address %>/audio.opus
31 |
Opus audio stream.
32 |
http://<%= $network_address %>/audio.pcm
33 |
Raw PCM audio stream.
34 |
http://<%= $network_address %>/audio.m4a
35 |
AAC audio stream.
36 |
http://<%= $network_address %>/audio.mp3
37 |
MP3 audio stream.
38 |
http://<%= $network_address %>/audio.alaw
39 |
A-law compressed audio stream.
40 |
http://<%= $network_address %>/audio.ulaw
41 |
μ-law compressed audio stream.
42 |
http://<%= $network_address %>/audio.g711a
43 |
G.711 A-law audio stream.
44 |
http://<%= $network_address %>/play_audio
45 |
Play audio file on camera's speaker.1,3 46 |
Accepts POST requests with audio file as a parameter.
47 |
48 |
49 |
50 |

Still Images

51 |
52 |
http://<%= $network_address %>/image.jpg
53 |
Snapshot in JPEG format.
Optional parameters:2,4 54 |
    55 |
  • width, height - size of resulting image
  • 56 |
  • qfactor - JPEG quality factor (1-99)
  • 57 |
  • color2gray - convert to grayscale
  • 58 |
  • crop - crop resulting image as 16x16x320x320
  • 59 |
60 |
61 |
http://<%= $network_address %>/image.heif
62 |
Snapshot in HEIF format.
63 |
http://<%= $network_address %>/image.yuv420
64 |
Snapshot in YUV420 format.
65 |
http://<%= $network_address %>/image.dng
66 |
Snapshot in Adobe DNG format (raw).3
67 |
68 |
69 |
70 |

Night API

71 |
72 |
http://<%= $network_address %>/night/on
73 |
Turn on night mode.
74 |
http://<%= $network_address %>/night/off
75 |
Turn off night mode.
76 |
http://<%= $network_address %>/night/toggle
77 |
Toggle current night mode.
78 |
79 |
80 |
81 |

Monitoring

82 |
83 |
http://<%= $network_address %>/api/v1/config.json
84 |
Actual Majestic config in JSON format.
85 |
http://<%= $network_address %>/metrics
86 |
Node exporter for Prometheus.
87 |
88 |
89 |
90 | 91 |
    92 |
  1. Only HiSilicon and Goke SoCs.
  2. 93 |
  3. Only HiSilicon SoCs v2 and up.
  4. 94 |
  5. E.g. ffplay -ar 48000 -ac 1 -f s16le http://<%= $network_address %>/audio.pcm
  6. 95 |
  7. E.g. http://<%= $network_address %>/image.jpg?width=640&height=480&qfactor=50&color2gray=1&crop=80x32x512x400
  8. 96 |
97 | 98 |

More examples available in our wiki.

99 | 100 | 132 | <%in p/footer.cgi %> 133 | --------------------------------------------------------------------------------