Initial copy to open source repo
29
.gitignore
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# dotenv
|
||||
.env
|
||||
|
||||
# vscode
|
||||
.vscode/
|
||||
|
||||
.DS_Store
|
||||
|
||||
# Output (rootfs, etc...)
|
||||
out/
|
||||
tools/product_key_gen/keys.txt
|
||||
tools/product_key_gen/keys.pdf
|
||||
tools/product_key_gen/keys.html
|
||||
tools/product_key_gen/keys.sql
|
||||
|
||||
# Release tarballs
|
||||
releases/
|
31
make_rootfs.sh
Executable file
|
@ -0,0 +1,31 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
### Clear existing rootfs ###
|
||||
rm -rf out/rootfs*
|
||||
mkdir -p out/rootfs_rock64/
|
||||
mkdir -p out/rootfs_raspi/
|
||||
#mkdir -p out/rootfs_free/
|
||||
|
||||
|
||||
### Make standard rootfs ###
|
||||
# Copy Base
|
||||
cp -rf rootfs/standard/* out/rootfs_rock64/
|
||||
|
||||
|
||||
#### Make mini rootfs ###
|
||||
# Copy base
|
||||
cp -rf rootfs/standard/* out/rootfs_raspi/
|
||||
cp -rf rootfs/raspi/* out/rootfs_raspi/
|
||||
|
||||
# Remove unnecessary files
|
||||
#rm -rf out/rootfs_raspi/etc/systemd/system/electrs.service
|
||||
#rm -rf out/rootfs_raspi/var/www/mynode/static/electrum_server.html
|
||||
#rm -rf out/rootfs_raspi/var/www/mynode/static/bitcoind_address.html
|
||||
#rm -rf out/rootfs_raspi/var/www/mynode/static/bitcoind_block.html
|
||||
#rm -rf out/rootfs_raspi/var/www/mynode/static/bitcoind_explorer.html
|
||||
#rm -rf out/rootfs_raspi/var/www/mynode/static/bitcoind_tx.html
|
||||
#rm -rf out/rootfs_raspi/var/www/mynode/electrum_server.py
|
||||
|
||||
#### Make free rootfs ###
|
||||
#cp -rf rootfs/free/* out/rootfs_free/
|
4
make_rootfs_auto.sh
Executable file
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
|
||||
fswatch $(dirname $0)/rootfs | (while read; do $(dirname $0)/make_rootfs.sh; echo "Update rootfs!"; done)
|
||||
|
27
rootfs/free/etc/dphys-swapfile
Normal file
|
@ -0,0 +1,27 @@
|
|||
# /etc/dphys-swapfile - user settings for dphys-swapfile package
|
||||
# author Neil Franklin, last modification 2010.05.05
|
||||
# copyright ETH Zuerich Physics Departement
|
||||
# use under either modified/non-advertising BSD or GPL license
|
||||
|
||||
# this file is sourced with . so full normal sh syntax applies
|
||||
|
||||
# the default settings are added as commented out CONF_*=* lines
|
||||
|
||||
|
||||
# where we want the swapfile to be, this is the default
|
||||
#CONF_SWAPFILE=/var/swap
|
||||
|
||||
# set size to absolute value, leaving empty (default) then uses computed value
|
||||
# you most likely don't want this, unless you have an special disk situation
|
||||
#######################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################CONF_SWAPSIZE=100100
|
||||
|
||||
# set size to computed value, this times RAM size, dynamically adapts,
|
||||
# guarantees that there is enough swap without wasting disk space on excess
|
||||
#CONF_SWAPFACTOR=2
|
||||
|
||||
# restrict size (computed and absolute!) to maximally this limit
|
||||
# can be set to empty for no limit, but beware of filled partitions!
|
||||
# this is/was a (outdated?) 32bit kernel limit (in MBytes), do not overrun it
|
||||
# but is also sensible on 64bit to prevent filling /var or even / partition
|
||||
CONF_MAXSWAP=1024
|
||||
CONF_SWAPFILE=/mnt/hdd/swapfile
|
855
rootfs/free/etc/fail2ban/jail.conf
Normal file
|
@ -0,0 +1,855 @@
|
|||
#
|
||||
# WARNING: heavily refactored in 0.9.0 release. Please review and
|
||||
# customize settings for your setup.
|
||||
#
|
||||
# Changes: in most of the cases you should not modify this
|
||||
# file, but provide customizations in jail.local file,
|
||||
# or separate .conf files under jail.d/ directory, e.g.:
|
||||
#
|
||||
# HOW TO ACTIVATE JAILS:
|
||||
#
|
||||
# YOU SHOULD NOT MODIFY THIS FILE.
|
||||
#
|
||||
# It will probably be overwritten or improved in a distribution update.
|
||||
#
|
||||
# Provide customizations in a jail.local file or a jail.d/customisation.local.
|
||||
# For example to change the default bantime for all jails and to enable the
|
||||
# ssh-iptables jail the following (uncommented) would appear in the .local file.
|
||||
# See man 5 jail.conf for details.
|
||||
#
|
||||
# [DEFAULT]
|
||||
# bantime = 3600
|
||||
#
|
||||
# [sshd]
|
||||
# enabled = true
|
||||
#
|
||||
# See jail.conf(5) man page for more information
|
||||
|
||||
|
||||
|
||||
# Comments: use '#' for comment lines and ';' (following a space) for inline comments
|
||||
|
||||
|
||||
[INCLUDES]
|
||||
|
||||
#before = paths-distro.conf
|
||||
before = paths-debian.conf
|
||||
|
||||
# The DEFAULT allows a global definition of the options. They can be overridden
|
||||
# in each jail afterwards.
|
||||
|
||||
[DEFAULT]
|
||||
|
||||
#
|
||||
# MISCELLANEOUS OPTIONS
|
||||
#
|
||||
|
||||
# "ignoreip" can be an IP address, a CIDR mask or a DNS host. Fail2ban will not
|
||||
# ban a host which matches an address in this list. Several addresses can be
|
||||
# defined using space (and/or comma) separator.
|
||||
ignoreip = 127.0.0.1/8 10.0.0.0/8 192.168.0.0/16
|
||||
|
||||
# External command that will take an tagged arguments to ignore, e.g. <ip>,
|
||||
# and return true if the IP is to be ignored. False otherwise.
|
||||
#
|
||||
# ignorecommand = /path/to/command <ip>
|
||||
ignorecommand =
|
||||
|
||||
# "bantime" is the number of seconds that a host is banned.
|
||||
bantime = 600
|
||||
|
||||
# A host is banned if it has generated "maxretry" during the last "findtime"
|
||||
# seconds.
|
||||
findtime = 600
|
||||
|
||||
# "maxretry" is the number of failures before a host get banned.
|
||||
maxretry = 10
|
||||
|
||||
# "backend" specifies the backend used to get files modification.
|
||||
# Available options are "pyinotify", "gamin", "polling", "systemd" and "auto".
|
||||
# This option can be overridden in each jail as well.
|
||||
#
|
||||
# pyinotify: requires pyinotify (a file alteration monitor) to be installed.
|
||||
# If pyinotify is not installed, Fail2ban will use auto.
|
||||
# gamin: requires Gamin (a file alteration monitor) to be installed.
|
||||
# If Gamin is not installed, Fail2ban will use auto.
|
||||
# polling: uses a polling algorithm which does not require external libraries.
|
||||
# systemd: uses systemd python library to access the systemd journal.
|
||||
# Specifying "logpath" is not valid for this backend.
|
||||
# See "journalmatch" in the jails associated filter config
|
||||
# auto: will try to use the following backends, in order:
|
||||
# pyinotify, gamin, polling.
|
||||
#
|
||||
# Note: if systemd backend is chosen as the default but you enable a jail
|
||||
# for which logs are present only in its own log files, specify some other
|
||||
# backend for that jail (e.g. polling) and provide empty value for
|
||||
# journalmatch. See https://github.com/fail2ban/fail2ban/issues/959#issuecomment-74901200
|
||||
backend = auto
|
||||
|
||||
# "usedns" specifies if jails should trust hostnames in logs,
|
||||
# warn when DNS lookups are performed, or ignore all hostnames in logs
|
||||
#
|
||||
# yes: if a hostname is encountered, a DNS lookup will be performed.
|
||||
# warn: if a hostname is encountered, a DNS lookup will be performed,
|
||||
# but it will be logged as a warning.
|
||||
# no: if a hostname is encountered, will not be used for banning,
|
||||
# but it will be logged as info.
|
||||
# raw: use raw value (no hostname), allow use it for no-host filters/actions (example user)
|
||||
usedns = warn
|
||||
|
||||
# "logencoding" specifies the encoding of the log files handled by the jail
|
||||
# This is used to decode the lines from the log file.
|
||||
# Typical examples: "ascii", "utf-8"
|
||||
#
|
||||
# auto: will use the system locale setting
|
||||
logencoding = auto
|
||||
|
||||
# "enabled" enables the jails.
|
||||
# By default all jails are disabled, and it should stay this way.
|
||||
# Enable only relevant to your setup jails in your .local or jail.d/*.conf
|
||||
#
|
||||
# true: jail will be enabled and log files will get monitored for changes
|
||||
# false: jail is not enabled
|
||||
enabled = false
|
||||
|
||||
|
||||
# "filter" defines the filter to use by the jail.
|
||||
# By default jails have names matching their filter name
|
||||
#
|
||||
filter = %(__name__)s
|
||||
|
||||
|
||||
#
|
||||
# ACTIONS
|
||||
#
|
||||
|
||||
# Some options used for actions
|
||||
|
||||
# Destination email address used solely for the interpolations in
|
||||
# jail.{conf,local,d/*} configuration files.
|
||||
destemail = root@localhost
|
||||
|
||||
# Sender email address used solely for some actions
|
||||
sender = root@localhost
|
||||
|
||||
# E-mail action. Since 0.8.1 Fail2Ban uses sendmail MTA for the
|
||||
# mailing. Change mta configuration parameter to mail if you want to
|
||||
# revert to conventional 'mail'.
|
||||
mta = sendmail
|
||||
|
||||
# Default protocol
|
||||
protocol = tcp
|
||||
|
||||
# Specify chain where jumps would need to be added in iptables-* actions
|
||||
chain = INPUT
|
||||
|
||||
# Ports to be banned
|
||||
# Usually should be overridden in a particular jail
|
||||
port = 0:65535
|
||||
|
||||
# Format of user-agent https://tools.ietf.org/html/rfc7231#section-5.5.3
|
||||
fail2ban_agent = Fail2Ban/%(fail2ban_version)s
|
||||
|
||||
#
|
||||
# Action shortcuts. To be used to define action parameter
|
||||
|
||||
# Default banning action (e.g. iptables, iptables-new,
|
||||
# iptables-multiport, shorewall, etc) It is used to define
|
||||
# action_* variables. Can be overridden globally or per
|
||||
# section within jail.local file
|
||||
banaction = iptables-multiport
|
||||
banaction_allports = iptables-allports
|
||||
|
||||
# The simplest action to take: ban only
|
||||
action_ = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
|
||||
# ban & send an e-mail with whois report to the destemail.
|
||||
action_mw = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
%(mta)s-whois[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
|
||||
# ban & send an e-mail with whois report and relevant log lines
|
||||
# to the destemail.
|
||||
action_mwl = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
%(mta)s-whois-lines[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"]
|
||||
|
||||
# See the IMPORTANT note in action.d/xarf-login-attack for when to use this action
|
||||
#
|
||||
# ban & send a xarf e-mail to abuse contact of IP address and include relevant log lines
|
||||
# to the destemail.
|
||||
action_xarf = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
|
||||
xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath=%(logpath)s, port="%(port)s"]
|
||||
|
||||
# ban IP on CloudFlare & send an e-mail with whois report and relevant log lines
|
||||
# to the destemail.
|
||||
action_cf_mwl = cloudflare[cfuser="%(cfemail)s", cftoken="%(cfapikey)s"]
|
||||
%(mta)s-whois-lines[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"]
|
||||
|
||||
# Report block via blocklist.de fail2ban reporting service API
|
||||
#
|
||||
# See the IMPORTANT note in action.d/blocklist_de.conf for when to
|
||||
# use this action. Create a file jail.d/blocklist_de.local containing
|
||||
# [Init]
|
||||
# blocklist_de_apikey = {api key from registration]
|
||||
#
|
||||
action_blocklist_de = blocklist_de[email="%(sender)s", service=%(filter)s, apikey="%(blocklist_de_apikey)s", agent="%(fail2ban_agent)s"]
|
||||
|
||||
# Report ban via badips.com, and use as blacklist
|
||||
#
|
||||
# See BadIPsAction docstring in config/action.d/badips.py for
|
||||
# documentation for this action.
|
||||
#
|
||||
# NOTE: This action relies on banaction being present on start and therefore
|
||||
# should be last action defined for a jail.
|
||||
#
|
||||
action_badips = badips.py[category="%(__name__)s", banaction="%(banaction)s", agent="%(fail2ban_agent)s"]
|
||||
#
|
||||
# Report ban via badips.com (uses action.d/badips.conf for reporting only)
|
||||
#
|
||||
action_badips_report = badips[category="%(__name__)s", agent="%(fail2ban_agent)s"]
|
||||
|
||||
# Choose default action. To change, just override value of 'action' with the
|
||||
# interpolation to the chosen action shortcut (e.g. action_mw, action_mwl, etc) in jail.local
|
||||
# globally (section [DEFAULT]) or per specific section
|
||||
action = %(action_)s
|
||||
|
||||
|
||||
#
|
||||
# JAILS
|
||||
#
|
||||
|
||||
#
|
||||
# SSH servers
|
||||
#
|
||||
|
||||
[sshd]
|
||||
|
||||
port = ssh
|
||||
logpath = %(sshd_log)s
|
||||
backend = %(sshd_backend)s
|
||||
|
||||
|
||||
[sshd-ddos]
|
||||
# This jail corresponds to the standard configuration in Fail2ban.
|
||||
# The mail-whois action send a notification e-mail with a whois request
|
||||
# in the body.
|
||||
port = ssh
|
||||
logpath = %(sshd_log)s
|
||||
backend = %(sshd_backend)s
|
||||
|
||||
|
||||
[dropbear]
|
||||
|
||||
port = ssh
|
||||
logpath = %(dropbear_log)s
|
||||
backend = %(dropbear_backend)s
|
||||
|
||||
|
||||
[selinux-ssh]
|
||||
|
||||
port = ssh
|
||||
logpath = %(auditd_log)s
|
||||
|
||||
|
||||
#
|
||||
# HTTP servers
|
||||
#
|
||||
|
||||
[apache-auth]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
|
||||
|
||||
[apache-badbots]
|
||||
# Ban hosts which agent identifies spammer robots crawling the web
|
||||
# for email addresses. The mail outputs are buffered.
|
||||
port = http,https
|
||||
logpath = %(apache_access_log)s
|
||||
bantime = 172800
|
||||
maxretry = 1
|
||||
|
||||
|
||||
[apache-noscript]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
|
||||
|
||||
[apache-overflows]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
[apache-nohome]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
[apache-botsearch]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
[apache-fakegooglebot]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_access_log)s
|
||||
maxretry = 1
|
||||
ignorecommand = %(ignorecommands_dir)s/apache-fakegooglebot <ip>
|
||||
|
||||
|
||||
[apache-modsecurity]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
[apache-shellshock]
|
||||
|
||||
port = http,https
|
||||
logpath = %(apache_error_log)s
|
||||
maxretry = 1
|
||||
|
||||
|
||||
[openhab-auth]
|
||||
|
||||
filter = openhab
|
||||
action = iptables-allports[name=NoAuthFailures]
|
||||
logpath = /opt/openhab/logs/request.log
|
||||
|
||||
|
||||
[nginx-http-auth]
|
||||
|
||||
port = http,https
|
||||
logpath = %(nginx_error_log)s
|
||||
|
||||
# To use 'nginx-limit-req' jail you should have `ngx_http_limit_req_module`
|
||||
# and define `limit_req` and `limit_req_zone` as described in nginx documentation
|
||||
# http://nginx.org/en/docs/http/ngx_http_limit_req_module.html
|
||||
# or for example see in 'config/filter.d/nginx-limit-req.conf'
|
||||
[nginx-limit-req]
|
||||
port = http,https
|
||||
logpath = %(nginx_error_log)s
|
||||
|
||||
[nginx-botsearch]
|
||||
|
||||
port = http,https
|
||||
logpath = %(nginx_error_log)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
# Ban attackers that try to use PHP's URL-fopen() functionality
|
||||
# through GET/POST variables. - Experimental, with more than a year
|
||||
# of usage in production environments.
|
||||
|
||||
[php-url-fopen]
|
||||
|
||||
port = http,https
|
||||
logpath = %(nginx_access_log)s
|
||||
%(apache_access_log)s
|
||||
|
||||
|
||||
[suhosin]
|
||||
|
||||
port = http,https
|
||||
logpath = %(suhosin_log)s
|
||||
|
||||
|
||||
[lighttpd-auth]
|
||||
# Same as above for Apache's mod_auth
|
||||
# It catches wrong authentifications
|
||||
port = http,https
|
||||
logpath = %(lighttpd_error_log)s
|
||||
|
||||
|
||||
#
|
||||
# Webmail and groupware servers
|
||||
#
|
||||
|
||||
[roundcube-auth]
|
||||
|
||||
port = http,https
|
||||
logpath = %(roundcube_errors_log)s
|
||||
|
||||
|
||||
[openwebmail]
|
||||
|
||||
port = http,https
|
||||
logpath = /var/log/openwebmail.log
|
||||
|
||||
|
||||
[horde]
|
||||
|
||||
port = http,https
|
||||
logpath = /var/log/horde/horde.log
|
||||
|
||||
|
||||
[groupoffice]
|
||||
|
||||
port = http,https
|
||||
logpath = /home/groupoffice/log/info.log
|
||||
|
||||
|
||||
[sogo-auth]
|
||||
# Monitor SOGo groupware server
|
||||
# without proxy this would be:
|
||||
# port = 20000
|
||||
port = http,https
|
||||
logpath = /var/log/sogo/sogo.log
|
||||
|
||||
|
||||
[tine20]
|
||||
|
||||
logpath = /var/log/tine20/tine20.log
|
||||
port = http,https
|
||||
|
||||
|
||||
#
|
||||
# Web Applications
|
||||
#
|
||||
#
|
||||
|
||||
[drupal-auth]
|
||||
|
||||
port = http,https
|
||||
logpath = %(syslog_daemon)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
[guacamole]
|
||||
|
||||
port = http,https
|
||||
logpath = /var/log/tomcat*/catalina.out
|
||||
|
||||
[monit]
|
||||
#Ban clients brute-forcing the monit gui login
|
||||
port = 2812
|
||||
logpath = /var/log/monit
|
||||
|
||||
|
||||
[webmin-auth]
|
||||
|
||||
port = 10000
|
||||
logpath = %(syslog_authpriv)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[froxlor-auth]
|
||||
|
||||
port = http,https
|
||||
logpath = %(syslog_authpriv)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
#
|
||||
# HTTP Proxy servers
|
||||
#
|
||||
#
|
||||
|
||||
[squid]
|
||||
|
||||
port = 80,443,3128,8080
|
||||
logpath = /var/log/squid/access.log
|
||||
|
||||
|
||||
[3proxy]
|
||||
|
||||
port = 3128
|
||||
logpath = /var/log/3proxy.log
|
||||
|
||||
|
||||
#
|
||||
# FTP servers
|
||||
#
|
||||
|
||||
|
||||
[proftpd]
|
||||
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
logpath = %(proftpd_log)s
|
||||
backend = %(proftpd_backend)s
|
||||
|
||||
|
||||
[pure-ftpd]
|
||||
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
logpath = %(pureftpd_log)s
|
||||
backend = %(pureftpd_backend)s
|
||||
|
||||
|
||||
[gssftpd]
|
||||
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
logpath = %(syslog_daemon)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[wuftpd]
|
||||
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
logpath = %(wuftpd_log)s
|
||||
backend = %(wuftpd_backend)s
|
||||
|
||||
|
||||
[vsftpd]
|
||||
# or overwrite it in jails.local to be
|
||||
# logpath = %(syslog_authpriv)s
|
||||
# if you want to rely on PAM failed login attempts
|
||||
# vsftpd's failregex should match both of those formats
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
logpath = %(vsftpd_log)s
|
||||
|
||||
|
||||
#
|
||||
# Mail servers
|
||||
#
|
||||
|
||||
# ASSP SMTP Proxy Jail
|
||||
[assp]
|
||||
|
||||
port = smtp,465,submission
|
||||
logpath = /root/path/to/assp/logs/maillog.txt
|
||||
|
||||
|
||||
[courier-smtp]
|
||||
|
||||
port = smtp,465,submission
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[postfix]
|
||||
|
||||
port = smtp,465,submission
|
||||
logpath = %(postfix_log)s
|
||||
backend = %(postfix_backend)s
|
||||
|
||||
|
||||
[postfix-rbl]
|
||||
|
||||
port = smtp,465,submission
|
||||
logpath = %(postfix_log)s
|
||||
backend = %(postfix_backend)s
|
||||
maxretry = 1
|
||||
|
||||
|
||||
[sendmail-auth]
|
||||
|
||||
port = submission,465,smtp
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[sendmail-reject]
|
||||
|
||||
port = smtp,465,submission
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[qmail-rbl]
|
||||
|
||||
filter = qmail
|
||||
port = smtp,465,submission
|
||||
logpath = /service/qmail/log/main/current
|
||||
|
||||
|
||||
# dovecot defaults to logging to the mail syslog facility
|
||||
# but can be set by syslog_facility in the dovecot configuration.
|
||||
[dovecot]
|
||||
|
||||
port = pop3,pop3s,imap,imaps,submission,465,sieve
|
||||
logpath = %(dovecot_log)s
|
||||
backend = %(dovecot_backend)s
|
||||
|
||||
|
||||
[sieve]
|
||||
|
||||
port = smtp,465,submission
|
||||
logpath = %(dovecot_log)s
|
||||
backend = %(dovecot_backend)s
|
||||
|
||||
|
||||
[solid-pop3d]
|
||||
|
||||
port = pop3,pop3s
|
||||
logpath = %(solidpop3d_log)s
|
||||
|
||||
|
||||
[exim]
|
||||
|
||||
port = smtp,465,submission
|
||||
logpath = %(exim_main_log)s
|
||||
|
||||
|
||||
[exim-spam]
|
||||
|
||||
port = smtp,465,submission
|
||||
logpath = %(exim_main_log)s
|
||||
|
||||
|
||||
[kerio]
|
||||
|
||||
port = imap,smtp,imaps,465
|
||||
logpath = /opt/kerio/mailserver/store/logs/security.log
|
||||
|
||||
|
||||
#
|
||||
# Mail servers authenticators: might be used for smtp,ftp,imap servers, so
|
||||
# all relevant ports get banned
|
||||
#
|
||||
|
||||
[courier-auth]
|
||||
|
||||
port = smtp,465,submission,imap3,imaps,pop3,pop3s
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[postfix-sasl]
|
||||
|
||||
port = smtp,465,submission,imap3,imaps,pop3,pop3s
|
||||
# You might consider monitoring /var/log/mail.warn instead if you are
|
||||
# running postfix since it would provide the same log lines at the
|
||||
# "warn" level but overall at the smaller filesize.
|
||||
logpath = %(postfix_log)s
|
||||
backend = %(postfix_backend)s
|
||||
|
||||
|
||||
[perdition]
|
||||
|
||||
port = imap3,imaps,pop3,pop3s
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[squirrelmail]
|
||||
|
||||
port = smtp,465,submission,imap2,imap3,imaps,pop3,pop3s,http,https,socks
|
||||
logpath = /var/lib/squirrelmail/prefs/squirrelmail_access_log
|
||||
|
||||
|
||||
[cyrus-imap]
|
||||
|
||||
port = imap3,imaps
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[uwimap-auth]
|
||||
|
||||
port = imap3,imaps
|
||||
logpath = %(syslog_mail)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
# DNS servers
|
||||
#
|
||||
|
||||
|
||||
# !!! WARNING !!!
|
||||
# Since UDP is connection-less protocol, spoofing of IP and imitation
|
||||
# of illegal actions is way too simple. Thus enabling of this filter
|
||||
# might provide an easy way for implementing a DoS against a chosen
|
||||
# victim. See
|
||||
# http://nion.modprobe.de/blog/archives/690-fail2ban-+-dns-fail.html
|
||||
# Please DO NOT USE this jail unless you know what you are doing.
|
||||
#
|
||||
# IMPORTANT: see filter.d/named-refused for instructions to enable logging
|
||||
# This jail blocks UDP traffic for DNS requests.
|
||||
# [named-refused-udp]
|
||||
#
|
||||
# filter = named-refused
|
||||
# port = domain,953
|
||||
# protocol = udp
|
||||
# logpath = /var/log/named/security.log
|
||||
|
||||
# IMPORTANT: see filter.d/named-refused for instructions to enable logging
|
||||
# This jail blocks TCP traffic for DNS requests.
|
||||
|
||||
[named-refused]
|
||||
|
||||
port = domain,953
|
||||
logpath = /var/log/named/security.log
|
||||
|
||||
|
||||
[nsd]
|
||||
|
||||
port = 53
|
||||
action = %(banaction)s[name=%(__name__)s-tcp, port="%(port)s", protocol="tcp", chain="%(chain)s", actname=%(banaction)s-tcp]
|
||||
%(banaction)s[name=%(__name__)s-udp, port="%(port)s", protocol="udp", chain="%(chain)s", actname=%(banaction)s-udp]
|
||||
logpath = /var/log/nsd.log
|
||||
|
||||
|
||||
#
|
||||
# Miscellaneous
|
||||
#
|
||||
|
||||
[asterisk]
|
||||
|
||||
port = 5060,5061
|
||||
action = %(banaction)s[name=%(__name__)s-tcp, port="%(port)s", protocol="tcp", chain="%(chain)s", actname=%(banaction)s-tcp]
|
||||
%(banaction)s[name=%(__name__)s-udp, port="%(port)s", protocol="udp", chain="%(chain)s", actname=%(banaction)s-udp]
|
||||
%(mta)s-whois[name=%(__name__)s, dest="%(destemail)s"]
|
||||
logpath = /var/log/asterisk/messages
|
||||
maxretry = 10
|
||||
|
||||
|
||||
[freeswitch]
|
||||
|
||||
port = 5060,5061
|
||||
action = %(banaction)s[name=%(__name__)s-tcp, port="%(port)s", protocol="tcp", chain="%(chain)s", actname=%(banaction)s-tcp]
|
||||
%(banaction)s[name=%(__name__)s-udp, port="%(port)s", protocol="udp", chain="%(chain)s", actname=%(banaction)s-udp]
|
||||
%(mta)s-whois[name=%(__name__)s, dest="%(destemail)s"]
|
||||
logpath = /var/log/freeswitch.log
|
||||
maxretry = 10
|
||||
|
||||
|
||||
# To log wrong MySQL access attempts add to /etc/my.cnf in [mysqld] or
|
||||
# equivalent section:
|
||||
# log-warning = 2
|
||||
#
|
||||
# for syslog (daemon facility)
|
||||
# [mysqld_safe]
|
||||
# syslog
|
||||
#
|
||||
# for own logfile
|
||||
# [mysqld]
|
||||
# log-error=/var/log/mysqld.log
|
||||
[mysqld-auth]
|
||||
|
||||
port = 3306
|
||||
logpath = %(mysql_log)s
|
||||
backend = %(mysql_backend)s
|
||||
|
||||
|
||||
# Log wrong MongoDB auth (for details see filter 'filter.d/mongodb-auth.conf')
|
||||
[mongodb-auth]
|
||||
# change port when running with "--shardsvr" or "--configsvr" runtime operation
|
||||
port = 27017
|
||||
logpath = /var/log/mongodb/mongodb.log
|
||||
|
||||
|
||||
# Jail for more extended banning of persistent abusers
|
||||
# !!! WARNINGS !!!
|
||||
# 1. Make sure that your loglevel specified in fail2ban.conf/.local
|
||||
# is not at DEBUG level -- which might then cause fail2ban to fall into
|
||||
# an infinite loop constantly feeding itself with non-informative lines
|
||||
# 2. Increase dbpurgeage defined in fail2ban.conf to e.g. 648000 (7.5 days)
|
||||
# to maintain entries for failed logins for sufficient amount of time
|
||||
[recidive]
|
||||
|
||||
logpath = /var/log/fail2ban.log
|
||||
banaction = %(banaction_allports)s
|
||||
bantime = 604800 ; 1 week
|
||||
findtime = 86400 ; 1 day
|
||||
|
||||
|
||||
# Generic filter for PAM. Has to be used with action which bans all
|
||||
# ports such as iptables-allports, shorewall
|
||||
|
||||
[pam-generic]
|
||||
# pam-generic filter can be customized to monitor specific subset of 'tty's
|
||||
banaction = %(banaction_allports)s
|
||||
logpath = %(syslog_authpriv)s
|
||||
backend = %(syslog_backend)s
|
||||
|
||||
|
||||
[xinetd-fail]
|
||||
|
||||
banaction = iptables-multiport-log
|
||||
logpath = %(syslog_daemon)s
|
||||
backend = %(syslog_backend)s
|
||||
maxretry = 2
|
||||
|
||||
|
||||
# stunnel - need to set port for this
|
||||
[stunnel]
|
||||
|
||||
logpath = /var/log/stunnel4/stunnel.log
|
||||
|
||||
|
||||
[ejabberd-auth]
|
||||
|
||||
port = 5222
|
||||
logpath = /var/log/ejabberd/ejabberd.log
|
||||
|
||||
|
||||
[counter-strike]
|
||||
|
||||
logpath = /opt/cstrike/logs/L[0-9]*.log
|
||||
# Firewall: http://www.cstrike-planet.com/faq/6
|
||||
tcpport = 27030,27031,27032,27033,27034,27035,27036,27037,27038,27039
|
||||
udpport = 1200,27000,27001,27002,27003,27004,27005,27006,27007,27008,27009,27010,27011,27012,27013,27014,27015
|
||||
action = %(banaction)s[name=%(__name__)s-tcp, port="%(tcpport)s", protocol="tcp", chain="%(chain)s", actname=%(banaction)s-tcp]
|
||||
%(banaction)s[name=%(__name__)s-udp, port="%(udpport)s", protocol="udp", chain="%(chain)s", actname=%(banaction)s-udp]
|
||||
|
||||
# consider low maxretry and a long bantime
|
||||
# nobody except your own Nagios server should ever probe nrpe
|
||||
[nagios]
|
||||
|
||||
logpath = %(syslog_daemon)s ; nrpe.cfg may define a different log_facility
|
||||
backend = %(syslog_backend)s
|
||||
maxretry = 1
|
||||
|
||||
|
||||
[oracleims]
|
||||
# see "oracleims" filter file for configuration requirement for Oracle IMS v6 and above
|
||||
logpath = /opt/sun/comms/messaging64/log/mail.log_current
|
||||
banaction = %(banaction_allports)s
|
||||
|
||||
[directadmin]
|
||||
logpath = /var/log/directadmin/login.log
|
||||
port = 2222
|
||||
|
||||
[portsentry]
|
||||
logpath = /var/lib/portsentry/portsentry.history
|
||||
maxretry = 1
|
||||
|
||||
[pass2allow-ftp]
|
||||
# this pass2allow example allows FTP traffic after successful HTTP authentication
|
||||
port = ftp,ftp-data,ftps,ftps-data
|
||||
# knocking_url variable must be overridden to some secret value in jail.local
|
||||
knocking_url = /knocking/
|
||||
filter = apache-pass[knocking_url="%(knocking_url)s"]
|
||||
# access log of the website with HTTP auth
|
||||
logpath = %(apache_access_log)s
|
||||
blocktype = RETURN
|
||||
returntype = DROP
|
||||
bantime = 3600
|
||||
maxretry = 1
|
||||
findtime = 1
|
||||
|
||||
|
||||
[murmur]
|
||||
# AKA mumble-server
|
||||
port = 64738
|
||||
action = %(banaction)s[name=%(__name__)s-tcp, port="%(port)s", protocol=tcp, chain="%(chain)s", actname=%(banaction)s-tcp]
|
||||
%(banaction)s[name=%(__name__)s-udp, port="%(port)s", protocol=udp, chain="%(chain)s", actname=%(banaction)s-udp]
|
||||
logpath = /var/log/mumble-server/mumble-server.log
|
||||
|
||||
|
||||
[screensharingd]
|
||||
# For Mac OS Screen Sharing Service (VNC)
|
||||
logpath = /var/log/system.log
|
||||
logencoding = utf-8
|
||||
|
||||
[haproxy-http-auth]
|
||||
# HAProxy by default doesn't log to file you'll need to set it up to forward
|
||||
# logs to a syslog server which would then write them to disk.
|
||||
# See "haproxy-http-auth" filter for a brief cautionary note when setting
|
||||
# maxretry and findtime.
|
||||
logpath = /var/log/haproxy.log
|
||||
|
||||
[slapd]
|
||||
port = ldap,ldaps
|
||||
filter = slapd
|
||||
logpath = /var/log/slapd.log
|
17
rootfs/free/etc/log2ram.conf
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Configuration file for Log2Ram (https://github.com/azlux/log2ram) under MIT license.
|
||||
# This configuration file is read by the log2ram service
|
||||
|
||||
# Size for the ram folder, it defines the size the log folder will reserve into the RAM.
|
||||
# If it's not enough, log2ram will not be able to use ram. Check you /var/log size folder.
|
||||
# The default is 40M and is basically enough for a lot of applications.
|
||||
# You will need to increase it if you have a server and a lot of log for example.
|
||||
SIZE=100M
|
||||
|
||||
# This variable can be set to true if you prefer "rsync" rather than "cp".
|
||||
# I use the command cp -u and rsync -X, so I don't copy the all folder every time for optimization.
|
||||
# You can choose which one you want. Be sure rsync is installed if you use it.
|
||||
USE_RSYNC=false
|
||||
|
||||
# If there are some errors with available RAM space, a system mail will be send
|
||||
# Change it to false and you will have only a log if there is no place on RAM anymore.
|
||||
MAIL=true
|
33
rootfs/free/etc/logrotate.conf
Normal file
|
@ -0,0 +1,33 @@
|
|||
# see "man logrotate" for details
|
||||
# rotate log files daily
|
||||
daily
|
||||
|
||||
# keep 3 days worth of backlogs as long as daily size is less than 3 MB
|
||||
rotate 3
|
||||
maxsize 3M
|
||||
|
||||
# create new (empty) log files after rotating old ones
|
||||
create
|
||||
|
||||
# uncomment this if you want your log files compressed
|
||||
#compress
|
||||
|
||||
# packages drop log rotation information into this directory
|
||||
include /etc/logrotate.d
|
||||
|
||||
# no packages own wtmp, or btmp -- we'll rotate them here
|
||||
/var/log/wtmp {
|
||||
missingok
|
||||
monthly
|
||||
create 0664 root utmp
|
||||
rotate 1
|
||||
}
|
||||
|
||||
/var/log/btmp {
|
||||
missingok
|
||||
monthly
|
||||
create 0660 root utmp
|
||||
rotate 1
|
||||
}
|
||||
|
||||
# system-specific logs may be configured here
|
48
rootfs/free/etc/logrotate.d/rsyslog
Normal file
|
@ -0,0 +1,48 @@
|
|||
/var/log/syslog
|
||||
/var/log/electrs.log
|
||||
/var/log/flask
|
||||
/var/log/lndhub.log
|
||||
/var/log/lnd.log
|
||||
/var/log/lnd_backup.log
|
||||
/var/log/log2ram.log
|
||||
/var/log/mynode.log
|
||||
/var/log/mynode_quicksync.log
|
||||
/var/log/redis-server.log
|
||||
/var/log/rtl.log
|
||||
/var/log/www.log
|
||||
/var/log/*
|
||||
{
|
||||
rotate 3
|
||||
daily
|
||||
maxsize 3M
|
||||
missingok
|
||||
notifempty
|
||||
postrotate
|
||||
invoke-rc.d rsyslog rotate > /dev/null
|
||||
endscript
|
||||
}
|
||||
|
||||
/var/log/mail.info
|
||||
/var/log/mail.warn
|
||||
/var/log/mail.err
|
||||
/var/log/mail.log
|
||||
/var/log/daemon.log
|
||||
/var/log/kern.log
|
||||
/var/log/auth.log
|
||||
/var/log/user.log
|
||||
/var/log/lpr.log
|
||||
/var/log/cron.log
|
||||
/var/log/debug
|
||||
/var/log/messages
|
||||
{
|
||||
rotate 3
|
||||
daily
|
||||
maxsize 3M
|
||||
missingok
|
||||
notifempty
|
||||
delaycompress
|
||||
sharedscripts
|
||||
postrotate
|
||||
invoke-rc.d rsyslog rotate > /dev/null
|
||||
endscript
|
||||
}
|
0
rootfs/free/etc/motd
Normal file
30
rootfs/free/etc/pam.d/common-session
Normal file
|
@ -0,0 +1,30 @@
|
|||
#
|
||||
# /etc/pam.d/common-session - session-related modules common to all services
|
||||
#
|
||||
# This file is included from other service-specific PAM config files,
|
||||
# and should contain a list of modules that define tasks to be performed
|
||||
# at the start and end of sessions of *any* kind (both interactive and
|
||||
# non-interactive).
|
||||
#
|
||||
# As of pam 1.0.1-6, this file is managed by pam-auth-update by default.
|
||||
# To take advantage of this, it is recommended that you configure any
|
||||
# local modules either before or after the default block, and use
|
||||
# pam-auth-update to manage selection of other modules. See
|
||||
# pam-auth-update(8) for details.
|
||||
|
||||
# here are the per-package modules (the "Primary" block)
|
||||
session [default=1] pam_permit.so
|
||||
# here's the fallback if no module succeeds
|
||||
session requisite pam_deny.so
|
||||
# prime the stack with a positive return value if there isn't one already;
|
||||
# this avoids us returning an error just because nothing sets a success code
|
||||
# since the modules above will each just jump around
|
||||
session required pam_permit.so
|
||||
# and here are more per-package modules (the "Additional" block)
|
||||
session required pam_unix.so
|
||||
session optional pam_systemd.so
|
||||
session optional pam_chksshpwd.so
|
||||
|
||||
session required pam_limits.so
|
||||
|
||||
# end of pam-auth-update config
|
28
rootfs/free/etc/pam.d/common-session-noninteractive
Normal file
|
@ -0,0 +1,28 @@
|
|||
#
|
||||
# /etc/pam.d/common-session-noninteractive - session-related modules
|
||||
# common to all non-interactive services
|
||||
#
|
||||
# This file is included from other service-specific PAM config files,
|
||||
# and should contain a list of modules that define tasks to be performed
|
||||
# at the start and end of all non-interactive sessions.
|
||||
#
|
||||
# As of pam 1.0.1-6, this file is managed by pam-auth-update by default.
|
||||
# To take advantage of this, it is recommended that you configure any
|
||||
# local modules either before or after the default block, and use
|
||||
# pam-auth-update to manage selection of other modules. See
|
||||
# pam-auth-update(8) for details.
|
||||
|
||||
# here are the per-package modules (the "Primary" block)
|
||||
session [default=1] pam_permit.so
|
||||
# here's the fallback if no module succeeds
|
||||
session requisite pam_deny.so
|
||||
# prime the stack with a positive return value if there isn't one already;
|
||||
# this avoids us returning an error just because nothing sets a success code
|
||||
# since the modules above will each just jump around
|
||||
session required pam_permit.so
|
||||
# and here are more per-package modules (the "Additional" block)
|
||||
session required pam_unix.so
|
||||
|
||||
session required pam_limits.so
|
||||
|
||||
# end of pam-auth-update config
|
13
rootfs/free/etc/resolvconf.conf
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Configuration for resolvconf(8)
|
||||
# See resolvconf.conf(5) for details
|
||||
|
||||
resolv_conf=/etc/resolv.conf
|
||||
# If you run a local name server, you should uncomment the below line and
|
||||
# configure your subscribers configuration files below.
|
||||
name_servers="8.8.8.8 8.8.4.4 1.1.1.1"
|
||||
|
||||
# Mirror the Debian package defaults for the below resolvers
|
||||
# so that resolvconf integrates seemlessly.
|
||||
dnsmasq_resolv=/var/run/dnsmasq/resolv.conf
|
||||
pdnsd_conf=/etc/pdnsd.conf
|
||||
unbound_conf=/var/cache/unbound/resolvconf_resolvers.conf
|
2
rootfs/free/etc/rsyslog.d/bitcoind.conf
Normal file
|
@ -0,0 +1,2 @@
|
|||
if $programname == 'bitcoind' then /var/log/bitcoind.log
|
||||
& stop
|
2
rootfs/free/etc/rsyslog.d/lnd.conf
Normal file
|
@ -0,0 +1,2 @@
|
|||
if $programname == 'lnd' then /var/log/lnd.log
|
||||
& stop
|
2
rootfs/free/etc/rsyslog.d/lndbackup.conf
Normal file
|
@ -0,0 +1,2 @@
|
|||
if $programname == 'lndbackup' then /var/log/lnd_backup.log
|
||||
& stop
|
2
rootfs/free/etc/rsyslog.d/mynode.conf
Normal file
|
@ -0,0 +1,2 @@
|
|||
if $programname == 'mynode' then /var/log/mynode.log
|
||||
& stop
|
6
rootfs/free/etc/rsyslog.d/mynode_quicksync.conf
Normal file
|
@ -0,0 +1,6 @@
|
|||
if $programname == 'mynode_quicksync' and $msg contains 'Seeding, uploading to' then ~
|
||||
& stop
|
||||
if $programname == 'mynode_quicksync' and $msg contains 'Progress:' then ~
|
||||
& stop
|
||||
if $programname == 'mynode_quicksync' then /var/log/mynode_quicksync.log
|
||||
& stop
|
2
rootfs/free/etc/rsyslog.d/www.conf
Normal file
|
@ -0,0 +1,2 @@
|
|||
if $programname == 'www' then /var/log/www.log
|
||||
& stop
|
62
rootfs/free/etc/security/limits.conf
Normal file
|
@ -0,0 +1,62 @@
|
|||
# /etc/security/limits.conf
|
||||
#
|
||||
#Each line describes a limit for a user in the form:
|
||||
#
|
||||
#<domain> <type> <item> <value>
|
||||
#
|
||||
#Where:
|
||||
#<domain> can be:
|
||||
# - a user name
|
||||
# - a group name, with @group syntax
|
||||
# - the wildcard *, for default entry
|
||||
# - the wildcard %, can be also used with %group syntax,
|
||||
# for maxlogin limit
|
||||
# - NOTE: group and wildcard limits are not applied to root.
|
||||
# To apply a limit to the root user, <domain> must be
|
||||
# the literal username root.
|
||||
#
|
||||
#<type> can have the two values:
|
||||
# - "soft" for enforcing the soft limits
|
||||
# - "hard" for enforcing hard limits
|
||||
#
|
||||
#<item> can be one of the following:
|
||||
# - core - limits the core file size (KB)
|
||||
# - data - max data size (KB)
|
||||
# - fsize - maximum filesize (KB)
|
||||
# - memlock - max locked-in-memory address space (KB)
|
||||
# - nofile - max number of open files
|
||||
# - rss - max resident set size (KB)
|
||||
# - stack - max stack size (KB)
|
||||
# - cpu - max CPU time (MIN)
|
||||
# - nproc - max number of processes
|
||||
# - as - address space limit (KB)
|
||||
# - maxlogins - max number of logins for this user
|
||||
# - maxsyslogins - max number of logins on the system
|
||||
# - priority - the priority to run user process with
|
||||
# - locks - max number of file locks the user can hold
|
||||
# - sigpending - max number of pending signals
|
||||
# - msgqueue - max memory used by POSIX message queues (bytes)
|
||||
# - nice - max nice priority allowed to raise to values: [-20, 19]
|
||||
# - rtprio - max realtime priority
|
||||
# - chroot - change root to directory (Debian-specific)
|
||||
#
|
||||
#<domain> <type> <item> <value>
|
||||
#
|
||||
|
||||
#* soft core 0
|
||||
#root hard core 100000
|
||||
#* hard rss 10000
|
||||
#@student hard nproc 20
|
||||
#@faculty soft nproc 20
|
||||
#@faculty hard nproc 50
|
||||
#ftp hard nproc 0
|
||||
#ftp - chroot /ftp
|
||||
#@student - maxlogins 4
|
||||
|
||||
|
||||
* soft nofile 128000
|
||||
* hard nofile 128000
|
||||
root soft nofile 128000
|
||||
root hard nofile 128000
|
||||
|
||||
# End of file
|
80
rootfs/free/etc/sysctl.conf
Normal file
|
@ -0,0 +1,80 @@
|
|||
#
|
||||
# /etc/sysctl.conf - Configuration file for setting system variables
|
||||
# See /etc/sysctl.d/ for additional system variables.
|
||||
# See sysctl.conf (5) for information.
|
||||
#
|
||||
|
||||
#kernel.domainname = example.com
|
||||
|
||||
# Uncomment the following to stop low-level messages on console
|
||||
#kernel.printk = 3 4 1 3
|
||||
|
||||
##############################################################3
|
||||
# Functions previously found in netbase
|
||||
#
|
||||
|
||||
# Uncomment the next two lines to enable Spoof protection (reverse-path filter)
|
||||
# Turn on Source Address Verification in all interfaces to
|
||||
# prevent some spoofing attacks
|
||||
#net.ipv4.conf.default.rp_filter=1
|
||||
#net.ipv4.conf.all.rp_filter=1
|
||||
|
||||
# Uncomment the next line to enable TCP/IP SYN cookies
|
||||
# See http://lwn.net/Articles/277146/
|
||||
# Note: This may impact IPv6 TCP sessions too
|
||||
#net.ipv4.tcp_syncookies=1
|
||||
|
||||
# Uncomment the next line to enable packet forwarding for IPv4
|
||||
#net.ipv4.ip_forward=1
|
||||
|
||||
# Uncomment the next line to enable packet forwarding for IPv6
|
||||
# Enabling this option disables Stateless Address Autoconfiguration
|
||||
# based on Router Advertisements for this host
|
||||
#net.ipv6.conf.all.forwarding=1
|
||||
|
||||
|
||||
###################################################################
|
||||
# Additional settings - these settings can improve the network
|
||||
# security of the host and prevent against some network attacks
|
||||
# including spoofing attacks and man in the middle attacks through
|
||||
# redirection. Some network environments, however, require that these
|
||||
# settings are disabled so review and enable them as needed.
|
||||
#
|
||||
# Do not accept ICMP redirects (prevent MITM attacks)
|
||||
#net.ipv4.conf.all.accept_redirects = 0
|
||||
#net.ipv6.conf.all.accept_redirects = 0
|
||||
# _or_
|
||||
# Accept ICMP redirects only for gateways listed in our default
|
||||
# gateway list (enabled by default)
|
||||
# net.ipv4.conf.all.secure_redirects = 1
|
||||
#
|
||||
# Do not send ICMP redirects (we are not a router)
|
||||
#net.ipv4.conf.all.send_redirects = 0
|
||||
#
|
||||
# Do not accept IP source route packets (we are not a router)
|
||||
#net.ipv4.conf.all.accept_source_route = 0
|
||||
#net.ipv6.conf.all.accept_source_route = 0
|
||||
#
|
||||
# Log Martian Packets
|
||||
#net.ipv4.conf.all.log_martians = 1
|
||||
#
|
||||
|
||||
###################################################################
|
||||
# Magic system request Key
|
||||
# 0=disable, 1=enable all
|
||||
# Debian kernels have this set to 0 (disable the key)
|
||||
# See https://www.kernel.org/doc/Documentation/sysrq.txt
|
||||
# for what other values do
|
||||
#kernel.sysrq=1
|
||||
|
||||
###################################################################
|
||||
# Protected links
|
||||
#
|
||||
# Protects against creating or following links under certain conditions
|
||||
# Debian kernels have both set to 1 (restricted)
|
||||
# See https://www.kernel.org/doc/Documentation/sysctl/fs.txt
|
||||
#fs.protected_hardlinks=0
|
||||
#fs.protected_symlinks=0
|
||||
|
||||
# Disable IPv6
|
||||
net.ipv6.conf.all.disable_ipv6 = 1
|
22
rootfs/free/etc/systemd/system/bandwidth.service
Normal file
|
@ -0,0 +1,22 @@
|
|||
# myNode Bandwidth Management
|
||||
# /etc/systemd/system/bandwidth.service
|
||||
|
||||
[Unit]
|
||||
Description=myNode Bandwidth Management
|
||||
Wants=quicksync.service
|
||||
After=quicksync.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
KillMode=control-group
|
||||
ExecStart=/usr/bin/mynode_bandwidth.sh
|
||||
User=bitcoin
|
||||
Group=bitcoin
|
||||
StandardOutput=syslog
|
||||
StandardError=syslog
|
||||
SyslogIdentifier=mynode_quicksync
|
||||
Restart=always
|
||||
RestartSec=30
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
25
rootfs/free/etc/systemd/system/bitcoind.service
Normal file
|
@ -0,0 +1,25 @@
|
|||
# bitcoind service
|
||||
# /etc/systemd/system/bitcoind.service
|
||||
|
||||
[Unit]
|
||||
Description=Bitcoin daemon
|
||||
After=network.target mynode.service
|
||||
|
||||
[Service]
|
||||
ExecStartPre=/bin/sh -c 'cat /mnt/hdd/mynode/quicksync/.quicksync_complete'
|
||||
EnvironmentFile=/mnt/hdd/mynode/bitcoin/env
|
||||
ExecStart=/usr/local/bin/bitcoind -daemon $BTCARGS -deprecatedrpc=accounts -par=-1 -conf=/home/bitcoin/.bitcoin/bitcoin.conf -printtoconsole -pid=/home/bitcoin/.bitcoin/bitcoind.pid
|
||||
PIDFile=/home/bitcoin/.bitcoin/bitcoind.pid
|
||||
User=bitcoin
|
||||
Group=bitcoin
|
||||
Type=forking
|
||||
KillMode=process
|
||||
Restart=always
|
||||
TimeoutSec=300
|
||||
RestartSec=30
|
||||
StandardOutput=syslog
|
||||
StandardError=syslog
|
||||
SyslogIdentifier=bitcoind
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
20
rootfs/free/etc/systemd/system/drive_check.service
Normal file
|
@ -0,0 +1,20 @@
|
|||
# myNode www service
|
||||
# /etc/systemd/system/www.service
|
||||
|
||||
[Unit]
|
||||
Description=myNode Drive Check
|
||||
Wants=mynode.service
|
||||
After=mynode.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
KillMode=process
|
||||
TimeoutSec=30
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
ExecStart=/usr/bin/drive_check.sh
|
||||
User=root
|
||||
Group=root
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
28
rootfs/free/etc/systemd/system/lnd.service
Normal file
|
@ -0,0 +1,28 @@
|
|||
# lnd service
|
||||
# /etc/systemd/system/lnd.service
|
||||
|
||||
[Unit]
|
||||
Description=LND Lightning Daemon
|
||||
Wants=bitcoind.service
|
||||
After=bitcoind.service
|
||||
|
||||
[Service]
|
||||
ExecStartPre=/usr/bin/pre_lnd.sh
|
||||
ExecStartPre=/usr/bin/wait_on_bitcoin.sh
|
||||
ExecStart=/usr/local/bin/lnd
|
||||
#ExecStartPost=/usr/bin/unlock_lnd.sh
|
||||
|
||||
User=bitcoin
|
||||
Group=bitcoin
|
||||
Type=simple
|
||||
KillMode=control-group
|
||||
LimitNOFILE=128000
|
||||
TimeoutSec=240
|
||||
Restart=always
|
||||
RestartSec=1
|
||||
StandardOutput=syslog
|
||||
StandardError=syslog
|
||||
SyslogIdentifier=lnd
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
21
rootfs/free/etc/systemd/system/lnd_admin_files.service
Normal file
|
@ -0,0 +1,21 @@
|
|||
# myNode LND Admin Files
|
||||
# /etc/systemd/system/lnd_admin_files.service
|
||||
|
||||
[Unit]
|
||||
Description=Copy LND Admin Files
|
||||
Wants=lnd.service
|
||||
After=lnd.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/bin/mynode_lnd_admin_files.sh
|
||||
Restart=always
|
||||
RestartSec=1
|
||||
User=root
|
||||
Group=root
|
||||
StandardOutput=syslog
|
||||
StandardError=syslog
|
||||
SyslogIdentifier=lndbackup
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
21
rootfs/free/etc/systemd/system/lnd_unlock.service
Normal file
|
@ -0,0 +1,21 @@
|
|||
# myNode Unlock LND
|
||||
# /etc/systemd/system/lnd_unlock.service
|
||||
|
||||
[Unit]
|
||||
Description=Post LND Unlock
|
||||
Wants=lnd.service
|
||||
After=lnd.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/bin/unlock_lnd.sh
|
||||
User=bitcoin
|
||||
Group=bitcoin
|
||||
StandardOutput=syslog
|
||||
StandardError=syslog
|
||||
SyslogIdentifier=lnd
|
||||
Restart=always
|
||||
RestartSec=1
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
22
rootfs/free/etc/systemd/system/mynode.service
Normal file
|
@ -0,0 +1,22 @@
|
|||
# myNode start service
|
||||
# /etc/systemd/system/mynode.service
|
||||
|
||||
[Unit]
|
||||
Description=myNode Startup
|
||||
Wants=network-online.target
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/mynode_startup.sh
|
||||
User=root
|
||||
Group=root
|
||||
StandardOutput=syslog
|
||||
StandardError=syslog
|
||||
SyslogIdentifier=mynode
|
||||
|
||||
RestartSec=30
|
||||
RemainAfterExit=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
23
rootfs/free/etc/systemd/system/quicksync.service
Normal file
|
@ -0,0 +1,23 @@
|
|||
# myNode QuickSync Service
|
||||
# /etc/systemd/system/quicksync.service
|
||||
|
||||
[Unit]
|
||||
Description=myNode QuickSync
|
||||
Wants=mynode.service
|
||||
After=mynode.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
KillMode=control-group
|
||||
TimeoutSec=60
|
||||
Restart=always
|
||||
RestartSec=30
|
||||
ExecStart=/usr/bin/mynode_quicksync.sh
|
||||
User=bitcoin
|
||||
Group=bitcoin
|
||||
StandardOutput=syslog
|
||||
StandardError=syslog
|
||||
SyslogIdentifier=mynode_quicksync
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
20
rootfs/free/etc/systemd/system/torrent_check.service
Normal file
|
@ -0,0 +1,20 @@
|
|||
# myNode torrent_check service
|
||||
# /etc/systemd/system/torrent_check.service
|
||||
|
||||
[Unit]
|
||||
Description=myNode Torrent Check
|
||||
Wants=mynode.service
|
||||
After=mynode.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
KillMode=process
|
||||
TimeoutSec=30
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
ExecStart=/usr/bin/mynode_torrent_check.sh
|
||||
User=root
|
||||
Group=root
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
23
rootfs/free/etc/systemd/system/www.service
Normal file
|
@ -0,0 +1,23 @@
|
|||
# myNode www service
|
||||
# /etc/systemd/system/www.service
|
||||
|
||||
[Unit]
|
||||
Description=myNode Web Server
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
KillMode=mixed
|
||||
KillSignal=2
|
||||
TimeoutSec=30
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
ExecStart=/usr/bin/python /var/www/mynode/mynode.py
|
||||
User=root
|
||||
Group=root
|
||||
StandardOutput=syslog
|
||||
StandardError=syslog
|
||||
SyslogIdentifier=www
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
10
rootfs/free/etc/update-motd.d/10-mynode-header
Executable file
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
|
||||
THIS_SCRIPT="header"
|
||||
MOTD_DISABLE=""
|
||||
|
||||
toilet -f standard -F metal "myNode Free"
|
||||
|
||||
printf '\nWelcome to myNode!\n'
|
||||
uname -a
|
||||
printf '\n'
|
197
rootfs/free/etc/update-motd.d/30-mynode-sysinfo
Executable file
|
@ -0,0 +1,197 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright (c) Authors: http://www.armbian.com/authors
|
||||
#
|
||||
# This file is licensed under the terms of the GNU General Public
|
||||
# License version 2. This program is licensed "as is" without any
|
||||
# warranty of any kind, whether express or implied.
|
||||
#
|
||||
|
||||
# DO NOT EDIT THIS FILE but add config options to /etc/default/armbian-motd
|
||||
# generate system information
|
||||
|
||||
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
|
||||
THIS_SCRIPT="sysinfo"
|
||||
MOTD_DISABLE=""
|
||||
STORAGE=/dev/sda1
|
||||
SHOW_IP_PATTERN="^[ewr].*|^br.*|^lt.*|^umts.*"
|
||||
|
||||
[[ -f /etc/default/armbian-motd ]] && . /etc/default/armbian-motd
|
||||
|
||||
for f in $MOTD_DISABLE; do
|
||||
[[ $f == $THIS_SCRIPT ]] && exit 0
|
||||
done
|
||||
|
||||
# don't edit below here
|
||||
|
||||
function display() {
|
||||
# $1=name $2=value $3=red_limit $4=minimal_show_limit $5=unit $6=after $7=acs/desc{
|
||||
# battery red color is opposite, lower number
|
||||
if [[ "$1" == "Battery" ]]; then local great="<"; else local great=">"; fi
|
||||
if [[ -n "$2" && "$2" > "0" && (( "${2%.*}" -ge "$4" )) ]]; then
|
||||
printf "%-14s%s" "$1:"
|
||||
if awk "BEGIN{exit ! ($2 $great $3)}"; then echo -ne "\e[0;91m $2"; else echo -ne "\e[0;92m $2"; fi
|
||||
printf "%-1s%s\x1B[0m" "$5"
|
||||
printf "%-11s%s\t" "$6"
|
||||
return 1
|
||||
fi
|
||||
} # display
|
||||
|
||||
function getboardtemp() {
|
||||
if [ -f /etc/armbianmonitor/datasources/soctemp ]; then
|
||||
read raw_temp </etc/armbianmonitor/datasources/soctemp 2>/dev/null
|
||||
if [ ! -z $(echo "$raw_temp" | grep -o "^[1-9][0-9]*\.\?[0-9]*$") ] && (( $(echo "${raw_temp} < 200" |bc -l) )); then
|
||||
# Allwinner legacy kernels output degree C
|
||||
board_temp=${raw_temp}
|
||||
else
|
||||
board_temp=$(awk '{printf("%d",$1/1000)}' <<<${raw_temp})
|
||||
fi
|
||||
elif [ -f /etc/armbianmonitor/datasources/pmictemp ]; then
|
||||
# fallback to PMIC temperature
|
||||
board_temp=$(awk '{printf("%d",$1/1000)}' </etc/armbianmonitor/datasources/pmictemp)
|
||||
fi
|
||||
} # getboardtemp
|
||||
|
||||
function batteryinfo() {
|
||||
# Battery info for Allwinner
|
||||
mainline_dir="/sys/power/axp_pmu"
|
||||
legacy_dir="/sys/class/power_supply"
|
||||
if [[ -e "$mainline_dir" ]]; then
|
||||
read status_battery_connected < $mainline_dir/battery/connected
|
||||
if [[ "$status_battery_connected" == "1" ]]; then
|
||||
read status_battery_charging < $mainline_dir/charger/charging
|
||||
read status_ac_connect < $mainline_dir/ac/connected
|
||||
read battery_percent< $mainline_dir/battery/capacity
|
||||
# dispay charging / percentage
|
||||
if [[ "$status_ac_connect" == "1" && "$battery_percent" -lt "100" ]]; then
|
||||
status_battery_text=" charging"
|
||||
elif [[ "$status_ac_connect" == "1" && "$battery_percent" -eq "100" ]]; then
|
||||
status_battery_text=" charged"
|
||||
else
|
||||
status_battery_text=" discharging"
|
||||
fi
|
||||
fi
|
||||
elif [[ -e "$legacy_dir/axp813-ac" ]]; then
|
||||
read status_battery_connected < $legacy_dir/axp20x-battery/present
|
||||
if [[ "$status_battery_connected" == "1" ]]; then
|
||||
status_battery_text=" "$(awk '{print tolower($0)}' < $legacy_dir/axp20x-battery/status)
|
||||
read status_ac_connect < $legacy_dir/axp813-ac/present
|
||||
read battery_percent< $legacy_dir/axp20x-battery/capacity
|
||||
fi
|
||||
elif [[ -e "$legacy_dir/battery" ]]; then
|
||||
if [[ (("$(cat $legacy_dir/battery/voltage_now)" -gt "5" )) ]]; then
|
||||
status_battery_text=" "$(awk '{print tolower($0)}' < $legacy_dir/battery/status)
|
||||
read battery_percent <$legacy_dir/battery/capacity
|
||||
fi
|
||||
fi
|
||||
} # batteryinfo
|
||||
|
||||
function ambienttemp() {
|
||||
if [ -f /etc/armbianmonitor/datasources/ambienttemp ]; then
|
||||
read raw_temp </etc/armbianmonitor/datasources/ambienttemp 2>/dev/null
|
||||
amb_temp=$(awk '{printf("%d",$1/1000)}' <<<${raw_temp})
|
||||
echo $amb_temp
|
||||
else
|
||||
# read ambient temperature from USB device if available
|
||||
if [[ ! -f /usr/bin/temper ]]; then
|
||||
echo ""
|
||||
return
|
||||
fi
|
||||
amb_temp=$(temper -c 2>/dev/null)
|
||||
case ${amb_temp} in
|
||||
*"find the USB device"*)
|
||||
echo ""
|
||||
;;
|
||||
*)
|
||||
amb_temp=$(awk '{print $NF}' <<<$amb_temp | sed 's/C//g')
|
||||
echo -n "scale=1;${amb_temp}/1" | grep -oE "\-?[[:digit:]]+\.[[:digit:]]"
|
||||
esac
|
||||
fi
|
||||
} # ambienttemp
|
||||
|
||||
#function get_ip_addresses() {
|
||||
# # return up to 2 IPv4 address(es) comma separated
|
||||
# hostname -I | tr " " "\n" | \
|
||||
# grep -E "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$" | \
|
||||
# tail -n2 | sed ':a;N;$!ba;s/\n/,/g'
|
||||
#} # get_ip_addresses
|
||||
|
||||
function get_ip_addresses() {
|
||||
local ips=()
|
||||
for f in /sys/class/net/*; do
|
||||
local intf=$(basename $f)
|
||||
# match only interface names starting with e (Ethernet), br (bridge), w (wireless), r (some Ralink drivers use ra<number> format)
|
||||
if [[ $intf =~ $SHOW_IP_PATTERN ]]; then
|
||||
local tmp=$(ip -4 addr show dev $intf | awk '/inet/ {print $2}' | cut -d'/' -f1)
|
||||
# add both name and IP - can be informative but becomes ugly with long persistent/predictable device names
|
||||
#[[ -n $tmp ]] && ips+=("$intf: $tmp")
|
||||
# add IP only
|
||||
[[ -n $tmp ]] && ips+=("$tmp")
|
||||
fi
|
||||
done
|
||||
echo "${ips[@]}"
|
||||
} # get_ip_addresses
|
||||
|
||||
function storage_info() {
|
||||
# storage info
|
||||
RootInfo=$(df -h /)
|
||||
root_usage=$(awk '/\// {print $(NF-1)}' <<<${RootInfo} | sed 's/%//g')
|
||||
root_total=$(awk '/\// {print $(NF-4)}' <<<${RootInfo})
|
||||
StorageInfo=$(df -h $STORAGE 2>/dev/null | grep $STORAGE)
|
||||
if [[ -n "${StorageInfo}" && ${RootInfo} != *$STORAGE* ]]; then
|
||||
storage_usage=$(awk '/\// {print $(NF-1)}' <<<${StorageInfo} | sed 's/%//g')
|
||||
storage_total=$(awk '/\// {print $(NF-4)}' <<<${StorageInfo})
|
||||
fi
|
||||
} # storage_info
|
||||
|
||||
# query various systems and send some stuff to the background for overall faster execution.
|
||||
# Works only with ambienttemp and batteryinfo since A20 is slow enough :)
|
||||
amb_temp=$(ambienttemp &)
|
||||
ip_address=$(get_ip_addresses &)
|
||||
batteryinfo
|
||||
storage_info
|
||||
getboardtemp
|
||||
critical_load=$(( 1 + $(grep -c processor /proc/cpuinfo) / 2 ))
|
||||
|
||||
# get uptime, logged in users and load in one take
|
||||
UptimeString=$(uptime | tr -d ',')
|
||||
time=$(awk -F" " '{print $3" "$4}' <<<"${UptimeString}")
|
||||
load="$(awk -F"average: " '{print $2}'<<<"${UptimeString}")"
|
||||
users="$(awk -F" user" '{print $1}'<<<"${UptimeString}")"
|
||||
case ${time} in
|
||||
1:*) # 1-2 hours
|
||||
time=$(awk -F" " '{print $3" hour"}' <<<"${UptimeString}")
|
||||
;;
|
||||
*:*) # 2-24 hours
|
||||
time=$(awk -F" " '{print $3" hours"}' <<<"${UptimeString}")
|
||||
;;
|
||||
esac
|
||||
|
||||
# memory and swap
|
||||
mem_info=$(LC_ALL=C free -w 2>/dev/null | grep "^Mem" || LC_ALL=C free | grep "^Mem")
|
||||
memory_usage=$(awk '{printf("%.0f",(($2-($4+$6+$7))/$2) * 100)}' <<<${mem_info})
|
||||
memory_total=$(awk '{printf("%d",$2/1024)}' <<<${mem_info})
|
||||
swap_info=$(LC_ALL=C free -m | grep "^Swap")
|
||||
swap_usage=$( (awk '/Swap/ { printf("%3.0f", $3/$2*100) }' <<<${swap_info} 2>/dev/null || echo 0) | tr -c -d '[:digit:]')
|
||||
swap_total=$(awk '{print $(2)}' <<<${swap_info})
|
||||
|
||||
# display info
|
||||
display "System load" "${load%% *}" "${critical_load}" "0" "" "${load#* }"
|
||||
printf "Up time: \x1B[92m%s\x1B[0m\t\t" "$time"
|
||||
display "Local users" "${users##* }" "3" "2" ""
|
||||
echo "" # fixed newline
|
||||
display "Memory usage" "$memory_usage" "70" "0" " %" " of ${memory_total}MB"
|
||||
display "Zram usage" "$swap_usage" "75" "0" " %" " of $swap_total""Mb"
|
||||
printf "IP: "
|
||||
printf "\x1B[92m%s\x1B[0m" "$ip_address"
|
||||
echo "" # fixed newline
|
||||
a=0;b=0;c=0
|
||||
display "CPU temp" "$board_temp" "45" "0" "°C" "" ; a=$?
|
||||
display "Ambient temp" "$amb_temp" "40" "0" "°C" "" ; b=$?
|
||||
(( ($a+$b) >0 )) && echo "" # new line only if some value is displayed
|
||||
display "Usage of /" "$root_usage" "90" "1" "%" " of $root_total"
|
||||
display "storage/" "$storage_usage" "90" "1" "%" " of $storage_total"
|
||||
display "Battery" "$battery_percent" "20" "1" "%" "$status_battery_text"
|
||||
echo ""
|
||||
echo ""
|
54
rootfs/free/usr/bin/create_lnd_wallet.tcl
Executable file
|
@ -0,0 +1,54 @@
|
|||
#!/usr/bin/expect
|
||||
|
||||
set timeout 5
|
||||
|
||||
set f [open "/home/bitcoin/.mynode/.lndpw"]
|
||||
set pw [read $f]
|
||||
set seed [lindex $argv 0];
|
||||
close $f
|
||||
|
||||
set tls_cert "/home/bitcoin/.lnd/tls.cert"
|
||||
set macaroon "/home/bitcoin/.lnd/data/chain/mainnet/admin.macaroon"
|
||||
|
||||
spawn lncli --tlscertpath $tls_cert --macaroonpath $macaroon create
|
||||
expect {
|
||||
"Input wallet password:" {
|
||||
send -- "$pw\n"
|
||||
}
|
||||
timeout { exit 2 }
|
||||
}
|
||||
expect {
|
||||
"Confirm wallet password:" {
|
||||
send -- "$pw\n"
|
||||
}
|
||||
timeout { exit 2 }
|
||||
}
|
||||
expect {
|
||||
"want to use? (Enter y/n):" {
|
||||
send -- "y\n"
|
||||
}
|
||||
timeout { exit 2 }
|
||||
}
|
||||
expect {
|
||||
"spaces:" {
|
||||
send -- "$seed\n"
|
||||
}
|
||||
timeout { exit 2 }
|
||||
}
|
||||
expect {
|
||||
"passphrase):" {
|
||||
send -- "\n"
|
||||
}
|
||||
timeout { exit 2 }
|
||||
}
|
||||
expect {
|
||||
"0):" {
|
||||
send -- "\n"
|
||||
}
|
||||
timeout { exit 2 }
|
||||
}
|
||||
expect eof
|
||||
|
||||
lassign [wait] pid spawnid os_error_flag return_code
|
||||
|
||||
exit $return_code
|
23
rootfs/free/usr/bin/drive_check.sh
Executable file
|
@ -0,0 +1,23 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Find
|
||||
drive=""
|
||||
|
||||
drive=$(cat /tmp/.mynode_drive)
|
||||
while [ -z "$drive" ]; do
|
||||
sleep 10
|
||||
echo "Waiting on myNode Drive..."
|
||||
drive=$(cat /tmp/.mynode_drive)
|
||||
done
|
||||
|
||||
echo "Found Drive: $drive"
|
||||
|
||||
lsblk $drive &> /dev/null
|
||||
while [ $? -eq 0 ]; do
|
||||
echo "$drive still found..."
|
||||
sleep 60
|
||||
lsblk $drive &> /dev/null
|
||||
done
|
||||
|
||||
echo "Drive $drive NOT found! Rebooting."
|
||||
reboot -f
|
17
rootfs/free/usr/bin/format_drive.sh
Executable file
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash
|
||||
dev=$1
|
||||
|
||||
# Delete any old partitions
|
||||
for i in `seq 4 1`;
|
||||
do
|
||||
sudo parted --script /dev/$dev rm $i || true
|
||||
done
|
||||
|
||||
# Try to setup new table
|
||||
parted --script /dev/$dev mklabel gpt || true
|
||||
|
||||
# Make new partition with entire drive
|
||||
parted --script /dev/$dev mkpart primary ext4 0% 100%
|
||||
|
||||
partprobe /dev/$dev
|
||||
sleep 2
|
29
rootfs/free/usr/bin/gen_seed.py
Executable file
|
@ -0,0 +1,29 @@
|
|||
#!/usr/bin/python3
|
||||
from lnd_grpc import lnd_grpc
|
||||
|
||||
def format_seed_numbered(seed):
|
||||
formatted_seed = ""
|
||||
count = 1
|
||||
for word in seed:
|
||||
formatted_seed += "{}: {}\n".format(count, word)
|
||||
count += 1
|
||||
|
||||
return formatted_seed.rstrip()
|
||||
|
||||
def format_seed_raw(seed):
|
||||
s = ""
|
||||
for word in seed:
|
||||
s += word + " "
|
||||
return s.rstrip()
|
||||
|
||||
# This is the main entry point for the program
|
||||
if __name__ == "__main__":
|
||||
|
||||
# Generate the seed
|
||||
rpc = lnd_grpc.Client(lnd_dir="/home/bitcoin/.lnd/",
|
||||
macaroon_path="/home/bitcoin/.lnd/data/chain/bitcoin/mainnet/admin.macaroon")
|
||||
|
||||
# Get seed and print
|
||||
data = rpc.gen_seed()
|
||||
formatted_seed = format_seed_raw(data.cipher_seed_mnemonic)
|
||||
print(formatted_seed)
|
121
rootfs/free/usr/bin/mount_drive.tcl
Executable file
|
@ -0,0 +1,121 @@
|
|||
#!/usr/bin/tclsh
|
||||
|
||||
proc checkPartitionForExistingMyNodeFs {partition} {
|
||||
if [catch {runCommand mount /dev/$partition /mnt/hdd}] {
|
||||
puts "Cannot mount partition ${partition}"
|
||||
return 0
|
||||
}
|
||||
if [file exists /mnt/hdd/.mynode] {
|
||||
puts "Found existing myNode FS on ${partition}"
|
||||
runCommand echo /dev/${partition} > /tmp/.mynode_drive
|
||||
return 1
|
||||
}
|
||||
|
||||
runCommand umount /mnt/hdd
|
||||
|
||||
puts "No myNode filesystem on existing partition ${partition}"
|
||||
return 0
|
||||
}
|
||||
|
||||
proc checkPartitionsForExistingMyNodeFs {partitionsName} {
|
||||
upvar $partitionsName partitions
|
||||
runCommand mkdir -p /mnt/hdd
|
||||
foreach partition $partitions {
|
||||
if [checkPartitionForExistingMyNodeFs $partition] {
|
||||
# Remove this partition from the list so we don't try to
|
||||
# use it as the config drive later on.
|
||||
set partitions [lsearch -all -inline -not -exact $partitions $partition]
|
||||
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
proc findBlockDevices {hardDrivesName} {
|
||||
upvar $hardDrivesName hardDrives
|
||||
set devs [exec ls /sys/block/]
|
||||
|
||||
set hardDrives {}
|
||||
|
||||
foreach dev $devs {
|
||||
if [regexp "sd.*|hd.*|vd.*" $dev] {
|
||||
lappend hardDrives $dev
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc findAllPartitionsForBlockDevices {blockDevices partitionsName} {
|
||||
upvar $partitionsName partitions
|
||||
|
||||
set partitions {}
|
||||
foreach dev $blockDevices {
|
||||
catch {
|
||||
set found [exec ls /sys/block/${dev}/ | grep ${dev}]
|
||||
foreach partition $found {
|
||||
lappend partitions $partition
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc createMyNodeFsOnBlockDevice {blockDevice} {
|
||||
if [exec cat /sys/block/$blockDevice/ro] {
|
||||
puts "Cannot create myNode partition on ${blockDevice} because it is read-only"
|
||||
return 0
|
||||
}
|
||||
|
||||
if [catch {
|
||||
puts "Creating new partition table on ${blockDevice}"
|
||||
runCommand /usr/bin/format_drive.sh ${blockDevice}
|
||||
after 5000
|
||||
|
||||
puts "Formatting new partition ${blockDevice}1"
|
||||
runCommand mkfs.ext4 -F -L myNode /dev/${blockDevice}1
|
||||
|
||||
runCommand mount /dev/${blockDevice}1 /mnt/hdd
|
||||
runCommand date >/mnt/hdd/.mynode
|
||||
runCommand echo /dev/${blockDevice}1 > /tmp/.mynode_drive
|
||||
}] {
|
||||
puts "Formatting on ${blockDevice} failed: $::errorInfo"
|
||||
return 0
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
proc createMyNodeFsOrDie {blockDevices} {
|
||||
foreach dev $blockDevices {
|
||||
if [createMyNodeFsOnBlockDevice $dev] {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
fatal "Cannot find a suitable drive for storing myNode files"
|
||||
}
|
||||
|
||||
proc runCommand {args} {
|
||||
#puts "Running: ${args}"
|
||||
puts [exec -ignorestderr {*}$args]
|
||||
}
|
||||
|
||||
proc mountFileSystems {} {
|
||||
findBlockDevices hardDrives
|
||||
|
||||
puts "Found these harddrives: ${hardDrives}"
|
||||
|
||||
findAllPartitionsForBlockDevices $hardDrives partitions
|
||||
puts "Found these existing harddrive partitions: ${partitions}"
|
||||
|
||||
if {![checkPartitionsForExistingMyNodeFs partitions]} {
|
||||
puts "No existing drive found. Creating new one."
|
||||
createMyNodeFsOrDie $hardDrives
|
||||
}
|
||||
}
|
||||
|
||||
if [catch {mountFileSystems}] {
|
||||
puts "No valid partition found. Try again."
|
||||
exit 1
|
||||
}
|
||||
exit 0
|
15
rootfs/free/usr/bin/mynode-get-quicksync-status
Executable file
|
@ -0,0 +1,15 @@
|
|||
#!/bin/bash
|
||||
|
||||
# General Info
|
||||
transmission-remote -t 1 -i
|
||||
|
||||
# Session Info
|
||||
transmission-remote -t 1 -si
|
||||
|
||||
# Session Stats
|
||||
#transmission-remote -t 1 -st
|
||||
|
||||
# Peer Info
|
||||
echo ""
|
||||
echo "PEER INFO"
|
||||
transmission-remote -t 1 --peer-info
|
40
rootfs/free/usr/bin/mynode_bandwidth.sh
Executable file
|
@ -0,0 +1,40 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
source /usr/share/mynode/mynode_config.sh
|
||||
|
||||
# Let transmission startup
|
||||
sleep 60s
|
||||
|
||||
# Upload slowly while downloading
|
||||
transmission-remote -u 0
|
||||
|
||||
# Wait until download is complete...
|
||||
while [ ! -f "/mnt/hdd/mynode/quicksync/.quicksync_complete" ]; do
|
||||
sleep 30s
|
||||
done
|
||||
|
||||
# Wait until blockchain is synced...
|
||||
while [ ! -f "/mnt/hdd/mynode/.mynode_bitcoind_synced" ]; do
|
||||
sleep 30s
|
||||
done
|
||||
|
||||
# Enable uploading
|
||||
echo "QuickSync Complete! Enabling Uploading."
|
||||
|
||||
while true; do
|
||||
if [ -f $QUICKSYNC_BANDWIDTH_FILE ]; then
|
||||
RATE=$(cat $QUICKSYNC_BANDWIDTH_FILE)
|
||||
echo "Setting upload rate to $RATE kbps"
|
||||
transmission-remote -u $RATE
|
||||
else
|
||||
echo "Setting upload rate to unlimited"
|
||||
transmission-remote -U
|
||||
fi
|
||||
sleep 1d
|
||||
done
|
||||
|
||||
# We should not exit
|
||||
exit 1
|
7
rootfs/free/usr/bin/mynode_chpasswd.sh
Executable file
|
@ -0,0 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
PASSWORD=$1
|
||||
|
||||
# Change Linux Password
|
||||
echo "admin:$PASSWORD" | chpasswd
|
||||
|
35
rootfs/free/usr/bin/mynode_lnd_admin_files.sh
Executable file
|
@ -0,0 +1,35 @@
|
|||
#!/bin/bash
|
||||
|
||||
source /usr/share/mynode/mynode_config.sh
|
||||
|
||||
mkdir -p /home/admin/.lnd/
|
||||
mkdir -p /home/admin/.lnd/data/chain/bitcoin/mainnet/
|
||||
chown -R admin:admin /home/admin/.lnd/
|
||||
|
||||
echo "Waiting on lnd files..."
|
||||
while [ ! -f $LND_TLS_CERT_FILE ]; do
|
||||
sleep 1m
|
||||
done
|
||||
while [ ! -f $LND_ADMIN_MACAROON_FILE ]; do
|
||||
sleep 1m
|
||||
done
|
||||
echo "LND files found!"
|
||||
|
||||
while true; do
|
||||
# Make sure lnd admin path exists
|
||||
mkdir -p /home/admin/.lnd/
|
||||
mkdir -p /home/admin/.lnd/data/chain/bitcoin/mainnet/
|
||||
chown -R admin:admin /home/admin/.lnd/
|
||||
|
||||
# Copy LND files to admin folder
|
||||
cp -f $LND_TLS_CERT_FILE /home/admin/.lnd/
|
||||
cp -f $LND_ADMIN_MACAROON_FILE /home/admin/.lnd/data/chain/bitcoin/mainnet/admin.macaroon
|
||||
chown -R admin:admin /home/admin/.lnd/
|
||||
echo "Updated admin copy of LND files!"
|
||||
|
||||
# Wait for changes
|
||||
inotifywait -e modify -e create -e delete $LND_TLS_CERT_FILE $LND_ADMIN_MACAROON_FILE
|
||||
done
|
||||
|
||||
# Should never exit
|
||||
exit 99
|
68
rootfs/free/usr/bin/mynode_post_upgrade.sh
Executable file
|
@ -0,0 +1,68 @@
|
|||
#!/bin/bash
|
||||
|
||||
source /usr/share/mynode/mynode_config.sh
|
||||
|
||||
# Install any new software
|
||||
# apt-get -y install ...
|
||||
|
||||
# Install any pip software
|
||||
# ...
|
||||
|
||||
# Upgrade BTC
|
||||
ARCH="arm-linux-gnueabihf"
|
||||
uname -a | grep aarch64
|
||||
if [ $? = 0 ]; then
|
||||
ARCH="aarch64-linux-gnu"
|
||||
fi
|
||||
BTC_UPGRADE_URL=https://bitcoin.org/bin/bitcoin-core-0.18.0/bitcoin-0.18.0-$ARCH.tar.gz
|
||||
BTC_UPGRADE_URL_FILE=/home/bitcoin/.mynode/.btc_url
|
||||
CURRENT=""
|
||||
if [ -f $BTC_UPGRADE_URL_FILE ]; then
|
||||
CURRENT=$(cat $BTC_UPGRADE_URL_FILE)
|
||||
fi
|
||||
if [ "$CURRENT" != "$BTC_UPGRADE_URL" ]; then
|
||||
# Download and install Bitcoin
|
||||
rm -rf /tmp/bitcoin*
|
||||
cd /tmp
|
||||
ARCH="arm-linux-gnueabihf"
|
||||
uname -a | grep aarch64
|
||||
if [ $? = 0 ]; then
|
||||
ARCH="aarch64-linux-gnu"
|
||||
fi
|
||||
wget $BTC_UPGRADE_URL -O bitcoin.tar.gz
|
||||
tar -xvf bitcoin.tar.gz
|
||||
mv bitcoin-* bitcoin
|
||||
install -m 0755 -o root -g root -t /usr/local/bin bitcoin/bin/*
|
||||
|
||||
# Mark current version
|
||||
echo $BTC_UPGRADE_URL > $BTC_UPGRADE_URL_FILE
|
||||
fi
|
||||
|
||||
# Upgrade LND
|
||||
LND_UPGRADE_URL=https://github.com/lightningnetwork/lnd/releases/download/v0.6.1-beta/lnd-linux-armv7-v0.6.1-beta.tar.gz
|
||||
LND_UPGRADE_URL_FILE=/home/bitcoin/.mynode/.lnd_url
|
||||
CURRENT=""
|
||||
if [ -f $LND_UPGRADE_URL_FILE ]; then
|
||||
CURRENT=$(cat $LND_UPGRADE_URL_FILE)
|
||||
fi
|
||||
if [ "$CURRENT" != "$LND_UPGRADE_URL" ]; then
|
||||
# Download and install LND
|
||||
rm -rf /tmp/lnd*
|
||||
cd /tmp
|
||||
wget $LND_UPGRADE_URL -O lnd.tar.gz
|
||||
tar -xzf lnd.tar.gz
|
||||
mv lnd-* lnd
|
||||
install -m 0755 -o root -g root -t /usr/local/bin lnd/*
|
||||
|
||||
# Mark current version
|
||||
echo $LND_UPGRADE_URL > $LND_UPGRADE_URL_FILE
|
||||
fi
|
||||
|
||||
# Enable any new/required services
|
||||
# systemctl enable ...
|
||||
|
||||
# Reload service settings
|
||||
systemctl daemon-reload
|
||||
|
||||
# Sync FS
|
||||
sync
|
84
rootfs/free/usr/bin/mynode_quicksync.sh
Executable file
|
@ -0,0 +1,84 @@
|
|||
#!/bin/bash
|
||||
|
||||
# mynode_quicksync.sh
|
||||
# Downloads blockchain up through Feb 2019 for MUCH faster syncing
|
||||
# Seeds afterwards if not disabled
|
||||
# Dependencies: Must run after mynode script so HDD is mounted
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
source /usr/share/mynode/mynode_config.sh
|
||||
|
||||
mkdir -p $QUICKSYNC_DIR
|
||||
mkdir -p $QUICKSYNC_CONFIG_DIR
|
||||
|
||||
cp -f /usr/share/quicksync/settings.json $QUICKSYNC_CONFIG_DIR/settings.json
|
||||
|
||||
# Make sure folder exists
|
||||
mkdir -p $QUICKSYNC_DIR
|
||||
if [ ! -f $QUICKSYNC_DIR/.quicksync_download_complete ]; then
|
||||
echo "quicksync_download" > $MYNODE_DIR/.mynode_status
|
||||
fi
|
||||
echo "Starting quicksync..."
|
||||
|
||||
# Download finished, but failed during copy, recopy
|
||||
if [ ! -f $QUICKSYNC_DIR/.quicksync_complete ] && [ -f $QUICKSYNC_DIR/.quicksync_download_complete ]; then
|
||||
echo "Quicksync download complete, needs copy"
|
||||
/usr/bin/mynode_quicksync_complete.sh
|
||||
fi
|
||||
# Check if quicksync was completed
|
||||
if [ -f $QUICKSYNC_DIR/.quicksync_complete ]; then
|
||||
echo "stable" > $MYNODE_DIR/.mynode_status
|
||||
fi
|
||||
|
||||
# Download torrent
|
||||
rm -rf $QUICKSYNC_DIR/blockchain_temp.torrent
|
||||
wget -O $QUICKSYNC_DIR/blockchain_temp.torrent $QUICKSYNC_TORRENT_URL
|
||||
|
||||
if [ ! -f $QUICKSYNC_DIR/blockchain_temp.torrent ]; then
|
||||
echo "Torrent download failed...."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if new torrent is updated
|
||||
if [ ! -f $QUICKSYNC_DIR/blockchain.torrent ]; then
|
||||
cp $QUICKSYNC_DIR/blockchain_temp.torrent $QUICKSYNC_DIR/blockchain.torrent
|
||||
else
|
||||
# Run commands as long as torrents are different (last command updates torrent file)
|
||||
COMPLETED=0
|
||||
if [ -f $QUICKSYNC_DIR/.quicksync_complete ]; then
|
||||
COMPLETED=1
|
||||
fi
|
||||
|
||||
NEW_TORRENT=0
|
||||
cmp --silent $QUICKSYNC_DIR/blockchain_temp.torrent $QUICKSYNC_DIR/blockchain.torrent || NEW_TORRENT=1
|
||||
if [ $NEW_TORRENT -eq 1 ]; then
|
||||
# Delete old QuickSync data+config and start new one
|
||||
rm -f $QUICKSYNC_DIR/*
|
||||
rm -rf $QUICKSYNC_CONFIG_DIR
|
||||
mkdir -p $QUICKSYNC_CONFIG_DIR
|
||||
cp -f /usr/share/quicksync/settings.json $QUICKSYNC_CONFIG_DIR/settings.json
|
||||
cp $QUICKSYNC_DIR/blockchain_temp.torrent $QUICKSYNC_DIR/blockchain.torrent
|
||||
sync
|
||||
|
||||
# If download had been completed
|
||||
if [ $COMPLETED -eq 1 ]; then
|
||||
touch $QUICKSYNC_DIR/.quicksync_download_complete
|
||||
touch $QUICKSYNC_DIR/.quicksync_complete
|
||||
|
||||
# Since this will start/continue a background download, wait so everything else boots smoothly
|
||||
sleep 5m
|
||||
/usr/bin/wait_on_bitcoin.sh
|
||||
sleep 10m
|
||||
fi
|
||||
sync
|
||||
fi
|
||||
fi
|
||||
|
||||
# Start torrent
|
||||
echo "Running torrent..."
|
||||
transmission-cli \
|
||||
--download-dir $QUICKSYNC_DIR \
|
||||
--finish=/usr/bin/mynode_quicksync_complete.sh \
|
||||
$QUICKSYNC_DIR/blockchain.torrent
|
25
rootfs/free/usr/bin/mynode_quicksync_complete.sh
Executable file
|
@ -0,0 +1,25 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
source /usr/share/mynode/mynode_config.sh
|
||||
|
||||
if [ -f $QUICKSYNC_DIR/.quicksync_complete ] && [ -f $QUICKSYNC_DIR/.quicksync_download_complete ]; then
|
||||
echo "Exiting quicksync_complete. Quicksync already completed. This was just a re-download."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Mark download complete
|
||||
touch $QUICKSYNC_DIR/.quicksync_download_complete
|
||||
sync
|
||||
|
||||
# Copy files
|
||||
echo "quicksync_copy" > $MYNODE_DIR/.mynode_status
|
||||
tar -xvf $QUICKSYNC_DIR/blockchain*.tar.gz -C $MYNODE_DIR/bitcoin/ --dereference
|
||||
|
||||
# Mark quicksync complete
|
||||
echo "stable" > $MYNODE_DIR/.mynode_status
|
||||
touch $QUICKSYNC_DIR/.quicksync_complete
|
||||
sync
|
||||
|
||||
exit 0
|
155
rootfs/free/usr/bin/mynode_startup.sh
Executable file
|
@ -0,0 +1,155 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
source /usr/share/mynode/mynode_config.sh
|
||||
|
||||
# Verify FS is mounted as R/W
|
||||
if [ ! -w / ]; then
|
||||
mount -o remount,rw /;
|
||||
fi
|
||||
|
||||
# Expand Root FS
|
||||
mkdir -p /var/lib/mynode
|
||||
if [ $IS_RASPI -eq 1 ]; then
|
||||
if [ ! -f /var/lib/mynode/.expanded_rootfs ]; then
|
||||
raspi-config --expand-rootfs
|
||||
touch /var/lib/mynode/.expanded_rootfs
|
||||
fi
|
||||
fi
|
||||
|
||||
# Verify we are in a clean state (only raspi uses HDD swap)
|
||||
if [ $IS_RASPI -eq 1 ]; then
|
||||
dphys-swapfile swapoff || true
|
||||
dphys-swapfile uninstall || true
|
||||
fi
|
||||
umount /mnt/hdd || true
|
||||
|
||||
|
||||
# Mount HDD (format if necessary)
|
||||
while [ ! -f /mnt/hdd/.mynode ]
|
||||
do
|
||||
mount_drive.tcl || true
|
||||
sleep 10
|
||||
done
|
||||
|
||||
# Setup Drive
|
||||
mkdir -p /mnt/hdd/mynode
|
||||
mkdir -p /mnt/hdd/mynode/bitcoin
|
||||
mkdir -p /mnt/hdd/mynode/lnd
|
||||
mkdir -p /mnt/hdd/mynode/quicksync
|
||||
echo "drive_mounted" > $MYNODE_DIR/.mynode_status
|
||||
chmod 777 $MYNODE_DIR/.mynode_status
|
||||
rm -rf $MYNODE_DIR/.mynode_bitcoind_synced
|
||||
|
||||
|
||||
# Setup SD Card (if necessary)
|
||||
mkdir -p /home/admin/.bitcoin/
|
||||
chown admin:admin /home/admin/.bitcoin/
|
||||
|
||||
|
||||
# Regen SSH keys
|
||||
mkdir -p /home/bitcoin/.mynode/
|
||||
if [ ! -f /home/bitcoin/.mynode/.gensshkeys ]; then
|
||||
rm -rf /etc/ssh/ssh_host_*
|
||||
dpkg-reconfigure openssh-server
|
||||
systemctl restart ssh
|
||||
|
||||
touch /home/bitcoin/.mynode/.gensshkeys
|
||||
fi
|
||||
|
||||
|
||||
# Randomize RPC password
|
||||
mkdir -p /home/bitcoin/.mynode/
|
||||
if [ ! -f /home/bitcoin/.mynode/.btcrpcpw ]; then
|
||||
# Write random pw to .btcrpcpw
|
||||
< /dev/urandom tr -dc A-Za-z0-9 | head -c${1:-24} > /home/bitcoin/.mynode/.btcrpcpw
|
||||
chown bitcoin:bitcoin /home/bitcoin/.mynode/.btcrpcpw
|
||||
chmod 600 /home/bitcoin/.mynode/.btcrpcpw
|
||||
fi
|
||||
|
||||
|
||||
# Copy config files from /usr/share to /mnt/hdd if necessary
|
||||
if [ ! -f /mnt/hdd/mynode/bitcoin/bitcoin.conf ]; then
|
||||
cp -f /usr/share/mynode/bitcoin.conf /mnt/hdd/mynode/bitcoin/bitcoin.conf
|
||||
|
||||
PW=$(cat /home/bitcoin/.mynode/.btcrpcpw)
|
||||
sed -i "s/rpcpassword=.*/rpcpassword=$PW/g" /mnt/hdd/mynode/bitcoin/bitcoin.conf
|
||||
|
||||
cp -f /mnt/hdd/mynode/bitcoin/bitcoin.conf /home/admin/.bitcoin/bitcoin.conf
|
||||
chown bitcoin:bitcoin /mnt/hdd/mynode/bitcoin/bitcoin.conf
|
||||
chown admin:admin /home/admin/.bitcoin/bitcoin.conf
|
||||
fi
|
||||
if [ ! -f /mnt/hdd/mynode/lnd/lnd.conf ]; then
|
||||
cp /usr/share/mynode/lnd.conf /mnt/hdd/mynode/lnd/lnd.conf
|
||||
chown bitcoin:bitcoin /mnt/hdd/mynode/lnd/lnd.conf
|
||||
fi
|
||||
|
||||
# Update files that need RPC password (needed if upgrades overwrite files)
|
||||
PW=$(cat /home/bitcoin/.mynode/.btcrpcpw)
|
||||
echo "BTC_RPC_PASSWORD=$PW" > /home/bitcoin/.mynode/.btcrpc_environment
|
||||
chown bitcoin:bitcoin /home/bitcoin/.mynode/.btcrpc_environment
|
||||
if [ -f /mnt/hdd/mynode/bitcoin/bitcoin.conf ]; then
|
||||
sed -i "s/rpcpassword=.*/rpcpassword=$PW/g" /mnt/hdd/mynode/bitcoin/bitcoin.conf
|
||||
fi
|
||||
if [ -f /home/admin/.bitcoin/bitcoin.conf ]; then
|
||||
sed -i "s/rpcpassword=.*/rpcpassword=$PW/g" /home/admin/.bitcoin/bitcoin.conf
|
||||
else
|
||||
cp -f /mnt/hdd/mynode/bitcoin/bitcoin.conf /home/admin/.bitcoin/bitcoin.conf
|
||||
chown admin:admin /home/admin/.bitcoin/bitcoin.conf
|
||||
fi
|
||||
|
||||
|
||||
# Reset BTCARGS
|
||||
echo "BTCARGS=" > /mnt/hdd/mynode/bitcoin/env
|
||||
|
||||
|
||||
# Set proper permissions on drive
|
||||
USER=$(stat -c '%U' /mnt/hdd/mynode/quicksync)
|
||||
if [ "$USER" != "bitcoin" ]; then
|
||||
chown -R bitcoin:bitcoin /mnt/hdd/mynode/quicksync
|
||||
fi
|
||||
USER=$(stat -c '%U' /mnt/hdd/mynode/bitcoin)
|
||||
if [ "$USER" != "bitcoin" ]; then
|
||||
chown -R bitcoin:bitcoin /mnt/hdd/mynode/bitcoin
|
||||
fi
|
||||
USER=$(stat -c '%U' /home/bitcoin)
|
||||
if [ "$USER" != "bitcoin" ]; then
|
||||
chown -R --no-dereference bitcoin:bitcoin /home/bitcoin
|
||||
fi
|
||||
USER=$(stat -c '%U' /home/bitcoin/.mynode)
|
||||
if [ "$USER" != "bitcoin" ]; then
|
||||
chown -R bitcoin:bitcoin /home/bitcoin/.mynode
|
||||
fi
|
||||
USER=$(stat -c '%U' /mnt/hdd/mynode/lnd)
|
||||
if [ "$USER" != "bitcoin" ]; then
|
||||
chown -R bitcoin:bitcoin /mnt/hdd/mynode/lnd
|
||||
fi
|
||||
chown bitcoin:bitcoin /mnt/hdd/
|
||||
chown bitcoin:bitcoin /mnt/hdd/mynode/
|
||||
|
||||
|
||||
# Setup swap on new HDD
|
||||
if [ $IS_RASPI -eq 1 ]; then
|
||||
if [ ! -f /mnt/hdd/swapfile ]; then
|
||||
dd if=/dev/zero of=/mnt/hdd/swapfile count=1000 bs=1MiB
|
||||
chmod 600 /mnt/hdd/swapfile
|
||||
fi
|
||||
mkswap /mnt/hdd/swapfile
|
||||
dphys-swapfile setup
|
||||
dphys-swapfile swapon
|
||||
fi
|
||||
|
||||
# Add some DNS servers to make domain lookup more likely
|
||||
echo '' >> /etc/resolv.conf
|
||||
echo '# Added at myNode startup' >> /etc/resolv.conf
|
||||
echo 'nameserver 8.8.8.8' >> /etc/resolv.conf
|
||||
echo 'nameserver 8.8.4.4' >> /etc/resolv.conf
|
||||
echo 'nameserver 1.1.1.1' >> /etc/resolv.conf
|
||||
|
||||
|
||||
# Update current state
|
||||
if [ -f $QUICKSYNC_DIR/.quicksync_complete ]; then
|
||||
echo "stable" > $MYNODE_DIR/.mynode_status
|
||||
fi
|
33
rootfs/free/usr/bin/mynode_torrent_check.sh
Executable file
|
@ -0,0 +1,33 @@
|
|||
#!/bin/bash
|
||||
|
||||
source /usr/share/mynode/mynode_config.sh
|
||||
|
||||
echo "Waiting until QuickSync is complete..."
|
||||
while [ ! -f $QUICKSYNC_DIR/.quicksync_complete ]; do
|
||||
sleep 1m
|
||||
done
|
||||
echo "Quicksync Complete. Checking if there is a new torrent available..."
|
||||
|
||||
while true; do
|
||||
# Wait a while... we don't want everyone starting on a new torrent at once
|
||||
sleep 7d
|
||||
|
||||
# Download current torrent
|
||||
rm -rf /tmp/blockchain_temp.torrent
|
||||
wget -O /tmp/blockchain_temp.torrent $QUICKSYNC_TORRENT_URL
|
||||
if [ -f /tmp/blockchain_temp.torrent ]; then
|
||||
NEW_TORRENT=0
|
||||
cmp --silent /tmp/blockchain_temp.torrent $QUICKSYNC_DIR/blockchain.torrent || NEW_TORRENT=1
|
||||
if [ $NEW_TORRENT -eq 1 ]; then
|
||||
# Reboot to restart and get new torrent
|
||||
reboot
|
||||
else
|
||||
echo "Torrent has not changed."
|
||||
fi
|
||||
else
|
||||
echo "Torrent download failed...."
|
||||
fi
|
||||
done
|
||||
|
||||
# Should never exit
|
||||
exit 99
|
35
rootfs/free/usr/bin/mynode_upgrade.sh
Executable file
|
@ -0,0 +1,35 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -x
|
||||
#set -e
|
||||
|
||||
source /usr/share/mynode/mynode_config.sh
|
||||
|
||||
# Setup
|
||||
rm -rf /tmp/mynode_release_latest.tar.gz
|
||||
rm -rf /tmp/mynode_release.pub
|
||||
rm -rf /tmp/upgrade/
|
||||
mkdir -p /tmp/upgrade/
|
||||
|
||||
# Download Latest
|
||||
wget $UPGRADE_DOWNLOAD_URL -O /tmp/mynode_release_latest.tar.gz
|
||||
wget $UPGRADE_DOWNLOAD_SIGNATURE_URL -O /tmp/mynode_release_latest.sha256
|
||||
wget $UPGRADE_PUBKEY_URL -O /tmp/mynode_release.pub
|
||||
|
||||
openssl dgst -sha256 -verify /tmp/mynode_release.pub -signature /tmp/mynode_release_latest.sha256 /tmp/mynode_release_latest.tar.gz
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "UPGRADE FAILED! Hash did not match!" >> /var/log/upgrade.log
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract to temp location
|
||||
tar -xvf /tmp/mynode_release_latest.tar.gz -C /tmp/upgrade/
|
||||
|
||||
# Install files
|
||||
cp -rf /tmp/upgrade/out/rootfs_*/* /
|
||||
sleep 1
|
||||
sync
|
||||
sleep 1
|
||||
|
||||
# Run post upgrade script
|
||||
/bin/bash /usr/bin/mynode_post_upgrade.sh
|
10
rootfs/free/usr/bin/pre_lnd.sh
Executable file
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Make sure we have wallet pw
|
||||
mkdir -p /home/bitcoin/.mynode/
|
||||
if [ ! -f /home/bitcoin/.mynode/.lndpw ]; then
|
||||
< /dev/urandom tr -dc A-Za-z0-9 | head -c${1:-24} > /home/bitcoin/.mynode/.lndpw
|
||||
chmod 600 /home/bitcoin/.mynode/.lndpw
|
||||
fi
|
||||
|
||||
exit 0
|
23
rootfs/free/usr/bin/unlock_lnd.sh
Executable file
|
@ -0,0 +1,23 @@
|
|||
#!/bin/bash
|
||||
|
||||
source /usr/share/mynode/mynode_config.sh
|
||||
|
||||
while true; do
|
||||
|
||||
while [ ! -f "$LND_WALLET_FILE" ]; do
|
||||
echo "Waiting for LND wallet file to exist..."
|
||||
sleep 30s
|
||||
done
|
||||
|
||||
echo "Unlocking wallet..."
|
||||
/usr/bin/expect /usr/bin/unlock_lnd.tcl
|
||||
if [ $? -eq 0 ]; then
|
||||
# Unlocked! Verify unlocked every time LND files change
|
||||
inotifywait -r -e modify -e create -e delete /mnt/hdd/mynode/lnd/data/chain/bitcoin/mainnet/
|
||||
else
|
||||
# Failed, try again in 15 seconds
|
||||
/bin/sleep 15s
|
||||
fi
|
||||
done
|
||||
|
||||
exit 0
|
27
rootfs/free/usr/bin/unlock_lnd.tcl
Executable file
|
@ -0,0 +1,27 @@
|
|||
#!/usr/bin/expect
|
||||
|
||||
set timeout 20
|
||||
|
||||
set tls_cert "/home/bitcoin/.lnd/tls.cert"
|
||||
set macaroon "/home/bitcoin/.lnd/data/chain/bitcoin/mainnet/admin.macaroon"
|
||||
|
||||
set f [open "/home/bitcoin/.mynode/.lndpw"]
|
||||
set pw [read $f]
|
||||
|
||||
spawn lncli --tlscertpath $tls_cert --macaroonpath $macaroon unlock
|
||||
expect {
|
||||
"wallet password:" {
|
||||
send -- "$pw\n"
|
||||
}
|
||||
}
|
||||
expect {
|
||||
"Wallet is already unlocked" {
|
||||
exit 0
|
||||
}
|
||||
eof {
|
||||
lassign [wait] pid spawnid os_error_flag return_code
|
||||
exit $return_code
|
||||
}
|
||||
}
|
||||
|
||||
exit 99
|
13
rootfs/free/usr/bin/wait_on_bitcoin.sh
Executable file
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Wait to see if bitcoind is synced
|
||||
echo "Checking if Bitcoin is synced..."
|
||||
while [ ! -f "/mnt/hdd/mynode/.mynode_bitcoind_synced" ]; do
|
||||
echo "Bitcoin not synced, sleeping for 60 seconds..."
|
||||
/bin/sleep 60s
|
||||
done
|
||||
|
||||
# And finally, make sure bitcoind responds to API requests
|
||||
bitcoin-cli -rpcwait getblockchaininfo
|
||||
|
||||
exit 0
|
11
rootfs/free/usr/bin/wait_on_lnd.sh
Executable file
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Wait until lnd is synced
|
||||
echo "Checking if LND is synced..."
|
||||
lncli --lnddir /mnt/hdd/mynode/lnd getinfo | grep 'synced_to_chain": true'
|
||||
while [ ! $? ]; do
|
||||
echo "LND not synced, sleeping for 60 seconds..."
|
||||
/bin/sleep 60s
|
||||
lncli --lnddir /mnt/hdd/mynode/lnd getinfo | grep 'synced_to_chain": true'
|
||||
done
|
||||
exit 0
|
29
rootfs/free/usr/share/mynode/bitcoin.conf
Normal file
|
@ -0,0 +1,29 @@
|
|||
# bitcoind configuration
|
||||
# /home/bitcoin/.bitcoin/bitcoin.conf
|
||||
|
||||
# remove the following line to enable Bitcoin mainnet
|
||||
#testnet=1
|
||||
|
||||
# Bitcoind options
|
||||
server=1
|
||||
daemon=1
|
||||
|
||||
# Connection settings
|
||||
rpcuser=mynode
|
||||
# This password was randomly generated by your device. Changing it may cause problems.
|
||||
rpcpassword=bolt
|
||||
rpcport=8332
|
||||
rpcbind=127.0.0.1
|
||||
rpcallowip=127.0.0.1
|
||||
|
||||
txindex=1
|
||||
|
||||
zmqpubrawblock=tcp://127.0.0.1:28332
|
||||
zmqpubrawtx=tcp://127.0.0.1:28333
|
||||
|
||||
# myNode Optimizations
|
||||
dbcache=400
|
||||
maxorphantx=10
|
||||
maxmempool=200
|
||||
maxconnections=40
|
||||
maxuploadtarget=1000
|
32
rootfs/free/usr/share/mynode/lnd.conf
Normal file
|
@ -0,0 +1,32 @@
|
|||
# lnd configuration
|
||||
# /home/bitcoin/.lnd/lnd.conf
|
||||
|
||||
[Application Options]
|
||||
debuglevel=info
|
||||
maxpendingchannels=5
|
||||
alias=myNode [LND]
|
||||
color=#68F442
|
||||
|
||||
# Your router must support and enable UPnP, otherwise delete this line
|
||||
nat=true
|
||||
|
||||
rpclisten=0.0.0.0:10009
|
||||
restlisten=0.0.0.0:10080
|
||||
|
||||
tlsextraip=0.0.0.0
|
||||
|
||||
#debuglevel=info
|
||||
debuglevel=debug
|
||||
|
||||
[Bitcoin]
|
||||
bitcoin.active=1
|
||||
|
||||
# enable either testnet or mainnet
|
||||
bitcoin.mainnet=1
|
||||
|
||||
bitcoin.node=bitcoind
|
||||
|
||||
[autopilot]
|
||||
#autopilot.active=1
|
||||
#autopilot.maxchannels=5
|
||||
#autopilot.allocation=0.6
|
22
rootfs/free/usr/share/mynode/mynode_config.sh
Normal file
|
@ -0,0 +1,22 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Device info
|
||||
IS_RASPI=1
|
||||
IS_ROCK64=0
|
||||
|
||||
# Set all default / standard bash config settings
|
||||
MYNODE_DIR=/mnt/hdd/mynode
|
||||
QUICKSYNC_DIR=/mnt/hdd/mynode/quicksync
|
||||
QUICKSYNC_CONFIG_DIR=/home/bitcoin/.config/transmission
|
||||
QUICKSYNC_TORRENT_URL="https://mynodebtc.com/device/blockchain.tar.gz.torrent"
|
||||
QUICKSYNC_BANDWIDTH_FILE="/home/bitcoin/.mynode/.bandwidth"
|
||||
LND_BACKUP_FOLDER="/home/bitcoin/lnd_backup/"
|
||||
LND_TLS_CERT_FILE="/mnt/hdd/mynode/lnd/tls.cert"
|
||||
LND_WALLET_FILE="/mnt/hdd/mynode/lnd/data/chain/bitcoin/mainnet/wallet.db"
|
||||
LND_CHANNEL_FILE="/mnt/hdd/mynode/lnd/data/chain/bitcoin/mainnet/channel.backup"
|
||||
LND_CHANNEL_FILE_BACKUP="/home/bitcoin/lnd_backup/channel.backup"
|
||||
LND_ADMIN_MACAROON_FILE="/mnt/hdd/mynode/lnd/data/chain/bitcoin/mainnet/admin.macaroon"
|
||||
|
||||
UPGRADE_DOWNLOAD_URL="http://www.mynodebtc.com/device/mynode_release_latest_free.tar.gz"
|
||||
UPGRADE_DOWNLOAD_SIGNATURE_URL="http://www.mynodebtc.com/device/mynode_release_latest_free.sha256"
|
||||
UPGRADE_PUBKEY_URL="https://raw.githubusercontent.com/mynodebtc/pubkey/master/mynode_release.pub"
|
1
rootfs/free/usr/share/mynode/version
Normal file
|
@ -0,0 +1 @@
|
|||
0.1.11
|
68
rootfs/free/usr/share/quicksync/settings.json
Normal file
|
@ -0,0 +1,68 @@
|
|||
{
|
||||
"alt-speed-down": 50,
|
||||
"alt-speed-enabled": false,
|
||||
"alt-speed-time-begin": 540,
|
||||
"alt-speed-time-day": 127,
|
||||
"alt-speed-time-enabled": false,
|
||||
"alt-speed-time-end": 1020,
|
||||
"alt-speed-up": 50,
|
||||
"bind-address-ipv4": "0.0.0.0",
|
||||
"bind-address-ipv6": "::",
|
||||
"blocklist-enabled": false,
|
||||
"blocklist-url": "http://www.example.com/blocklist",
|
||||
"cache-size-mb": 4,
|
||||
"dht-enabled": true,
|
||||
"download-dir": "/mnt/hdd/mynode/quicksync",
|
||||
"download-queue-enabled": false,
|
||||
"download-queue-size": 5,
|
||||
"encryption": 0,
|
||||
"idle-seeding-limit": 30,
|
||||
"idle-seeding-limit-enabled": false,
|
||||
"incomplete-dir": "/home/admin/Downloads",
|
||||
"incomplete-dir-enabled": false,
|
||||
"lpd-enabled": true,
|
||||
"message-level": 0,
|
||||
"peer-congestion-algorithm": "",
|
||||
"peer-id-ttl-hours": 6,
|
||||
"peer-limit-global": 200,
|
||||
"peer-limit-per-torrent": 50,
|
||||
"peer-port": 56881,
|
||||
"peer-port-random-high": 56899,
|
||||
"peer-port-random-low": 56881,
|
||||
"peer-port-random-on-start": false,
|
||||
"peer-socket-tos": "default",
|
||||
"pex-enabled": true,
|
||||
"port-forwarding-enabled": true,
|
||||
"preallocation": 1,
|
||||
"prefetch-enabled": true,
|
||||
"queue-stalled-enabled": false,
|
||||
"queue-stalled-minutes": 30,
|
||||
"ratio-limit": 2,
|
||||
"ratio-limit-enabled": false,
|
||||
"rename-partial-files": true,
|
||||
"rpc-authentication-required": false,
|
||||
"rpc-bind-address": "0.0.0.0",
|
||||
"rpc-enabled": true,
|
||||
"rpc-host-whitelist": "",
|
||||
"rpc-host-whitelist-enabled": true,
|
||||
"rpc-password": "",
|
||||
"rpc-port": 9091,
|
||||
"rpc-url": "/transmission/",
|
||||
"rpc-username": "",
|
||||
"rpc-whitelist": "127.0.0.1",
|
||||
"rpc-whitelist-enabled": true,
|
||||
"scrape-paused-torrents-enabled": true,
|
||||
"script-torrent-done-enabled": true,
|
||||
"script-torrent-done-filename": "/usr/bin/mynode_quicksync_complete.sh",
|
||||
"seed-queue-enabled": false,
|
||||
"seed-queue-size": 10,
|
||||
"speed-limit-down": 100,
|
||||
"speed-limit-down-enabled": false,
|
||||
"speed-limit-up": 100,
|
||||
"speed-limit-up-enabled": false,
|
||||
"start-added-torrents": true,
|
||||
"trash-original-torrent-files": false,
|
||||
"umask": 18,
|
||||
"upload-slots-per-torrent": 5,
|
||||
"utp-enabled": false
|
||||
}
|
29
rootfs/free/var/www/mynode/background_thread.py
Normal file
|
@ -0,0 +1,29 @@
|
|||
import threading
|
||||
import time
|
||||
import os
|
||||
|
||||
class BackgroundThread(threading.Thread):
|
||||
|
||||
def __init__(self, run_function, rate=30):
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
# The shutdown_flag is a threading.Event object that
|
||||
# indicates whether the thread should be terminated.
|
||||
self.shutdown_flag = threading.Event()
|
||||
self.run_function = run_function
|
||||
self.rate = rate
|
||||
self.pid = 0
|
||||
|
||||
# ... Other thread setup code here ...
|
||||
|
||||
def run(self):
|
||||
print('Thread #%s started' % self.ident)
|
||||
|
||||
self.pid = os.getpid()
|
||||
|
||||
while not self.shutdown_flag.is_set():
|
||||
self.run_function()
|
||||
time.sleep(self.rate)
|
||||
|
||||
# ... Clean shutdown code here ...
|
||||
print('Thread #%s stopped' % self.ident)
|
122
rootfs/free/var/www/mynode/bitcoin_info.py
Normal file
|
@ -0,0 +1,122 @@
|
|||
from config import *
|
||||
from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
|
||||
import subprocess
|
||||
import copy
|
||||
import time
|
||||
import os
|
||||
|
||||
# Variables
|
||||
bitcoin_block_height = 570000
|
||||
mynode_block_height = 566000
|
||||
bitcoin_blockchain_info = None
|
||||
bitcoin_recent_blocks = None
|
||||
bitcoin_peers = []
|
||||
bitcoin_mempool = None
|
||||
bitcoin_version = None
|
||||
|
||||
# Functions
|
||||
def get_bitcoin_rpc_username():
|
||||
return "mynode"
|
||||
|
||||
def get_bitcoin_rpc_password():
|
||||
try:
|
||||
with open("/home/bitcoin/.mynode/.btcrpcpw", "r") as f:
|
||||
return f.read()
|
||||
except:
|
||||
return "error_getting_password"
|
||||
|
||||
def get_bitcoin_version():
|
||||
global bitcoin_version
|
||||
if bitcoin_version == None:
|
||||
bitcoin_version = subprocess.check_output("bitcoind --version | egrep -o 'v[0-9]+\\.[0-9]+\\.[0-9]+'", shell=True)
|
||||
return bitcoin_version
|
||||
|
||||
def is_bitcoind_synced():
|
||||
if os.path.isfile( BITCOIN_SYNCED_FILE ):
|
||||
return True
|
||||
return False
|
||||
|
||||
def update_bitcoin_main_info():
|
||||
global bitcoin_block_height
|
||||
global mynode_block_height
|
||||
global bitcoin_blockchain_info
|
||||
|
||||
try:
|
||||
rpc_user = get_bitcoin_rpc_username()
|
||||
rpc_pass = get_bitcoin_rpc_password()
|
||||
|
||||
rpc_connection = AuthServiceProxy("http://%s:%s@127.0.0.1:8332"%(rpc_user, rpc_pass), timeout=120)
|
||||
|
||||
# Basic Info
|
||||
bitcoin_blockchain_info = rpc_connection.getblockchaininfo()
|
||||
if bitcoin_blockchain_info != None:
|
||||
bitcoin_block_height = bitcoin_blockchain_info['headers']
|
||||
mynode_block_height = bitcoin_blockchain_info['blocks']
|
||||
|
||||
except Exception as e:
|
||||
print "ERROR: In update_bitcoin_info - {}".format( str(e) )
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def update_bitcoin_other_info():
|
||||
global bitcoin_blockchain_info
|
||||
global bitcoin_recent_blocks
|
||||
global bitcoin_peers
|
||||
global bitcoin_mempool
|
||||
|
||||
if bitcoin_blockchain_info == None:
|
||||
# We still havent gotten the important info... wait 1 minute and return
|
||||
time.sleep(60)
|
||||
return True
|
||||
|
||||
try:
|
||||
rpc_user = get_bitcoin_rpc_username()
|
||||
rpc_pass = get_bitcoin_rpc_password()
|
||||
|
||||
rpc_connection = AuthServiceProxy("http://%s:%s@127.0.0.1:8332"%(rpc_user, rpc_pass), timeout=60)
|
||||
|
||||
# Get other less important info
|
||||
try:
|
||||
# Recent blocks
|
||||
commands = [ [ "getblockhash", height] for height in range(mynode_block_height-9, mynode_block_height+1) ]
|
||||
block_hashes = rpc_connection.batch_(commands)
|
||||
bitcoin_recent_blocks = rpc_connection.batch_([ [ "getblock", h ] for h in block_hashes ])
|
||||
|
||||
# Get peers
|
||||
bitcoin_peers = rpc_connection.getpeerinfo()
|
||||
|
||||
# Get mempool
|
||||
bitcoin_mempool = rpc_connection.getmempoolinfo()
|
||||
except:
|
||||
pass
|
||||
|
||||
except Exception as e:
|
||||
print "ERROR: In update_bitcoin_info - {}".format( str(e) )
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def get_bitcoin_blockchain_info():
|
||||
global bitcoin_blockchain_info
|
||||
return copy.deepcopy(bitcoin_blockchain_info)
|
||||
|
||||
def get_bitcoin_block_height():
|
||||
global bitcoin_block_height
|
||||
return bitcoin_block_height
|
||||
|
||||
def get_mynode_block_height():
|
||||
global mynode_block_height
|
||||
return mynode_block_height
|
||||
|
||||
def get_bitcoin_recent_blocks():
|
||||
global bitcoin_recent_blocks
|
||||
return copy.deepcopy(bitcoin_recent_blocks)
|
||||
|
||||
def get_bitcoin_peers():
|
||||
global bitcoin_peers
|
||||
return copy.deepcopy(bitcoin_peers)
|
||||
|
||||
def get_bitcoin_mempool():
|
||||
global bitcoin_mempool
|
||||
return copy.deepcopy(bitcoin_mempool)
|
94
rootfs/free/var/www/mynode/bitcoind.py
Normal file
|
@ -0,0 +1,94 @@
|
|||
from flask import Blueprint, render_template, session, abort, Markup, request, redirect
|
||||
from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
|
||||
from pprint import pprint, pformat
|
||||
from bitcoin_info import *
|
||||
#from bitcoin.wallet import *
|
||||
from subprocess import check_output, check_call
|
||||
#from electrum_functions import *
|
||||
import socket
|
||||
import hashlib
|
||||
import json
|
||||
import time
|
||||
|
||||
mynode_bitcoind = Blueprint('mynode_bitcoind',__name__)
|
||||
|
||||
|
||||
### Helper functions
|
||||
|
||||
### Page functions
|
||||
@mynode_bitcoind.route("/bitcoind")
|
||||
def bitcoind_status_page():
|
||||
# Get current information
|
||||
try:
|
||||
info = get_bitcoin_blockchain_info()
|
||||
blockdata = get_bitcoin_recent_blocks()
|
||||
peerdata = get_bitcoin_peers()
|
||||
mempooldata = get_bitcoin_mempool()
|
||||
version = get_bitcoin_version()
|
||||
|
||||
# Mempool info
|
||||
mempool = {}
|
||||
mempool["size"] = "???"
|
||||
mempool["bytes"] = "0"
|
||||
if mempooldata != None:
|
||||
if "size" in mempooldata:
|
||||
mempool["size"] = mempooldata["size"]
|
||||
if "bytes" in mempooldata:
|
||||
mempool["bytes"] = mempooldata["bytes"]
|
||||
|
||||
# Recent blocks
|
||||
blocks = []
|
||||
if blockdata != None:
|
||||
for b in blockdata:
|
||||
block = b
|
||||
minutes = int(time.time() - int(b["time"])) / 60
|
||||
block["age"] = "{} minutes".format(minutes)
|
||||
block["size"] = int(b["size"] / 1000)
|
||||
blocks.append(block)
|
||||
blocks.reverse()
|
||||
blocks = blocks[:5] # Take top 5
|
||||
|
||||
# Peers
|
||||
peers = []
|
||||
if peerdata != None:
|
||||
for p in peerdata:
|
||||
peer = p
|
||||
|
||||
if "pingtime" in p:
|
||||
peer["pingtime"] = int(p["pingtime"] * 1000)
|
||||
else:
|
||||
peer["pingtime"] = "N/A"
|
||||
|
||||
if "bytessent" in p:
|
||||
peer["tx"] = "{:.2f}".format(float(p["bytessent"]) / 1000 / 1000)
|
||||
else:
|
||||
peer["tx"] = "N/A"
|
||||
|
||||
if "bytesrecv" in p:
|
||||
peer["rx"] = "{:.2f}".format(float(p["bytesrecv"]) / 1000 / 1000)
|
||||
else:
|
||||
peer["rx"] = "N/A"
|
||||
|
||||
peers.append(peer)
|
||||
|
||||
except Exception as e:
|
||||
templateData = {
|
||||
"title": "myNode Bitcoin Error",
|
||||
"message": Markup("Error communicating with bitcoind. Node may be busy syncing.<br/><br/>{}".format(str(e)))
|
||||
}
|
||||
return render_template('bitcoind_status_error.html', **templateData)
|
||||
|
||||
|
||||
templateData = {
|
||||
"title": "myNode Bitcoin Status",
|
||||
"blocks": blocks,
|
||||
"peers": peers,
|
||||
"difficulty": "{:.3g}".format(info["difficulty"]),
|
||||
"block_num": info["blocks"],
|
||||
"header_num": info["headers"],
|
||||
"disk_size": (int(info["size_on_disk"]) / 1000 / 1000 / 1000),
|
||||
"mempool_tx": mempool["size"],
|
||||
"mempool_size": "{:.3} MB".format(float(mempool["bytes"]) / 1000 / 1000),
|
||||
"version": version
|
||||
}
|
||||
return render_template('bitcoind_status.html', **templateData)
|
17
rootfs/free/var/www/mynode/config.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
|
||||
CONFIG = {}
|
||||
|
||||
# Basic Config
|
||||
CONFIG["device_type"] = "free"
|
||||
|
||||
# myNode variables
|
||||
LATEST_VERSION_URL = "http://www.mynodebtc.com/device/latest_free_version"
|
||||
CHECKIN_URL = "http://www.mynodebtc.com/device_api/check_in.php"
|
||||
|
||||
# Bitcoin Variables
|
||||
BITCOIN_ENV_FILE = "/mnt/hdd/mynode/bitcoin/env"
|
||||
BITCOIN_SYNCED_FILE = "/mnt/hdd/mynode/.mynode_bitcoind_synced"
|
||||
|
||||
# LND Variables
|
||||
LND_WALLET_FILE = "/mnt/hdd/mynode/lnd/data/chain/bitcoin/mainnet/wallet.db"
|
||||
LND_DATA_FOLDER = "/mnt/hdd/mynode/lnd/data/"
|
33
rootfs/free/var/www/mynode/device_info.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
from config import *
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
# Functions
|
||||
def get_current_version():
|
||||
current_version = "0.0"
|
||||
try:
|
||||
with open("/usr/share/mynode/version", "r") as f:
|
||||
current_version = f.read().strip()
|
||||
except:
|
||||
current_version = "error"
|
||||
return current_version
|
||||
|
||||
|
||||
def update_latest_version():
|
||||
os.system("wget "+LATEST_VERSION_URL+" -O /usr/share/mynode/latest_version")
|
||||
return True
|
||||
|
||||
|
||||
def get_latest_version():
|
||||
latest_version = "0.0"
|
||||
try:
|
||||
with open("/usr/share/mynode/latest_version", "r") as f:
|
||||
latest_version = f.read().strip()
|
||||
except:
|
||||
latest_version = get_current_version()
|
||||
return latest_version
|
||||
|
||||
|
||||
def get_device_serial():
|
||||
serial = subprocess.check_output("cat /proc/cpuinfo | grep Serial | cut -d ' ' -f 2", shell=True)
|
||||
return serial
|
144
rootfs/free/var/www/mynode/lightning_info.py
Normal file
|
@ -0,0 +1,144 @@
|
|||
import copy
|
||||
import requests
|
||||
import subprocess
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
from threading import Timer
|
||||
from bitcoin_info import *
|
||||
|
||||
# Variables
|
||||
lightning_info = None
|
||||
lnd_ready = False
|
||||
|
||||
LND_FOLDER = "/mnt/hdd/mynode/lnd/"
|
||||
MACAROON_FILE = "/mnt/hdd/mynode/lnd/data/chain/bitcoin/mainnet/admin.macaroon"
|
||||
WALLET_FILE = "/mnt/hdd/mynode/lnd/data/chain/bitcoin/mainnet/wallet.db"
|
||||
TLS_CERT_FILE = "/mnt/hdd/mynode/lnd/tls.cert"
|
||||
LND_REST_PORT = "10080"
|
||||
|
||||
# Functions
|
||||
def update_lightning_info():
|
||||
global lightning_info
|
||||
global lnd_ready
|
||||
|
||||
# Get latest LN info
|
||||
lightning_info = lnd_get("/getinfo")
|
||||
|
||||
# Set is LND ready
|
||||
if lightning_info != None and "synced_to_chain" in lightning_info and lightning_info['synced_to_chain']:
|
||||
lnd_ready = True
|
||||
|
||||
# Check for LND de-sync (this can happen unfortunately)
|
||||
# See https://github.com/lightningnetwork/lnd/issues/1909
|
||||
# See https://github.com/bitcoin/bitcoin/pull/14687
|
||||
# Hopefully patch comes soon to enable TCP keepalive to prevent this from happening
|
||||
if lnd_ready and lightning_info != None and "synced_to_chain" in lightning_info and not lightning_info['synced_to_chain']:
|
||||
os.system("echo 'LND De-sync!!!' >> /tmp/lnd_failures")
|
||||
os.system("uptime >> /tmp/lnd_failures")
|
||||
restart_lnd()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def get_lightning_info():
|
||||
global lightning_info
|
||||
return copy.deepcopy(lightning_info)
|
||||
|
||||
def is_lnd_ready():
|
||||
global lnd_ready
|
||||
return lnd_ready
|
||||
|
||||
def lnd_get(path):
|
||||
try:
|
||||
macaroon = get_macaroon()
|
||||
headers = {"Grpc-Metadata-macaroon":macaroon}
|
||||
r = requests.get("https://localhost:"+LND_REST_PORT+"/v1"+path, verify=TLS_CERT_FILE,headers=headers)
|
||||
except Exception as e:
|
||||
return str(e)
|
||||
return r.json()
|
||||
|
||||
def gen_new_wallet_seed():
|
||||
seed = subprocess.check_output("python3 /usr/bin/gen_seed.py", shell=True)
|
||||
return seed
|
||||
|
||||
def restart_lnd_actual():
|
||||
os.system("systemctl restart lnd")
|
||||
os.system("systemctl restart lnd_unlock")
|
||||
|
||||
def restart_lnd():
|
||||
t = Timer(1.0, restart_lnd_actual)
|
||||
t.start()
|
||||
|
||||
def get_macaroon():
|
||||
m = subprocess.check_output("xxd -ps -u -c 1000 "+MACAROON_FILE, shell=True)
|
||||
return m.strip()
|
||||
|
||||
def lnd_wallet_exists():
|
||||
return os.path.isfile(WALLET_FILE)
|
||||
|
||||
def unlock_wallet():
|
||||
os.system("/usr/bin/expect /usr/bin/unlock_lnd.tcl")
|
||||
|
||||
def create_wallet(seed):
|
||||
try:
|
||||
subprocess.check_call("create_lnd_wallet.tcl \""+seed+"\"", shell=True)
|
||||
|
||||
t = Timer(1.0, unlock_wallet)
|
||||
t.start()
|
||||
|
||||
# Sync FS and sleep so the success redirect understands the wallet was created
|
||||
os.system("sync")
|
||||
time.sleep(2)
|
||||
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def is_lnd_logged_in():
|
||||
try:
|
||||
macaroon = get_macaroon()
|
||||
headers = {"Grpc-Metadata-macaroon":macaroon}
|
||||
r = requests.get("https://localhost:"+LND_REST_PORT+"/v1/getinfo", verify=TLS_CERT_FILE,headers=headers)
|
||||
if r.status_code == 200 and r.json():
|
||||
return True
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
def get_lnd_status():
|
||||
if not lnd_wallet_exists():
|
||||
return "Please create wallet..."
|
||||
|
||||
if not is_lnd_logged_in():
|
||||
return "Logging in..."
|
||||
|
||||
if is_lnd_ready():
|
||||
return "Running"
|
||||
|
||||
log = subprocess.check_output("tail -n 100 /var/log/lnd.log", shell=True)
|
||||
lines = log.splitlines()
|
||||
lines.reverse()
|
||||
for line in lines:
|
||||
if "Caught up to height" in line:
|
||||
m = re.search("height ([0-9]+)", line)
|
||||
height = m.group(1)
|
||||
percent = 100.0 * (float(height) / bitcoin_block_height)
|
||||
return "Syncing... {:.2f}%".format(percent)
|
||||
elif "Started rescan from block" in line:
|
||||
return "Scanning..."
|
||||
return "Waiting..."
|
||||
|
||||
def get_lnd_channels():
|
||||
try:
|
||||
macaroon = get_macaroon()
|
||||
headers = {"Grpc-Metadata-macaroon":macaroon}
|
||||
r = requests.get("https://localhost:"+LND_REST_PORT+"/v1/channels", verify=TLS_CERT_FILE,headers=headers)
|
||||
if r.status_code == 200 and r.json():
|
||||
data = r.json()
|
||||
return data["channels"]
|
||||
return False
|
||||
except Exception as e:
|
||||
print("EXCEPTION: {}".format(str(e)))
|
||||
return False
|
||||
|
176
rootfs/free/var/www/mynode/lnd.py
Normal file
|
@ -0,0 +1,176 @@
|
|||
from flask import Blueprint, render_template, session, abort, Markup, request, redirect, send_from_directory, url_for
|
||||
from pprint import pprint, pformat
|
||||
from threading import Timer
|
||||
from bitcoin_info import *
|
||||
from lightning_info import *
|
||||
import base64
|
||||
import subprocess
|
||||
import json
|
||||
import pam
|
||||
import time
|
||||
import re
|
||||
import requests
|
||||
import os.path
|
||||
|
||||
|
||||
mynode_lnd = Blueprint('mynode_lnd',__name__)
|
||||
|
||||
# Flask Pages
|
||||
@mynode_lnd.route("/lnd")
|
||||
def page_lnd():
|
||||
height = 0
|
||||
alias = "empty"
|
||||
num_peers = "0"
|
||||
num_active_channels = "TODO"
|
||||
num_pending_channels = "TODO"
|
||||
num_inactive_channels = "TODO"
|
||||
pubkey = "abcd"
|
||||
uri = ""
|
||||
ip = ""
|
||||
status = "Starting..."
|
||||
|
||||
wallet_exists = lnd_wallet_exists()
|
||||
wallet_logged_in = is_lnd_logged_in()
|
||||
|
||||
message = ""
|
||||
if request.args.get('error_message'):
|
||||
message = Markup("<div class='error_message'>"+request.args.get('error_message')+"</div>")
|
||||
if request.args.get('success_message'):
|
||||
message = Markup("<div class='success_message'>"+request.args.get('success_message')+"</div>")
|
||||
|
||||
if not lnd_wallet_exists():
|
||||
templateData = {
|
||||
"title": "myNode Lightning Wallet",
|
||||
"wallet_exists": wallet_exists,
|
||||
"wallet_logged_in": wallet_logged_in,
|
||||
"status": status,
|
||||
"message": message
|
||||
}
|
||||
return render_template('lnd.html', **templateData)
|
||||
|
||||
if not is_lnd_logged_in():
|
||||
templateData = {
|
||||
"title": "myNode Lightning Wallet",
|
||||
"wallet_exists": wallet_exists,
|
||||
"wallet_logged_in": wallet_logged_in,
|
||||
"status": get_lnd_status(),
|
||||
"message": message
|
||||
}
|
||||
return render_template('lnd.html', **templateData)
|
||||
|
||||
try:
|
||||
data = get_lightning_info()
|
||||
|
||||
height = data['block_height']
|
||||
alias = data['alias']
|
||||
pubkey = data['identity_pubkey']
|
||||
if "num_peers" in data:
|
||||
num_peers = data['num_peers']
|
||||
if "synced_to_chain" in data and data['synced_to_chain']:
|
||||
status = "Active"
|
||||
else:
|
||||
status = get_lnd_status()
|
||||
if "uris" in data and len(data['uris']) > 0:
|
||||
uri = data['uris'][0]
|
||||
ip = uri.split("@")[1]
|
||||
else:
|
||||
uri = "..."
|
||||
ip = "..."
|
||||
except Exception as e:
|
||||
templateData = {
|
||||
"title": "myNode Lightning Status",
|
||||
"message": str(e)
|
||||
}
|
||||
return render_template('lnd_error.html', **templateData)
|
||||
|
||||
templateData = {
|
||||
"title": "myNode Lightning Status",
|
||||
"wallet_exists": wallet_exists,
|
||||
"wallet_logged_in": wallet_logged_in,
|
||||
"status": status,
|
||||
"height": height,
|
||||
"alias": alias,
|
||||
"num_peers": num_peers,
|
||||
"num_active_channels": num_active_channels,
|
||||
"num_pending_channels": num_pending_channels,
|
||||
"num_inactive_channels": num_inactive_channels,
|
||||
"pubkey": pubkey,
|
||||
"uri": uri,
|
||||
"ip": ip,
|
||||
"message": message
|
||||
}
|
||||
return render_template('lnd.html', **templateData)
|
||||
|
||||
@mynode_lnd.route("/lnd/tls.cert")
|
||||
def lnd_tls_cert():
|
||||
return send_from_directory(directory="/mnt/hdd/mynode/lnd/", filename="tls.cert")
|
||||
|
||||
@mynode_lnd.route("/lnd/admin.macaroon", methods=["POST"])
|
||||
def lnd_macaroon():
|
||||
p = pam.pam()
|
||||
pw = request.form.get('password_download_macaroon')
|
||||
if pw == None or p.authenticate("admin", pw) == False:
|
||||
return redirect(url_for(".page_lnd", error_message="Invalid Password"))
|
||||
|
||||
# Download macaroon
|
||||
return send_from_directory(directory="/mnt/hdd/mynode/lnd/data/chain/bitcoin/mainnet/", filename="admin.macaroon")
|
||||
|
||||
@mynode_lnd.route("/lnd/create_wallet")
|
||||
def page_lnd_create_wallet():
|
||||
|
||||
try:
|
||||
seed = gen_new_wallet_seed()
|
||||
session['seed'] = seed.strip()
|
||||
except:
|
||||
templateData = {
|
||||
"title": "myNode Lightning Wallet",
|
||||
"message": Markup("Waiting on lnd...<br/>Please try again in a minute.")
|
||||
}
|
||||
return render_template('lnd_error.html', **templateData)
|
||||
|
||||
templateData = {
|
||||
"title": "myNode Lightning Wallet",
|
||||
"seed": seed
|
||||
}
|
||||
return render_template('lnd_wallet_create.html', **templateData)
|
||||
|
||||
@mynode_lnd.route("/lnd/create_wallet_with_seed", methods=['GET','POST'])
|
||||
def page_lnd_create_wallet_with_seed():
|
||||
# Load page
|
||||
if request.method == 'GET':
|
||||
templateData = {
|
||||
"title": "myNode Lightning Wallet",
|
||||
}
|
||||
return render_template('lnd_wallet_create_with_seed.html', **templateData)
|
||||
|
||||
# Create wallet!
|
||||
seed = request.form.get('seed').strip()
|
||||
if create_wallet(seed):
|
||||
return redirect(url_for(".page_lnd", success_message="Wallet Created!"))
|
||||
|
||||
# Error creating wallet
|
||||
return redirect(url_for(".page_lnd", error_message="Error Creating Wallet"))
|
||||
|
||||
|
||||
@mynode_lnd.route("/lnd/create_wallet_confirm", methods=['GET','POST'])
|
||||
def page_lnd_create_wallet_confirm():
|
||||
# Load page
|
||||
if request.method == 'GET':
|
||||
templateData = {
|
||||
"title": "myNode Lightning Wallet",
|
||||
}
|
||||
return render_template('lnd_wallet_create_confirm.html', **templateData)
|
||||
|
||||
# Parse submission
|
||||
seed = request.form.get('seed').strip()
|
||||
if seed != session['seed']:
|
||||
session["seed"] = None
|
||||
return redirect(url_for(".page_lnd", error_message="Incorrect Seed"))
|
||||
session["seed"] = None
|
||||
|
||||
# Seed matches, create wallet!
|
||||
if create_wallet(seed):
|
||||
return redirect(url_for(".page_lnd", success_message="Wallet Created!"))
|
||||
|
||||
# Error creating wallet
|
||||
return redirect(url_for(".page_lnd", error_message="Error Creating Wallet"))
|
42
rootfs/free/var/www/mynode/messages.py
Normal file
|
@ -0,0 +1,42 @@
|
|||
import random
|
||||
|
||||
# Messages
|
||||
messages = []
|
||||
messages.append("'I think the internet is going to be one of the major forces for reducing the role of government. The one thing that's missing but that will soon be developed, is a reliable e-cash.' - Milton Friedman")
|
||||
messages.append("'The swarm is headed towards us' - Satoshi Nakamoto")
|
||||
messages.append("'Bitcoin seems to be a very promising idea. I like the idea of basing security on the assumption that the CPU power of honest participants outweighs that of the attacker. It is a very modern notion that exploits the power of the long tail.' - Hal Finney")
|
||||
messages.append("'Bitcoin enables certain uses that are very unique. I think it offers possibilities that no other currency allows. For example the ability to spend a coin that only occurs when two separate parties agree to spend the coin; with a third party that couldn't run away with the coin itself.' - Pieter Wuille")
|
||||
messages.append("'Hey, obviously this is a very interesting time to be in Bitcoin right now, but if you guys want to argue over whether this is reality or not, one Bitcoin will feed over 40 homeless people in Pensacola right now. If you guys want proof Bitcoin is real, send them to me, I'll cash them out and feed homeless people.' - Jason King")
|
||||
messages.append("'Bitcoin was created to serve a highly political intent, a free and uncensored network where all can participate with equal access.' - Amir Taaki")
|
||||
messages.append("'When I first heard about Bitcoin, I thought it was impossible. How can you have a purely digital currency? Can't I just copy your hard drive and have your bitcoins? I didn't understand how that could be done, and then I looked into it and it was brilliant' - Jeff Garzik")
|
||||
messages.append("'The bitcoin world is this new ecosystem where it doesn't cost that much to start a new bitcoin company, it doesn't cost much to start owning bitcoin either, and it is a much more efficient way of moving money around the world.' - Tim Draper")
|
||||
messages.append("'Cryptocurrency is such a powerful concept that it can almost overturn governments' - Charlie Lee")
|
||||
messages.append("'Bitcoin is a remarkable cryptographic achievement and the ability to create something that is not duplicable in the digital world has enormous value' - Eric Schmidt, CEO of Google")
|
||||
messages.append("'Bitcoin is a technological tour de force.' - Bill Gates")
|
||||
messages.append("'Lost coins only make everyone else's coins worth slightly more. Think of it as a donation to everyone.' - Satoshi Nakamoto")
|
||||
messages.append("'The Times 03/Jan/2009 Chancellor on brink of second bailout for banks.' - Satoshi Nakamoto")
|
||||
messages.append("'Your keys. Your bitcoin. Not your keys. Not your bitcoin!' - Andreas Antonopoulos")
|
||||
messages.append("'Running bitcoin' - Hal Finney @ 9:33 PM 10 Jan 2009")
|
||||
messages.append("'Since we're all rich with bitcoins, or we will be once they're worth a million dollars like everyone expects, we ought to put some of this unearned wealth to good use.' - Hal Finney")
|
||||
messages.append("'I see Bitcoin as ultimately becoming a reserve currency for banks, playing much the same role as gold did in the early days of banking. Banks could issue digital cash with greater anonymity and lighter weight, more efficient transactions.' - Hal Finney")
|
||||
messages.append("Consider upgrading your myNode! mynodebtc.com")
|
||||
messages.append("mynodebtc.com")
|
||||
messages.append("Upgrading will give you RTL, LND Hub, LND Connect, Electrum Server, BTC explorer, channel backup, and MUCH more! mynodebtc.com")
|
||||
messages.append("If you like myNode Free, consider supporting us by upgrading at mynodebtc.com!")
|
||||
|
||||
# Funny messages
|
||||
funny_messages = []
|
||||
funny_messages.append("This may feel slow, but its better than 2 months!")
|
||||
funny_messages.append("I think I can. I think I can. I think I can.")
|
||||
funny_messages.append("Almost there! Stay on target!")
|
||||
funny_messages.append("Blockchains get big! Imagine if we had 64 MB blocks...")
|
||||
|
||||
|
||||
### Helper functions
|
||||
def get_message(include_funny=True):
|
||||
possible_messages = messages
|
||||
if include_funny:
|
||||
possible_messages = messages + funny_messages
|
||||
|
||||
msg = random.choice(possible_messages)
|
||||
return msg
|
296
rootfs/free/var/www/mynode/mynode.py
Normal file
|
@ -0,0 +1,296 @@
|
|||
|
||||
from config import *
|
||||
from flask import Flask, render_template, Markup, send_from_directory, redirect
|
||||
from bitcoind import mynode_bitcoind
|
||||
from lnd import mynode_lnd, lnd_wallet_exists, is_lnd_logged_in, lnd_get, get_lnd_status
|
||||
from settings import mynode_settings
|
||||
from pprint import pprint
|
||||
from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
|
||||
from background_thread import BackgroundThread
|
||||
from bitcoin_info import *
|
||||
from lightning_info import *
|
||||
from messages import get_message
|
||||
from thread_functions import *
|
||||
import random
|
||||
import logging
|
||||
import logging.handlers
|
||||
import requests
|
||||
import threading
|
||||
import signal
|
||||
import transmissionrpc
|
||||
import subprocess
|
||||
import os.path
|
||||
import psutil
|
||||
import time
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config['DEBUG'] = False
|
||||
app.config['TEMPLATES_AUTO_RELOAD'] = True
|
||||
app.register_blueprint(mynode_bitcoind)
|
||||
app.register_blueprint(mynode_lnd)
|
||||
app.register_blueprint(mynode_settings)
|
||||
|
||||
### Definitions
|
||||
STATE_DRIVE_MISSING = "drive_missing"
|
||||
STATE_DRIVE_MOUNTED = "drive_mounted"
|
||||
STATE_QUICKSYNC_DOWNLOAD = "quicksync_download"
|
||||
STATE_QUICKSYNC_COPY = "quicksync_copy"
|
||||
STATE_QUICKSYNC_RESET = "quicksync_reset"
|
||||
STATE_STABLE = "stable"
|
||||
|
||||
MYNODE_DIR = "/mnt/hdd/mynode"
|
||||
BITCOIN_DIR = "/mnt/hdd/mynode/bitcoin"
|
||||
LN_DIR = "/mnt/hdd/mynode/lnd"
|
||||
|
||||
### Global Variables
|
||||
need_to_stop = False
|
||||
|
||||
### Helper functions
|
||||
def get_status():
|
||||
status_file = "/mnt/hdd/mynode/.mynode_status"
|
||||
status = ""
|
||||
if (os.path.isfile(status_file)):
|
||||
try:
|
||||
with open(status_file, "r") as f:
|
||||
status = f.read().strip()
|
||||
except:
|
||||
status = STATE_DRIVE_MISSING
|
||||
else:
|
||||
status = STATE_DRIVE_MISSING
|
||||
return status
|
||||
|
||||
|
||||
# Exception to throw on exit
|
||||
class ServiceExit(Exception):
|
||||
pass
|
||||
|
||||
# Function to run on exit
|
||||
def on_shutdown(signum, frame):
|
||||
print('Caught signal %d' % signum)
|
||||
raise ServiceExit
|
||||
|
||||
|
||||
### Flask Page Processing
|
||||
@app.route("/")
|
||||
def index():
|
||||
status = get_status()
|
||||
|
||||
bitcoin_block_height = get_bitcoin_block_height()
|
||||
mynode_block_height = get_mynode_block_height()
|
||||
lnd_info = get_lightning_info()
|
||||
|
||||
if status == STATE_DRIVE_MISSING:
|
||||
templateData = {
|
||||
"title": "myNode Looking for Drive",
|
||||
"header_text": "Looking for Drive",
|
||||
"subheader_text": "Please attach a drive to your myNode"
|
||||
}
|
||||
return render_template('state.html', **templateData)
|
||||
elif status == STATE_DRIVE_MOUNTED:
|
||||
templateData = {
|
||||
"title": "myNode QuickSync",
|
||||
"header_text": "Drive Mounted",
|
||||
"subheader_text": "myNode starting soon..."
|
||||
}
|
||||
return render_template('state.html', **templateData)
|
||||
elif status == STATE_QUICKSYNC_COPY:
|
||||
try:
|
||||
current = subprocess.check_output(["du","-m","--max-depth=0","/mnt/hdd/mynode/bitcoin/"]).split()[0]
|
||||
total = subprocess.check_output(["du","-m","--max-depth=0","/mnt/hdd/mynode/quicksync/"]).split()[0]
|
||||
except:
|
||||
current = 0.0
|
||||
total = 100.0
|
||||
|
||||
total = float(total) * 1.3
|
||||
percent = (float(current) / float(total)) * 100.0
|
||||
if percent >= 99.99:
|
||||
percent = 99.99
|
||||
|
||||
message = "<div class='small_message'>{}</<div>".format( get_message() )
|
||||
|
||||
subheader_msg = Markup("Copying files... This will take several hours.<br/>{:.2f}%{}".format(percent, message))
|
||||
|
||||
templateData = {
|
||||
"title": "myNode QuickSync",
|
||||
"header_text": "QuickSync",
|
||||
"subheader_text": subheader_msg
|
||||
}
|
||||
return render_template('state.html', **templateData)
|
||||
elif status == STATE_QUICKSYNC_RESET:
|
||||
templateData = {
|
||||
"title": "myNode QuickSync",
|
||||
"header_text": "QuickSync",
|
||||
"subheader_text": "Restarting QuickSync..."
|
||||
}
|
||||
return render_template('state.html', **templateData)
|
||||
elif status == STATE_QUICKSYNC_DOWNLOAD:
|
||||
subheader = Markup("")
|
||||
try:
|
||||
tc = transmissionrpc.Client('localhost', port=9091)
|
||||
t = tc.get_torrent(1)
|
||||
|
||||
dl_rate = float(t.rateDownload) / 1000 / 1000
|
||||
complete = t.percentDone * 100
|
||||
|
||||
include_funny = False
|
||||
if dl_rate > 3.0:
|
||||
include_funny = True
|
||||
message = "<div class='small_message'>{}</<div>".format( get_message(include_funny) )
|
||||
|
||||
subheader = Markup("Downloading...<br/>{:.2f}%</br>{:.2f} MB/s{}".format(complete, dl_rate, message))
|
||||
except Exception as e:
|
||||
subheader = Markup("Starting<br/>Waiting on download client to start...")
|
||||
|
||||
templateData = {
|
||||
"title": "myNode QuickSync",
|
||||
"header_text": "QuickSync",
|
||||
"subheader_text": subheader
|
||||
}
|
||||
return render_template('state.html', **templateData)
|
||||
elif status == STATE_STABLE:
|
||||
bitcoind_status_code = os.system("systemctl status bitcoind --no-pager")
|
||||
lnd_status_code = os.system("systemctl status lnd --no-pager")
|
||||
bitcoind_status_color = "red"
|
||||
bitcoind_status = "Inactive"
|
||||
lnd_status_color = "red"
|
||||
lnd_ready = is_lnd_ready()
|
||||
lnd_status = "Inactive"
|
||||
|
||||
if not get_has_updated_btc_info():
|
||||
message = "<div class='small_message'>{}</<div>".format( get_message(include_funny=True) )
|
||||
templateData = {
|
||||
"title": "myNode Status",
|
||||
"header_text": "Starting...",
|
||||
"subheader_text": Markup("Launching myNode services...{}".format(message))
|
||||
}
|
||||
return render_template('state.html', **templateData)
|
||||
|
||||
# Display sync info if not synced
|
||||
if not is_bitcoind_synced():
|
||||
subheader = Markup("Syncing...")
|
||||
if bitcoin_block_height != None:
|
||||
message = "<div class='small_message'>{}</<div>".format( get_message(include_funny=True) )
|
||||
|
||||
remaining = bitcoin_block_height - mynode_block_height
|
||||
subheader = Markup("Syncing...<br/>Block {} of {}{}".format(mynode_block_height, bitcoin_block_height, message))
|
||||
templateData = {
|
||||
"title": "myNode Sync",
|
||||
"header_text": "Bitcoin Blockchain",
|
||||
"subheader_text": subheader
|
||||
}
|
||||
return render_template('state.html', **templateData)
|
||||
|
||||
# Find bitcoind status
|
||||
if bitcoind_status_code != 0:
|
||||
bitcoind_status_color = "red"
|
||||
else:
|
||||
bitcoind_status = "Validating blocks..."
|
||||
bitcoind_status_color = "green"
|
||||
if bitcoin_block_height != None:
|
||||
remaining = bitcoin_block_height - mynode_block_height
|
||||
if remaining == 0:
|
||||
bitcoind_status = "Running"
|
||||
else:
|
||||
bitcoind_status = "Syncing<br/>{} blocks remaining...".format(remaining)
|
||||
else:
|
||||
bitcoind_status = "Waiting for info..."
|
||||
|
||||
# Find lnd status
|
||||
if is_bitcoind_synced():
|
||||
lnd_status_color = "green"
|
||||
lnd_status = get_lnd_status()
|
||||
|
||||
# Get LND status
|
||||
if not lnd_wallet_exists():
|
||||
# This hides the restart /login attempt LND does from the GUI
|
||||
lnd_status_color = "green"
|
||||
elif lnd_status_code != 0:
|
||||
lnd_status_color = "red"
|
||||
if lnd_status == "Logging in...":
|
||||
lnd_status_color = "yellow"
|
||||
else:
|
||||
lnd_status_color = "yellow"
|
||||
lnd_status = "Waiting..."
|
||||
|
||||
templateData = {
|
||||
"title": "myNode Home",
|
||||
"config": CONFIG,
|
||||
"bitcoind_status_color": bitcoind_status_color,
|
||||
"bitcoind_status": Markup(bitcoind_status),
|
||||
"lnd_status_color": lnd_status_color,
|
||||
"lnd_status": Markup(lnd_status),
|
||||
"lnd_ready": lnd_ready,
|
||||
"drive_usage": get_drive_usage(),
|
||||
"cpu_usage": get_cpu_usage(),
|
||||
"ram_usage": get_ram_usage(),
|
||||
"swap_usage": get_swap_usage()
|
||||
}
|
||||
return render_template('main.html', **templateData)
|
||||
else:
|
||||
templateData = {
|
||||
"title": "myNode Error",
|
||||
"header_text": "Error",
|
||||
"subheader_text": "Unknown State ("+status+"). Please restart your myNode."
|
||||
}
|
||||
return render_template('state.html', **templateData)
|
||||
|
||||
@app.route("/about")
|
||||
def page_about():
|
||||
return render_template('about.html')
|
||||
|
||||
@app.route("/help")
|
||||
def page_help():
|
||||
return render_template('help.html')
|
||||
|
||||
# Disable browser caching
|
||||
@app.after_request
|
||||
def set_response_headers(response):
|
||||
response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
|
||||
response.headers['Pragma'] = 'no-cache'
|
||||
response.headers['Expires'] = '0'
|
||||
return response
|
||||
|
||||
if __name__ == "__main__":
|
||||
signal.signal(signal.SIGTERM, on_shutdown)
|
||||
signal.signal(signal.SIGINT, on_shutdown)
|
||||
btc_thread1 = BackgroundThread(update_bitcoin_main_info_thread, 60)
|
||||
btc_thread1.start()
|
||||
btc_thread2 = BackgroundThread(update_bitcoin_other_info_thread, 60)
|
||||
btc_thread2.start()
|
||||
lnd_thread = BackgroundThread(update_lnd_info_thread, 60)
|
||||
lnd_thread.start()
|
||||
drive_thread = BackgroundThread(update_device_info, 60)
|
||||
drive_thread.start()
|
||||
checkin_thread = BackgroundThread(check_in, 60*60*24) # Per-day checkin
|
||||
checkin_thread.start()
|
||||
|
||||
my_logger = logging.getLogger('FlaskLogger')
|
||||
my_logger.setLevel(logging.DEBUG)
|
||||
handler = logging.handlers.RotatingFileHandler(filename='/var/log/flask', maxBytes=2000000, backupCount=2)
|
||||
my_logger.addHandler(handler)
|
||||
app.logger.addHandler(my_logger)
|
||||
|
||||
app.secret_key = 'NoZlPx7t15foPfKpivbVrTrTy2bTQ99chJoz3LFmf5BFsh3Nz4ud0mMpGjtB4bhP'
|
||||
|
||||
try:
|
||||
app.run(host='0.0.0.0', port=80)
|
||||
except ServiceExit:
|
||||
# Stop background thread
|
||||
print("Killing {}".format(btc_thread1.pid))
|
||||
os.kill(btc_thread1.pid, signal.SIGKILL)
|
||||
print("Killing {}".format(btc_thread2.pid))
|
||||
os.kill(btc_thread2.pid, signal.SIGKILL)
|
||||
print("Killing {}".format(lnd_thread.pid))
|
||||
os.kill(lnd_thread.pid, signal.SIGKILL)
|
||||
print("Killing {}".format(drive_thread.pid))
|
||||
os.kill(drive_thread.pid, signal.SIGKILL)
|
||||
print("Killing {}".format(checkin_thread.pid))
|
||||
os.kill(checkin_thread.pid, signal.SIGKILL)
|
||||
|
||||
# Shutdown Flask
|
||||
func = request.environ.get('werkzeug.server.shutdown')
|
||||
if func is None:
|
||||
raise RuntimeError('Not running with the Werkzeug Server')
|
||||
func()
|
||||
|
||||
print("Service www exiting...")
|
280
rootfs/free/var/www/mynode/settings.py
Normal file
|
@ -0,0 +1,280 @@
|
|||
from config import *
|
||||
from flask import Blueprint, render_template, session, abort, Markup, request, redirect, send_from_directory
|
||||
from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
|
||||
from pprint import pprint, pformat
|
||||
from threading import Timer
|
||||
from device_info import *
|
||||
import pam
|
||||
import json
|
||||
import time
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
mynode_settings = Blueprint('mynode_settings',__name__)
|
||||
|
||||
def restart_lnd_actual():
|
||||
os.system("systemctl restart lnd")
|
||||
os.system("systemctl restart lnd_admin")
|
||||
|
||||
def restart_lnd():
|
||||
t = Timer(1.0, restart_lnd_actual)
|
||||
t.start()
|
||||
|
||||
def stop_bitcoind():
|
||||
os.system("systemctl stop bitcoind")
|
||||
|
||||
def stop_quickcync():
|
||||
os.system("systemctl stop quicksync")
|
||||
|
||||
def reset_bitcoin_env_file():
|
||||
os.system("echo 'BTCARGS=' > "+BITCOIN_ENV_FILE)
|
||||
|
||||
def delete_bitcoin_data():
|
||||
os.system("rm -rf /mnt/hdd/mynode/bitcoin")
|
||||
os.system("rm -rf /mnt/hdd/mynode/quicksync/.quicksync_complete")
|
||||
os.system("rm -rf /home/bitcoin/.mynode/.btcrpc_environment")
|
||||
os.system("rm -rf /home/bitcoin/.mynode/.btcrpcpw")
|
||||
|
||||
def delete_quicksync_data():
|
||||
os.system("rm -rf /mnt/hdd/mynode/quicksync")
|
||||
os.system("rm -rf /home/bitcoin/.config/transmission")
|
||||
|
||||
def delete_lnd_data():
|
||||
#os.system("rm -f "+LND_WALLET_FILE)
|
||||
os.system("rm -rf "+LND_DATA_FOLDER)
|
||||
os.system("rm -rf /home/bitcoin/.mynode/.lndpw")
|
||||
os.system("rm -rf /home/admin/.lnd/")
|
||||
return True
|
||||
|
||||
def reboot_device():
|
||||
os.system("reboot")
|
||||
|
||||
def reset_blockchain():
|
||||
stop_bitcoind()
|
||||
delete_bitcoin_data()
|
||||
reboot_device()
|
||||
|
||||
def restart_quicksync():
|
||||
os.system('echo "quicksync_reset" > /mnt/hdd/mynode/.mynode_status')
|
||||
stop_bitcoind()
|
||||
stop_quickcync()
|
||||
delete_bitcoin_data()
|
||||
delete_quicksync_data()
|
||||
reboot_device()
|
||||
|
||||
def factory_reset():
|
||||
# Reset subsystems that have local data
|
||||
delete_quicksync_data()
|
||||
|
||||
# Delete LND data
|
||||
delete_lnd_data()
|
||||
|
||||
# Disable services
|
||||
os.system("systemctl disable electrs")
|
||||
|
||||
# Trigger drive to be reformatted on reboot
|
||||
os.system("rm -f /mnt/hdd/.mynode")
|
||||
|
||||
# Reset password
|
||||
os.system("/usr/bin/mynode_chpasswd.sh bolt")
|
||||
|
||||
# Reboot
|
||||
reboot_device()
|
||||
|
||||
def upgrade_device():
|
||||
# Upgrade
|
||||
os.system("/usr/bin/mynode_upgrade.sh")
|
||||
|
||||
# Reboot
|
||||
reboot_device()
|
||||
|
||||
|
||||
# Flask Pages
|
||||
@mynode_settings.route("/settings")
|
||||
def page_settings():
|
||||
|
||||
current_version = get_current_version()
|
||||
latest_version = get_latest_version()
|
||||
|
||||
serial_number = get_device_serial()
|
||||
product_key = "free"
|
||||
|
||||
templateData = {
|
||||
"title": "myNode Settings",
|
||||
"password_message": "",
|
||||
"current_version": current_version,
|
||||
"latest_version": latest_version,
|
||||
"serial_number": serial_number,
|
||||
"product_key": product_key
|
||||
}
|
||||
return render_template('settings.html', **templateData)
|
||||
|
||||
@mynode_settings.route("/settings/upgrade")
|
||||
def upgrade_page():
|
||||
# Upgrade device
|
||||
t = Timer(1.0, upgrade_device)
|
||||
t.start()
|
||||
|
||||
# Display wait page
|
||||
templateData = {
|
||||
"title": "myNode Upgrade",
|
||||
"header_text": "Upgrading",
|
||||
"subheader_text": "This will take several minutes..."
|
||||
}
|
||||
return render_template('reboot.html', **templateData)
|
||||
|
||||
@mynode_settings.route("/settings/get-latest-version")
|
||||
def get_latest_version_page():
|
||||
update_latest_version()
|
||||
return redirect("/settings")
|
||||
|
||||
@mynode_settings.route("/settings/reset-blockchain")
|
||||
def reset_blockchain_page():
|
||||
t = Timer(1.0, reset_blockchain)
|
||||
t.start()
|
||||
|
||||
# Display wait page
|
||||
templateData = {
|
||||
"title": "myNode",
|
||||
"header_text": "Reset Blockchain",
|
||||
"subheader_text": "This will take several minutes..."
|
||||
}
|
||||
return render_template('reboot.html', **templateData)
|
||||
|
||||
@mynode_settings.route("/settings/restart-quicksync")
|
||||
def restart_quicksync_page():
|
||||
t = Timer(1.0, restart_quicksync)
|
||||
t.start()
|
||||
|
||||
# Display wait page
|
||||
templateData = {
|
||||
"title": "myNode",
|
||||
"header_text": "Restart Quicksync",
|
||||
"subheader_text": "This will take several minutes..."
|
||||
}
|
||||
return render_template('reboot.html', **templateData)
|
||||
|
||||
@mynode_settings.route("/settings/reboot-device")
|
||||
def reboot_device_page():
|
||||
# Trigger reboot
|
||||
t = Timer(1.0, reboot_device)
|
||||
t.start()
|
||||
|
||||
# Wait until device is restarted
|
||||
templateData = {
|
||||
"title": "myNode Reboot",
|
||||
"header_text": "Restarting",
|
||||
"subheader_text": "This will take several minutes..."
|
||||
}
|
||||
return render_template('reboot.html', **templateData)
|
||||
|
||||
@mynode_settings.route("/settings/reindex-blockchain")
|
||||
def reindex_blockchain_page():
|
||||
os.system("echo 'BTCARGS=-reindex-chainstate' > "+BITCOIN_ENV_FILE)
|
||||
os.system("systemctl restart bitcoind")
|
||||
t = Timer(30.0, reset_bitcoin_env_file)
|
||||
t.start()
|
||||
return redirect("/settings")
|
||||
|
||||
@mynode_settings.route("/settings/rescan-blockchain")
|
||||
def rescan_blockchain_page():
|
||||
os.system("echo 'BTCARGS=-rescan' > "+BITCOIN_ENV_FILE)
|
||||
os.system("systemctl restart bitcoind")
|
||||
t = Timer(30.0, reset_bitcoin_env_file)
|
||||
t.start()
|
||||
return redirect("/settings")
|
||||
|
||||
@mynode_settings.route("/settings/factory-reset", methods=['POST'])
|
||||
def factory_reset_page():
|
||||
p = pam.pam()
|
||||
pw = request.form.get('password_factory_reset')
|
||||
if pw == None or p.authenticate("admin", pw) == False:
|
||||
message = "<div class='error_message'>Invalid Password</div>"
|
||||
templateData = {
|
||||
"title": "myNode Settings",
|
||||
"overall_message": Markup(message)
|
||||
}
|
||||
return render_template('settings.html', **templateData)
|
||||
else:
|
||||
t = Timer(2.0, factory_reset)
|
||||
t.start()
|
||||
|
||||
templateData = {
|
||||
"title": "myNode Factory Reset",
|
||||
"header_text": "Factory Reset",
|
||||
"subheader_text": "This will take several minutes..."
|
||||
}
|
||||
return render_template('reboot.html', **templateData)
|
||||
|
||||
|
||||
@mynode_settings.route("/settings/password", methods=['POST'])
|
||||
def change_password_page():
|
||||
if not request:
|
||||
return redirect("/settings")
|
||||
|
||||
message = "<div class='success_message'>Successfully changed password!</div>"
|
||||
|
||||
# Verify current password
|
||||
p = pam.pam()
|
||||
current = request.form.get('current_password')
|
||||
if current == None or p.authenticate("admin", current) == False:
|
||||
message = "<div class='error_message'>Incorrect password</div>"
|
||||
templateData = {
|
||||
"title": "myNode Settings",
|
||||
"password_message": Markup(message)
|
||||
}
|
||||
return render_template('settings.html', **templateData)
|
||||
|
||||
p1 = request.form.get('password1')
|
||||
p2 = request.form.get('password2')
|
||||
|
||||
if p1 == None or p2 == None or p1 == "" or p2 == "" or p1 != p2:
|
||||
message = "<div class='error_message'>Passwords did not match or were empty!</div>"
|
||||
else:
|
||||
# Change password
|
||||
subprocess.call(['/usr/bin/mynode_chpasswd.sh', p1])
|
||||
|
||||
templateData = {
|
||||
"title": "myNode Settings",
|
||||
"password_message": Markup(message)
|
||||
}
|
||||
return render_template('settings.html', **templateData)
|
||||
|
||||
|
||||
@mynode_settings.route("/settings/delete-lnd-wallet", methods=['POST'])
|
||||
def page_lnd_delete_wallet():
|
||||
|
||||
p = pam.pam()
|
||||
pw = request.form.get('password_lnd_delete')
|
||||
if pw == None or p.authenticate("admin", pw) == False:
|
||||
message = "<div class='error_message'>Invalid Password</div>"
|
||||
templateData = {
|
||||
"title": "myNode Settings",
|
||||
"overall_message": Markup(message)
|
||||
}
|
||||
return render_template('settings.html', **templateData)
|
||||
else:
|
||||
# Successful Auth
|
||||
delete_lnd_data()
|
||||
restart_lnd()
|
||||
|
||||
message = "<div class='success_message'>Lighting Wallet Deleted!</div>"
|
||||
templateData = {
|
||||
"title": "myNode Settings",
|
||||
"overall_message": Markup(message)
|
||||
}
|
||||
return render_template('settings.html', **templateData)
|
||||
|
||||
@mynode_settings.route("/settings/mynode_logs.tar.gz")
|
||||
def download_logs_page():
|
||||
os.system("rm -rf /tmp/mynode_logs.tar.gz")
|
||||
os.system("rm -rf /tmp/mynode_info/")
|
||||
os.system("mkdir -p /tmp/mynode_info/")
|
||||
os.system("mynode-get-quicksync-status > /tmp/mynode_info/quicksync_state.txt")
|
||||
os.system("cp /usr/share/version /tmp/mynode_info/version")
|
||||
os.system("tar -czvf /tmp/mynode_logs.tar.gz /var/log/ /tmp/mynode_info/")
|
||||
return send_from_directory(directory="/tmp/", filename="mynode_logs.tar.gz")
|
||||
|
||||
@mynode_settings.route("/settings/ping")
|
||||
def ping_page():
|
||||
return "alive"
|
315
rootfs/free/var/www/mynode/static/css/mynode.css
Normal file
|
@ -0,0 +1,315 @@
|
|||
.logo_header {
|
||||
margin: auto;
|
||||
width: 300px;
|
||||
padding-bottom: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.logo_image {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin: auto;
|
||||
padding-top: 25px;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
a:link {
|
||||
color: black;
|
||||
text-decoration: underline dashed orange;
|
||||
}
|
||||
a:visited {
|
||||
color: black;
|
||||
text-decoration: underline dashed orange;
|
||||
}
|
||||
a:hover {
|
||||
color: black;
|
||||
text-decoration: underline solid orange;
|
||||
}
|
||||
a:active {
|
||||
color: black;
|
||||
text-decoration: underline dashed orange;
|
||||
}
|
||||
|
||||
.mynode_back_div {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
}
|
||||
|
||||
.state_header {
|
||||
color: #555555;
|
||||
text-align: center;
|
||||
font-size: 56px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
.state_subheader {
|
||||
color: #555555;
|
||||
text-align: center;
|
||||
font-size: 28px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
.main_header {
|
||||
color: #555555;
|
||||
text-align: center;
|
||||
font-size: 32px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.main_header_sub_text {
|
||||
width: 600px;
|
||||
color: #444444;
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.error_message {
|
||||
color: red;
|
||||
font-size: 16px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.success_message {
|
||||
color: green;
|
||||
font-size: 16px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.app_tile_row {
|
||||
margin: auto;
|
||||
display: flex;
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.app_tile {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
border: 3px solid orange;
|
||||
border-radius: 20px;
|
||||
width: 130px;
|
||||
min-width: 130px;
|
||||
height: 180px;
|
||||
padding: 10px;
|
||||
margin: 10px;
|
||||
}
|
||||
.app_tile_short {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
border: 3px solid orange;
|
||||
border-radius: 20px;
|
||||
width: 130px;
|
||||
min-width: 130px;
|
||||
height: 140px;
|
||||
padding: 10px;
|
||||
margin: 10px;
|
||||
}
|
||||
.green { background-color: green; }
|
||||
.yellow { background-color: yellow; }
|
||||
.red { background-color: red; }
|
||||
.gray { background-color: gray; }
|
||||
|
||||
.green_text {color: green;}
|
||||
.yellow_text {color: yellow;}
|
||||
.red_text {color: red;}
|
||||
|
||||
.app_status_icon {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
border-radius: 50%;
|
||||
-moz-border-radius: 50%;
|
||||
-webkit-border-radius: 50%;
|
||||
}
|
||||
.app_logo {
|
||||
margin: auto;
|
||||
height: 55px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
.app_logo_icon {
|
||||
margin: auto;
|
||||
display: block;
|
||||
width: 40%;
|
||||
}
|
||||
.app_title {
|
||||
font-size: 18px;
|
||||
text-align: center;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.app_status {
|
||||
font-size: 12px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
line-height: 130%;
|
||||
}
|
||||
.app_contents {
|
||||
font-size: 12px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
width: 130px;
|
||||
bottom: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info_tile {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
border: 3px solid orange;
|
||||
border-radius: 25px;
|
||||
min-width: 120px;
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.info_tile_header {
|
||||
border-top-left-radius: 20px;
|
||||
border-top-right-radius: 20px;
|
||||
font-size: 18px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
color: #FFFFFF;
|
||||
background-color: orange;
|
||||
padding: 5px 10px 5px 10px;
|
||||
margin-top: -2px;
|
||||
}
|
||||
.info_tile_contents {
|
||||
margin-top: 5px;
|
||||
font-size: 16px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
vertical-align: middle;
|
||||
padding: 5px 10px 5px 10px;
|
||||
}
|
||||
|
||||
.content_block {
|
||||
width: 600px;
|
||||
color: #444444;
|
||||
margin: auto;
|
||||
text-align: justify;
|
||||
font-size: 14px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.mynode_button {
|
||||
width: 80%;
|
||||
font-size: 14px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.mynode_button_small {
|
||||
font-size: 12px !important;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
.drive_usage {
|
||||
margin-bottom: 25px;
|
||||
font-size: 24px;
|
||||
color: #222222;
|
||||
}
|
||||
|
||||
.settings_block_header {
|
||||
color: #333333;
|
||||
border: 3px solid orange;
|
||||
border-radius: 25px;
|
||||
text-align: center;
|
||||
display: block;
|
||||
font-size: 24px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
padding: 5px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.settings_block_subheader {
|
||||
color: #333333;
|
||||
text-align: left;
|
||||
font-size: 18px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.settings_block {
|
||||
width: 600px;
|
||||
color: #444444;
|
||||
margin: auto;
|
||||
text-align: justify;
|
||||
font-size: 14px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.divider {
|
||||
width: 100%;
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
border-bottom: 3px dashed orange;
|
||||
}
|
||||
.settings_button {
|
||||
font-size: 14px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.settings_button_small {
|
||||
font-size: 10px !important;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
.settings_input {
|
||||
font-size: 14px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
.seed_textbox {
|
||||
width: 99%;
|
||||
height: 120px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.small_message {
|
||||
width: 500px;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
text-align: center;
|
||||
padding-top: 40px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
#lndconnect_tabs {
|
||||
margin: auto;
|
||||
width: 500px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 10px;
|
||||
line-height: 1.2;
|
||||
word-wrap: break-word;
|
||||
text-align: center;
|
||||
}
|
||||
.lndconnect_qr_code {
|
||||
width: 300px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.upgrade_ad_main_page {
|
||||
color: #333333;
|
||||
border: 3px solid orange;
|
||||
background-color: rgb(255, 250, 238);
|
||||
width: 600px;
|
||||
border-radius: 25px;
|
||||
text-align: justify;
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
padding: 5px;
|
||||
margin: auto;
|
||||
margin-bottom: 20px;
|
||||
}
|
63
rootfs/free/var/www/mynode/static/css/mynode_bitcoind.css
Normal file
|
@ -0,0 +1,63 @@
|
|||
|
||||
.bitcoind_search {
|
||||
width: 600px;
|
||||
margin: auto;
|
||||
display: table;
|
||||
padding: 10px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.bitcoind_search_input {
|
||||
width: 480px;
|
||||
font-size: 20px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.bitcoind_search_button {
|
||||
width: 100px;
|
||||
font-size: 16px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.bitcoind_search_text {
|
||||
font-size: 12px;
|
||||
font-style: italic;
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
.bitcoind_error_message {
|
||||
color: #BB4444;
|
||||
text-align: center;
|
||||
font-size: 28px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.bitcoind_table {
|
||||
width: 600px;
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
font-size: 14px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.bitcoind_table_header {
|
||||
font-size: 16px;
|
||||
background-color: #FFFFFF;
|
||||
font-weight: bold;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
table tbody tr:nth-child(odd) td{
|
||||
background-color: #ffdecb;
|
||||
}
|
||||
table tbody tr:nth-child(even) td{
|
||||
background-color: #fff5ef;
|
||||
}
|
||||
|
||||
table td {
|
||||
padding: 10px;
|
||||
margin: 0px;
|
||||
}
|
||||
.bitcoind_dump_contents {
|
||||
margin: auto;
|
||||
width: 600px;
|
||||
}
|
BIN
rootfs/free/var/www/mynode/static/images/bitcoin.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
rootfs/free/var/www/mynode/static/images/cpu.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
rootfs/free/var/www/mynode/static/images/drive.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
rootfs/free/var/www/mynode/static/images/explorer.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
rootfs/free/var/www/mynode/static/images/favicon.ico
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
rootfs/free/var/www/mynode/static/images/lightning.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
rootfs/free/var/www/mynode/static/images/loading.gif
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
rootfs/free/var/www/mynode/static/images/logo.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
rootfs/free/var/www/mynode/static/images/ram.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
rootfs/free/var/www/mynode/static/images/settings.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 6.2 KiB |
1312
rootfs/free/var/www/mynode/static/jquery_ui/jquery-ui.css
vendored
Normal file
18706
rootfs/free/var/www/mynode/static/jquery_ui/jquery-ui.js
vendored
Normal file
7
rootfs/free/var/www/mynode/static/jquery_ui/jquery-ui.min.css
vendored
Normal file
13
rootfs/free/var/www/mynode/static/jquery_ui/jquery-ui.min.js
vendored
Normal file
886
rootfs/free/var/www/mynode/static/jquery_ui/jquery-ui.structure.css
vendored
Normal file
|
@ -0,0 +1,886 @@
|
|||
/*!
|
||||
* jQuery UI CSS Framework 1.12.1
|
||||
* http://jqueryui.com
|
||||
*
|
||||
* Copyright jQuery Foundation and other contributors
|
||||
* Released under the MIT license.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://api.jqueryui.com/category/theming/
|
||||
*/
|
||||
/* Layout helpers
|
||||
----------------------------------*/
|
||||
.ui-helper-hidden {
|
||||
display: none;
|
||||
}
|
||||
.ui-helper-hidden-accessible {
|
||||
border: 0;
|
||||
clip: rect(0 0 0 0);
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
}
|
||||
.ui-helper-reset {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
line-height: 1.3;
|
||||
text-decoration: none;
|
||||
font-size: 100%;
|
||||
list-style: none;
|
||||
}
|
||||
.ui-helper-clearfix:before,
|
||||
.ui-helper-clearfix:after {
|
||||
content: "";
|
||||
display: table;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.ui-helper-clearfix:after {
|
||||
clear: both;
|
||||
}
|
||||
.ui-helper-zfix {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
filter:Alpha(Opacity=0); /* support: IE8 */
|
||||
}
|
||||
|
||||
.ui-front {
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
|
||||
/* Interaction Cues
|
||||
----------------------------------*/
|
||||
.ui-state-disabled {
|
||||
cursor: default !important;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
|
||||
/* Icons
|
||||
----------------------------------*/
|
||||
.ui-icon {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-top: -.25em;
|
||||
position: relative;
|
||||
text-indent: -99999px;
|
||||
overflow: hidden;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.ui-widget-icon-block {
|
||||
left: 50%;
|
||||
margin-left: -8px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Misc visuals
|
||||
----------------------------------*/
|
||||
|
||||
/* Overlays */
|
||||
.ui-widget-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.ui-accordion .ui-accordion-header {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
margin: 2px 0 0 0;
|
||||
padding: .5em .5em .5em .7em;
|
||||
font-size: 100%;
|
||||
}
|
||||
.ui-accordion .ui-accordion-content {
|
||||
padding: 1em 2.2em;
|
||||
border-top: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
.ui-autocomplete {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
cursor: default;
|
||||
}
|
||||
.ui-menu {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: block;
|
||||
outline: 0;
|
||||
}
|
||||
.ui-menu .ui-menu {
|
||||
position: absolute;
|
||||
}
|
||||
.ui-menu .ui-menu-item {
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
/* support: IE10, see #8844 */
|
||||
list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
|
||||
}
|
||||
.ui-menu .ui-menu-item-wrapper {
|
||||
position: relative;
|
||||
padding: 3px 1em 3px .4em;
|
||||
}
|
||||
.ui-menu .ui-menu-divider {
|
||||
margin: 5px 0;
|
||||
height: 0;
|
||||
font-size: 0;
|
||||
line-height: 0;
|
||||
border-width: 1px 0 0 0;
|
||||
}
|
||||
.ui-menu .ui-state-focus,
|
||||
.ui-menu .ui-state-active {
|
||||
margin: -1px;
|
||||
}
|
||||
|
||||
/* icon support */
|
||||
.ui-menu-icons {
|
||||
position: relative;
|
||||
}
|
||||
.ui-menu-icons .ui-menu-item-wrapper {
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
/* left-aligned */
|
||||
.ui-menu .ui-icon {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: .2em;
|
||||
margin: auto 0;
|
||||
}
|
||||
|
||||
/* right-aligned */
|
||||
.ui-menu .ui-menu-icon {
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
.ui-button {
|
||||
padding: .4em 1em;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
line-height: normal;
|
||||
margin-right: .1em;
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
/* Support: IE <= 11 */
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.ui-button,
|
||||
.ui-button:link,
|
||||
.ui-button:visited,
|
||||
.ui-button:hover,
|
||||
.ui-button:active {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* to make room for the icon, a width needs to be set here */
|
||||
.ui-button-icon-only {
|
||||
width: 2em;
|
||||
box-sizing: border-box;
|
||||
text-indent: -9999px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* no icon support for input elements */
|
||||
input.ui-button.ui-button-icon-only {
|
||||
text-indent: 0;
|
||||
}
|
||||
|
||||
/* button icon element(s) */
|
||||
.ui-button-icon-only .ui-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-top: -8px;
|
||||
margin-left: -8px;
|
||||
}
|
||||
|
||||
.ui-button.ui-icon-notext .ui-icon {
|
||||
padding: 0;
|
||||
width: 2.1em;
|
||||
height: 2.1em;
|
||||
text-indent: -9999px;
|
||||
white-space: nowrap;
|
||||
|
||||
}
|
||||
|
||||
input.ui-button.ui-icon-notext .ui-icon {
|
||||
width: auto;
|
||||
height: auto;
|
||||
text-indent: 0;
|
||||
white-space: normal;
|
||||
padding: .4em 1em;
|
||||
}
|
||||
|
||||
/* workarounds */
|
||||
/* Support: Firefox 5 - 40 */
|
||||
input.ui-button::-moz-focus-inner,
|
||||
button.ui-button::-moz-focus-inner {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.ui-controlgroup {
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
}
|
||||
.ui-controlgroup > .ui-controlgroup-item {
|
||||
float: left;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
.ui-controlgroup > .ui-controlgroup-item:focus,
|
||||
.ui-controlgroup > .ui-controlgroup-item.ui-visual-focus {
|
||||
z-index: 9999;
|
||||
}
|
||||
.ui-controlgroup-vertical > .ui-controlgroup-item {
|
||||
display: block;
|
||||
float: none;
|
||||
width: 100%;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
text-align: left;
|
||||
}
|
||||
.ui-controlgroup-vertical .ui-controlgroup-item {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.ui-controlgroup .ui-controlgroup-label {
|
||||
padding: .4em 1em;
|
||||
}
|
||||
.ui-controlgroup .ui-controlgroup-label span {
|
||||
font-size: 80%;
|
||||
}
|
||||
.ui-controlgroup-horizontal .ui-controlgroup-label + .ui-controlgroup-item {
|
||||
border-left: none;
|
||||
}
|
||||
.ui-controlgroup-vertical .ui-controlgroup-label + .ui-controlgroup-item {
|
||||
border-top: none;
|
||||
}
|
||||
.ui-controlgroup-horizontal .ui-controlgroup-label.ui-widget-content {
|
||||
border-right: none;
|
||||
}
|
||||
.ui-controlgroup-vertical .ui-controlgroup-label.ui-widget-content {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
/* Spinner specific style fixes */
|
||||
.ui-controlgroup-vertical .ui-spinner-input {
|
||||
|
||||
/* Support: IE8 only, Android < 4.4 only */
|
||||
width: 75%;
|
||||
width: calc( 100% - 2.4em );
|
||||
}
|
||||
.ui-controlgroup-vertical .ui-spinner .ui-spinner-up {
|
||||
border-top-style: solid;
|
||||
}
|
||||
|
||||
.ui-checkboxradio-label .ui-icon-background {
|
||||
box-shadow: inset 1px 1px 1px #ccc;
|
||||
border-radius: .12em;
|
||||
border: none;
|
||||
}
|
||||
.ui-checkboxradio-radio-label .ui-icon-background {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 1em;
|
||||
overflow: visible;
|
||||
border: none;
|
||||
}
|
||||
.ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon,
|
||||
.ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon {
|
||||
background-image: none;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-width: 4px;
|
||||
border-style: solid;
|
||||
}
|
||||
.ui-checkboxradio-disabled {
|
||||
pointer-events: none;
|
||||
}
|
||||
.ui-datepicker {
|
||||
width: 17em;
|
||||
padding: .2em .2em 0;
|
||||
display: none;
|
||||
}
|
||||
.ui-datepicker .ui-datepicker-header {
|
||||
position: relative;
|
||||
padding: .2em 0;
|
||||
}
|
||||
.ui-datepicker .ui-datepicker-prev,
|
||||
.ui-datepicker .ui-datepicker-next {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
width: 1.8em;
|
||||
height: 1.8em;
|
||||
}
|
||||
.ui-datepicker .ui-datepicker-prev-hover,
|
||||
.ui-datepicker .ui-datepicker-next-hover {
|
||||
top: 1px;
|
||||
}
|
||||
.ui-datepicker .ui-datepicker-prev {
|
||||
left: 2px;
|
||||
}
|
||||
.ui-datepicker .ui-datepicker-next {
|
||||
right: 2px;
|
||||
}
|
||||
.ui-datepicker .ui-datepicker-prev-hover {
|
||||
left: 1px;
|
||||
}
|
||||
.ui-datepicker .ui-datepicker-next-hover {
|
||||
right: 1px;
|
||||
}
|
||||
.ui-datepicker .ui-datepicker-prev span,
|
||||
.ui-datepicker .ui-datepicker-next span {
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
margin-left: -8px;
|
||||
top: 50%;
|
||||
margin-top: -8px;
|
||||
}
|
||||
.ui-datepicker .ui-datepicker-title {
|
||||
margin: 0 2.3em;
|
||||
line-height: 1.8em;
|
||||
text-align: center;
|
||||
}
|
||||
.ui-datepicker .ui-datepicker-title select {
|
||||
font-size: 1em;
|
||||
margin: 1px 0;
|
||||
}
|
||||
.ui-datepicker select.ui-datepicker-month,
|
||||
.ui-datepicker select.ui-datepicker-year {
|
||||
width: 45%;
|
||||
}
|
||||
.ui-datepicker table {
|
||||
width: 100%;
|
||||
font-size: .9em;
|
||||
border-collapse: collapse;
|
||||
margin: 0 0 .4em;
|
||||
}
|
||||
.ui-datepicker th {
|
||||
padding: .7em .3em;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
border: 0;
|
||||
}
|
||||
.ui-datepicker td {
|
||||
border: 0;
|
||||
padding: 1px;
|
||||
}
|
||||
.ui-datepicker td span,
|
||||
.ui-datepicker td a {
|
||||
display: block;
|
||||
padding: .2em;
|
||||
text-align: right;
|
||||
text-decoration: none;
|
||||
}
|
||||
.ui-datepicker .ui-datepicker-buttonpane {
|
||||
background-image: none;
|
||||
margin: .7em 0 0 0;
|
||||
padding: 0 .2em;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
.ui-datepicker .ui-datepicker-buttonpane button {
|
||||
float: right;
|
||||
margin: .5em .2em .4em;
|
||||
cursor: pointer;
|
||||
padding: .2em .6em .3em .6em;
|
||||
width: auto;
|
||||
overflow: visible;
|
||||
}
|
||||
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current {
|
||||
float: left;
|
||||
}
|
||||
|
||||
/* with multiple calendars */
|
||||
.ui-datepicker.ui-datepicker-multi {
|
||||
width: auto;
|
||||
}
|
||||
.ui-datepicker-multi .ui-datepicker-group {
|
||||
float: left;
|
||||
}
|
||||
.ui-datepicker-multi .ui-datepicker-group table {
|
||||
width: 95%;
|
||||
margin: 0 auto .4em;
|
||||
}
|
||||
.ui-datepicker-multi-2 .ui-datepicker-group {
|
||||
width: 50%;
|
||||
}
|
||||
.ui-datepicker-multi-3 .ui-datepicker-group {
|
||||
width: 33.3%;
|
||||
}
|
||||
.ui-datepicker-multi-4 .ui-datepicker-group {
|
||||
width: 25%;
|
||||
}
|
||||
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,
|
||||
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header {
|
||||
border-left-width: 0;
|
||||
}
|
||||
.ui-datepicker-multi .ui-datepicker-buttonpane {
|
||||
clear: left;
|
||||
}
|
||||
.ui-datepicker-row-break {
|
||||
clear: both;
|
||||
width: 100%;
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
/* RTL support */
|
||||
.ui-datepicker-rtl {
|
||||
direction: rtl;
|
||||
}
|
||||
.ui-datepicker-rtl .ui-datepicker-prev {
|
||||
right: 2px;
|
||||
left: auto;
|
||||
}
|
||||
.ui-datepicker-rtl .ui-datepicker-next {
|
||||
left: 2px;
|
||||
right: auto;
|
||||
}
|
||||
.ui-datepicker-rtl .ui-datepicker-prev:hover {
|
||||
right: 1px;
|
||||
left: auto;
|
||||
}
|
||||
.ui-datepicker-rtl .ui-datepicker-next:hover {
|
||||
left: 1px;
|
||||
right: auto;
|
||||
}
|
||||
.ui-datepicker-rtl .ui-datepicker-buttonpane {
|
||||
clear: right;
|
||||
}
|
||||
.ui-datepicker-rtl .ui-datepicker-buttonpane button {
|
||||
float: left;
|
||||
}
|
||||
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,
|
||||
.ui-datepicker-rtl .ui-datepicker-group {
|
||||
float: right;
|
||||
}
|
||||
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,
|
||||
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header {
|
||||
border-right-width: 0;
|
||||
border-left-width: 1px;
|
||||
}
|
||||
|
||||
/* Icons */
|
||||
.ui-datepicker .ui-icon {
|
||||
display: block;
|
||||
text-indent: -99999px;
|
||||
overflow: hidden;
|
||||
background-repeat: no-repeat;
|
||||
left: .5em;
|
||||
top: .3em;
|
||||
}
|
||||
.ui-dialog {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
padding: .2em;
|
||||
outline: 0;
|
||||
}
|
||||
.ui-dialog .ui-dialog-titlebar {
|
||||
padding: .4em 1em;
|
||||
position: relative;
|
||||
}
|
||||
.ui-dialog .ui-dialog-title {
|
||||
float: left;
|
||||
margin: .1em 0;
|
||||
white-space: nowrap;
|
||||
width: 90%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.ui-dialog .ui-dialog-titlebar-close {
|
||||
position: absolute;
|
||||
right: .3em;
|
||||
top: 50%;
|
||||
width: 20px;
|
||||
margin: -10px 0 0 0;
|
||||
padding: 1px;
|
||||
height: 20px;
|
||||
}
|
||||
.ui-dialog .ui-dialog-content {
|
||||
position: relative;
|
||||
border: 0;
|
||||
padding: .5em 1em;
|
||||
background: none;
|
||||
overflow: auto;
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane {
|
||||
text-align: left;
|
||||
border-width: 1px 0 0 0;
|
||||
background-image: none;
|
||||
margin-top: .5em;
|
||||
padding: .3em 1em .5em .4em;
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
|
||||
float: right;
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane button {
|
||||
margin: .5em .4em .5em 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
.ui-dialog .ui-resizable-n {
|
||||
height: 2px;
|
||||
top: 0;
|
||||
}
|
||||
.ui-dialog .ui-resizable-e {
|
||||
width: 2px;
|
||||
right: 0;
|
||||
}
|
||||
.ui-dialog .ui-resizable-s {
|
||||
height: 2px;
|
||||
bottom: 0;
|
||||
}
|
||||
.ui-dialog .ui-resizable-w {
|
||||
width: 2px;
|
||||
left: 0;
|
||||
}
|
||||
.ui-dialog .ui-resizable-se,
|
||||
.ui-dialog .ui-resizable-sw,
|
||||
.ui-dialog .ui-resizable-ne,
|
||||
.ui-dialog .ui-resizable-nw {
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
}
|
||||
.ui-dialog .ui-resizable-se {
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
.ui-dialog .ui-resizable-sw {
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
.ui-dialog .ui-resizable-ne {
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
.ui-dialog .ui-resizable-nw {
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.ui-draggable .ui-dialog-titlebar {
|
||||
cursor: move;
|
||||
}
|
||||
.ui-draggable-handle {
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
}
|
||||
.ui-resizable {
|
||||
position: relative;
|
||||
}
|
||||
.ui-resizable-handle {
|
||||
position: absolute;
|
||||
font-size: 0.1px;
|
||||
display: block;
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
}
|
||||
.ui-resizable-disabled .ui-resizable-handle,
|
||||
.ui-resizable-autohide .ui-resizable-handle {
|
||||
display: none;
|
||||
}
|
||||
.ui-resizable-n {
|
||||
cursor: n-resize;
|
||||
height: 7px;
|
||||
width: 100%;
|
||||
top: -5px;
|
||||
left: 0;
|
||||
}
|
||||
.ui-resizable-s {
|
||||
cursor: s-resize;
|
||||
height: 7px;
|
||||
width: 100%;
|
||||
bottom: -5px;
|
||||
left: 0;
|
||||
}
|
||||
.ui-resizable-e {
|
||||
cursor: e-resize;
|
||||
width: 7px;
|
||||
right: -5px;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
}
|
||||
.ui-resizable-w {
|
||||
cursor: w-resize;
|
||||
width: 7px;
|
||||
left: -5px;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
}
|
||||
.ui-resizable-se {
|
||||
cursor: se-resize;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
right: 1px;
|
||||
bottom: 1px;
|
||||
}
|
||||
.ui-resizable-sw {
|
||||
cursor: sw-resize;
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
left: -5px;
|
||||
bottom: -5px;
|
||||
}
|
||||
.ui-resizable-nw {
|
||||
cursor: nw-resize;
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
left: -5px;
|
||||
top: -5px;
|
||||
}
|
||||
.ui-resizable-ne {
|
||||
cursor: ne-resize;
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
right: -5px;
|
||||
top: -5px;
|
||||
}
|
||||
.ui-progressbar {
|
||||
height: 2em;
|
||||
text-align: left;
|
||||
overflow: hidden;
|
||||
}
|
||||
.ui-progressbar .ui-progressbar-value {
|
||||
margin: -1px;
|
||||
height: 100%;
|
||||
}
|
||||
.ui-progressbar .ui-progressbar-overlay {
|
||||
background: url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");
|
||||
height: 100%;
|
||||
filter: alpha(opacity=25); /* support: IE8 */
|
||||
opacity: 0.25;
|
||||
}
|
||||
.ui-progressbar-indeterminate .ui-progressbar-value {
|
||||
background-image: none;
|
||||
}
|
||||
.ui-selectable {
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
}
|
||||
.ui-selectable-helper {
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
border: 1px dotted black;
|
||||
}
|
||||
.ui-selectmenu-menu {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: none;
|
||||
}
|
||||
.ui-selectmenu-menu .ui-menu {
|
||||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup {
|
||||
font-size: 1em;
|
||||
font-weight: bold;
|
||||
line-height: 1.5;
|
||||
padding: 2px 0.4em;
|
||||
margin: 0.5em 0 0 0;
|
||||
height: auto;
|
||||
border: 0;
|
||||
}
|
||||
.ui-selectmenu-open {
|
||||
display: block;
|
||||
}
|
||||
.ui-selectmenu-text {
|
||||
display: block;
|
||||
margin-right: 20px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.ui-selectmenu-button.ui-button {
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
width: 14em;
|
||||
}
|
||||
.ui-selectmenu-icon.ui-icon {
|
||||
float: right;
|
||||
margin-top: 0;
|
||||
}
|
||||
.ui-slider {
|
||||
position: relative;
|
||||
text-align: left;
|
||||
}
|
||||
.ui-slider .ui-slider-handle {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
width: 1.2em;
|
||||
height: 1.2em;
|
||||
cursor: default;
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
}
|
||||
.ui-slider .ui-slider-range {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
font-size: .7em;
|
||||
display: block;
|
||||
border: 0;
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
/* support: IE8 - See #6727 */
|
||||
.ui-slider.ui-state-disabled .ui-slider-handle,
|
||||
.ui-slider.ui-state-disabled .ui-slider-range {
|
||||
filter: inherit;
|
||||
}
|
||||
|
||||
.ui-slider-horizontal {
|
||||
height: .8em;
|
||||
}
|
||||
.ui-slider-horizontal .ui-slider-handle {
|
||||
top: -.3em;
|
||||
margin-left: -.6em;
|
||||
}
|
||||
.ui-slider-horizontal .ui-slider-range {
|
||||
top: 0;
|
||||
height: 100%;
|
||||
}
|
||||
.ui-slider-horizontal .ui-slider-range-min {
|
||||
left: 0;
|
||||
}
|
||||
.ui-slider-horizontal .ui-slider-range-max {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.ui-slider-vertical {
|
||||
width: .8em;
|
||||
height: 100px;
|
||||
}
|
||||
.ui-slider-vertical .ui-slider-handle {
|
||||
left: -.3em;
|
||||
margin-left: 0;
|
||||
margin-bottom: -.6em;
|
||||
}
|
||||
.ui-slider-vertical .ui-slider-range {
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
.ui-slider-vertical .ui-slider-range-min {
|
||||
bottom: 0;
|
||||
}
|
||||
.ui-slider-vertical .ui-slider-range-max {
|
||||
top: 0;
|
||||
}
|
||||
.ui-sortable-handle {
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
}
|
||||
.ui-spinner {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.ui-spinner-input {
|
||||
border: none;
|
||||
background: none;
|
||||
color: inherit;
|
||||
padding: .222em 0;
|
||||
margin: .2em 0;
|
||||
vertical-align: middle;
|
||||
margin-left: .4em;
|
||||
margin-right: 2em;
|
||||
}
|
||||
.ui-spinner-button {
|
||||
width: 1.6em;
|
||||
height: 50%;
|
||||
font-size: .5em;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
cursor: default;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
right: 0;
|
||||
}
|
||||
/* more specificity required here to override default borders */
|
||||
.ui-spinner a.ui-spinner-button {
|
||||
border-top-style: none;
|
||||
border-bottom-style: none;
|
||||
border-right-style: none;
|
||||
}
|
||||
.ui-spinner-up {
|
||||
top: 0;
|
||||
}
|
||||
.ui-spinner-down {
|
||||
bottom: 0;
|
||||
}
|
||||
.ui-tabs {
|
||||
position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
|
||||
padding: .2em;
|
||||
}
|
||||
.ui-tabs .ui-tabs-nav {
|
||||
margin: 0;
|
||||
padding: .2em .2em 0;
|
||||
}
|
||||
.ui-tabs .ui-tabs-nav li {
|
||||
list-style: none;
|
||||
float: left;
|
||||
position: relative;
|
||||
top: 0;
|
||||
margin: 1px .2em 0 0;
|
||||
border-bottom-width: 0;
|
||||
padding: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.ui-tabs .ui-tabs-nav .ui-tabs-anchor {
|
||||
float: left;
|
||||
padding: .5em 1em;
|
||||
text-decoration: none;
|
||||
}
|
||||
.ui-tabs .ui-tabs-nav li.ui-tabs-active {
|
||||
margin-bottom: -1px;
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,
|
||||
.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,
|
||||
.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor {
|
||||
cursor: text;
|
||||
}
|
||||
.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor {
|
||||
cursor: pointer;
|
||||
}
|
||||
.ui-tabs .ui-tabs-panel {
|
||||
display: block;
|
||||
border-width: 0;
|
||||
padding: 1em 1.4em;
|
||||
background: none;
|
||||
}
|
||||
.ui-tooltip {
|
||||
padding: 8px;
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
max-width: 300px;
|
||||
}
|
||||
body .ui-tooltip {
|
||||
border-width: 2px;
|
||||
}
|
5
rootfs/free/var/www/mynode/static/jquery_ui/jquery-ui.structure.min.css
vendored
Normal file
443
rootfs/free/var/www/mynode/static/jquery_ui/jquery-ui.theme.css
vendored
Normal file
|
@ -0,0 +1,443 @@
|
|||
/*!
|
||||
* jQuery UI CSS Framework 1.12.1
|
||||
* http://jqueryui.com
|
||||
*
|
||||
* Copyright jQuery Foundation and other contributors
|
||||
* Released under the MIT license.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://api.jqueryui.com/category/theming/
|
||||
*
|
||||
* To view and modify this theme, visit http://jqueryui.com/themeroller/?bgShadowXPos=&bgOverlayXPos=&bgErrorXPos=&bgHighlightXPos=&bgContentXPos=&bgHeaderXPos=&bgActiveXPos=&bgHoverXPos=&bgDefaultXPos=&bgShadowYPos=&bgOverlayYPos=&bgErrorYPos=&bgHighlightYPos=&bgContentYPos=&bgHeaderYPos=&bgActiveYPos=&bgHoverYPos=&bgDefaultYPos=&bgShadowRepeat=&bgOverlayRepeat=&bgErrorRepeat=&bgHighlightRepeat=&bgContentRepeat=&bgHeaderRepeat=&bgActiveRepeat=&bgHoverRepeat=&bgDefaultRepeat=&iconsHover=url(%22images%2Fui-icons_555555_256x240.png%22)&iconsHighlight=url(%22images%2Fui-icons_777620_256x240.png%22)&iconsHeader=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsError=url(%22images%2Fui-icons_cc0000_256x240.png%22)&iconsDefault=url(%22images%2Fui-icons_777777_256x240.png%22)&iconsContent=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsActive=url(%22images%2Fui-icons_ffffff_256x240.png%22)&bgImgUrlShadow=&bgImgUrlOverlay=&bgImgUrlHover=&bgImgUrlHighlight=&bgImgUrlHeader=&bgImgUrlError=&bgImgUrlDefault=&bgImgUrlContent=&bgImgUrlActive=&opacityFilterShadow=Alpha(Opacity%3D30)&opacityFilterOverlay=Alpha(Opacity%3D30)&opacityShadowPerc=30&opacityOverlayPerc=30&iconColorHover=%23555555&iconColorHighlight=%23777620&iconColorHeader=%23444444&iconColorError=%23cc0000&iconColorDefault=%23777777&iconColorContent=%23444444&iconColorActive=%23ffffff&bgImgOpacityShadow=0&bgImgOpacityOverlay=0&bgImgOpacityError=95&bgImgOpacityHighlight=55&bgImgOpacityContent=75&bgImgOpacityHeader=75&bgImgOpacityActive=65&bgImgOpacityHover=75&bgImgOpacityDefault=75&bgTextureShadow=flat&bgTextureOverlay=flat&bgTextureError=flat&bgTextureHighlight=flat&bgTextureContent=flat&bgTextureHeader=flat&bgTextureActive=flat&bgTextureHover=flat&bgTextureDefault=flat&cornerRadius=3px&fwDefault=normal&ffDefault=Arial%2CHelvetica%2Csans-serif&fsDefault=1em&cornerRadiusShadow=8px&thicknessShadow=5px&offsetLeftShadow=0px&offsetTopShadow=0px&opacityShadow=.3&bgColorShadow=%23666666&opacityOverlay=.3&bgColorOverlay=%23aaaaaa&fcError=%235f3f3f&borderColorError=%23f1a899&bgColorError=%23fddfdf&fcHighlight=%23777620&borderColorHighlight=%23dad55e&bgColorHighlight=%23fffa90&fcContent=%23333333&borderColorContent=%23dddddd&bgColorContent=%23ffffff&fcHeader=%23333333&borderColorHeader=%23dddddd&bgColorHeader=%23e9e9e9&fcActive=%23ffffff&borderColorActive=%23003eff&bgColorActive=%23007fff&fcHover=%232b2b2b&borderColorHover=%23cccccc&bgColorHover=%23ededed&fcDefault=%23454545&borderColorDefault=%23c5c5c5&bgColorDefault=%23f6f6f6
|
||||
*/
|
||||
|
||||
|
||||
/* Component containers
|
||||
----------------------------------*/
|
||||
.ui-widget {
|
||||
font-family: Arial,Helvetica,sans-serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
.ui-widget .ui-widget {
|
||||
font-size: 1em;
|
||||
}
|
||||
.ui-widget input,
|
||||
.ui-widget select,
|
||||
.ui-widget textarea,
|
||||
.ui-widget button {
|
||||
font-family: Arial,Helvetica,sans-serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
.ui-widget.ui-widget-content {
|
||||
border: 1px solid #c5c5c5;
|
||||
}
|
||||
.ui-widget-content {
|
||||
border: 1px solid #dddddd;
|
||||
background: #ffffff;
|
||||
color: #333333;
|
||||
}
|
||||
.ui-widget-content a {
|
||||
color: #333333;
|
||||
}
|
||||
.ui-widget-header {
|
||||
border: 1px solid #dddddd;
|
||||
background: #e9e9e9;
|
||||
color: #333333;
|
||||
font-weight: bold;
|
||||
}
|
||||
.ui-widget-header a {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
/* Interaction states
|
||||
----------------------------------*/
|
||||
.ui-state-default,
|
||||
.ui-widget-content .ui-state-default,
|
||||
.ui-widget-header .ui-state-default,
|
||||
.ui-button,
|
||||
|
||||
/* We use html here because we need a greater specificity to make sure disabled
|
||||
works properly when clicked or hovered */
|
||||
html .ui-button.ui-state-disabled:hover,
|
||||
html .ui-button.ui-state-disabled:active {
|
||||
border: 1px solid #c5c5c5;
|
||||
background: #f6f6f6;
|
||||
font-weight: normal;
|
||||
color: #454545;
|
||||
}
|
||||
.ui-state-default a,
|
||||
.ui-state-default a:link,
|
||||
.ui-state-default a:visited,
|
||||
a.ui-button,
|
||||
a:link.ui-button,
|
||||
a:visited.ui-button,
|
||||
.ui-button {
|
||||
color: #454545;
|
||||
text-decoration: none;
|
||||
}
|
||||
.ui-state-hover,
|
||||
.ui-widget-content .ui-state-hover,
|
||||
.ui-widget-header .ui-state-hover,
|
||||
.ui-state-focus,
|
||||
.ui-widget-content .ui-state-focus,
|
||||
.ui-widget-header .ui-state-focus,
|
||||
.ui-button:hover,
|
||||
.ui-button:focus {
|
||||
border: 1px solid #cccccc;
|
||||
background: #ededed;
|
||||
font-weight: normal;
|
||||
color: #2b2b2b;
|
||||
}
|
||||
.ui-state-hover a,
|
||||
.ui-state-hover a:hover,
|
||||
.ui-state-hover a:link,
|
||||
.ui-state-hover a:visited,
|
||||
.ui-state-focus a,
|
||||
.ui-state-focus a:hover,
|
||||
.ui-state-focus a:link,
|
||||
.ui-state-focus a:visited,
|
||||
a.ui-button:hover,
|
||||
a.ui-button:focus {
|
||||
color: #2b2b2b;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.ui-visual-focus {
|
||||
box-shadow: 0 0 3px 1px rgb(94, 158, 214);
|
||||
}
|
||||
.ui-state-active,
|
||||
.ui-widget-content .ui-state-active,
|
||||
.ui-widget-header .ui-state-active,
|
||||
a.ui-button:active,
|
||||
.ui-button:active,
|
||||
.ui-button.ui-state-active:hover {
|
||||
border: 1px solid #003eff;
|
||||
background: #007fff;
|
||||
font-weight: normal;
|
||||
color: #ffffff;
|
||||
}
|
||||
.ui-icon-background,
|
||||
.ui-state-active .ui-icon-background {
|
||||
border: #003eff;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
.ui-state-active a,
|
||||
.ui-state-active a:link,
|
||||
.ui-state-active a:visited {
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Interaction Cues
|
||||
----------------------------------*/
|
||||
.ui-state-highlight,
|
||||
.ui-widget-content .ui-state-highlight,
|
||||
.ui-widget-header .ui-state-highlight {
|
||||
border: 1px solid #dad55e;
|
||||
background: #fffa90;
|
||||
color: #777620;
|
||||
}
|
||||
.ui-state-checked {
|
||||
border: 1px solid #dad55e;
|
||||
background: #fffa90;
|
||||
}
|
||||
.ui-state-highlight a,
|
||||
.ui-widget-content .ui-state-highlight a,
|
||||
.ui-widget-header .ui-state-highlight a {
|
||||
color: #777620;
|
||||
}
|
||||
.ui-state-error,
|
||||
.ui-widget-content .ui-state-error,
|
||||
.ui-widget-header .ui-state-error {
|
||||
border: 1px solid #f1a899;
|
||||
background: #fddfdf;
|
||||
color: #5f3f3f;
|
||||
}
|
||||
.ui-state-error a,
|
||||
.ui-widget-content .ui-state-error a,
|
||||
.ui-widget-header .ui-state-error a {
|
||||
color: #5f3f3f;
|
||||
}
|
||||
.ui-state-error-text,
|
||||
.ui-widget-content .ui-state-error-text,
|
||||
.ui-widget-header .ui-state-error-text {
|
||||
color: #5f3f3f;
|
||||
}
|
||||
.ui-priority-primary,
|
||||
.ui-widget-content .ui-priority-primary,
|
||||
.ui-widget-header .ui-priority-primary {
|
||||
font-weight: bold;
|
||||
}
|
||||
.ui-priority-secondary,
|
||||
.ui-widget-content .ui-priority-secondary,
|
||||
.ui-widget-header .ui-priority-secondary {
|
||||
opacity: .7;
|
||||
filter:Alpha(Opacity=70); /* support: IE8 */
|
||||
font-weight: normal;
|
||||
}
|
||||
.ui-state-disabled,
|
||||
.ui-widget-content .ui-state-disabled,
|
||||
.ui-widget-header .ui-state-disabled {
|
||||
opacity: .35;
|
||||
filter:Alpha(Opacity=35); /* support: IE8 */
|
||||
background-image: none;
|
||||
}
|
||||
.ui-state-disabled .ui-icon {
|
||||
filter:Alpha(Opacity=35); /* support: IE8 - See #6059 */
|
||||
}
|
||||
|
||||
/* Icons
|
||||
----------------------------------*/
|
||||
|
||||
/* states and images */
|
||||
.ui-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.ui-icon,
|
||||
.ui-widget-content .ui-icon {
|
||||
background-image: url("images/ui-icons_444444_256x240.png");
|
||||
}
|
||||
.ui-widget-header .ui-icon {
|
||||
background-image: url("images/ui-icons_444444_256x240.png");
|
||||
}
|
||||
.ui-state-hover .ui-icon,
|
||||
.ui-state-focus .ui-icon,
|
||||
.ui-button:hover .ui-icon,
|
||||
.ui-button:focus .ui-icon {
|
||||
background-image: url("images/ui-icons_555555_256x240.png");
|
||||
}
|
||||
.ui-state-active .ui-icon,
|
||||
.ui-button:active .ui-icon {
|
||||
background-image: url("images/ui-icons_ffffff_256x240.png");
|
||||
}
|
||||
.ui-state-highlight .ui-icon,
|
||||
.ui-button .ui-state-highlight.ui-icon {
|
||||
background-image: url("images/ui-icons_777620_256x240.png");
|
||||
}
|
||||
.ui-state-error .ui-icon,
|
||||
.ui-state-error-text .ui-icon {
|
||||
background-image: url("images/ui-icons_cc0000_256x240.png");
|
||||
}
|
||||
.ui-button .ui-icon {
|
||||
background-image: url("images/ui-icons_777777_256x240.png");
|
||||
}
|
||||
|
||||
/* positioning */
|
||||
.ui-icon-blank { background-position: 16px 16px; }
|
||||
.ui-icon-caret-1-n { background-position: 0 0; }
|
||||
.ui-icon-caret-1-ne { background-position: -16px 0; }
|
||||
.ui-icon-caret-1-e { background-position: -32px 0; }
|
||||
.ui-icon-caret-1-se { background-position: -48px 0; }
|
||||
.ui-icon-caret-1-s { background-position: -65px 0; }
|
||||
.ui-icon-caret-1-sw { background-position: -80px 0; }
|
||||
.ui-icon-caret-1-w { background-position: -96px 0; }
|
||||
.ui-icon-caret-1-nw { background-position: -112px 0; }
|
||||
.ui-icon-caret-2-n-s { background-position: -128px 0; }
|
||||
.ui-icon-caret-2-e-w { background-position: -144px 0; }
|
||||
.ui-icon-triangle-1-n { background-position: 0 -16px; }
|
||||
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
|
||||
.ui-icon-triangle-1-e { background-position: -32px -16px; }
|
||||
.ui-icon-triangle-1-se { background-position: -48px -16px; }
|
||||
.ui-icon-triangle-1-s { background-position: -65px -16px; }
|
||||
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
|
||||
.ui-icon-triangle-1-w { background-position: -96px -16px; }
|
||||
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
|
||||
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
|
||||
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
|
||||
.ui-icon-arrow-1-n { background-position: 0 -32px; }
|
||||
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
|
||||
.ui-icon-arrow-1-e { background-position: -32px -32px; }
|
||||
.ui-icon-arrow-1-se { background-position: -48px -32px; }
|
||||
.ui-icon-arrow-1-s { background-position: -65px -32px; }
|
||||
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
|
||||
.ui-icon-arrow-1-w { background-position: -96px -32px; }
|
||||
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
|
||||
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
|
||||
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
|
||||
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
|
||||
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
|
||||
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
|
||||
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
|
||||
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
|
||||
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
|
||||
.ui-icon-arrowthick-1-n { background-position: 1px -48px; }
|
||||
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
|
||||
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
|
||||
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
|
||||
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
|
||||
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
|
||||
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
|
||||
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
|
||||
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
|
||||
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
|
||||
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
|
||||
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
|
||||
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
|
||||
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
|
||||
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
|
||||
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
|
||||
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
|
||||
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
|
||||
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
|
||||
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
|
||||
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
|
||||
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
|
||||
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
|
||||
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
|
||||
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
|
||||
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
|
||||
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
|
||||
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
|
||||
.ui-icon-arrow-4 { background-position: 0 -80px; }
|
||||
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
|
||||
.ui-icon-extlink { background-position: -32px -80px; }
|
||||
.ui-icon-newwin { background-position: -48px -80px; }
|
||||
.ui-icon-refresh { background-position: -64px -80px; }
|
||||
.ui-icon-shuffle { background-position: -80px -80px; }
|
||||
.ui-icon-transfer-e-w { background-position: -96px -80px; }
|
||||
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
|
||||
.ui-icon-folder-collapsed { background-position: 0 -96px; }
|
||||
.ui-icon-folder-open { background-position: -16px -96px; }
|
||||
.ui-icon-document { background-position: -32px -96px; }
|
||||
.ui-icon-document-b { background-position: -48px -96px; }
|
||||
.ui-icon-note { background-position: -64px -96px; }
|
||||
.ui-icon-mail-closed { background-position: -80px -96px; }
|
||||
.ui-icon-mail-open { background-position: -96px -96px; }
|
||||
.ui-icon-suitcase { background-position: -112px -96px; }
|
||||
.ui-icon-comment { background-position: -128px -96px; }
|
||||
.ui-icon-person { background-position: -144px -96px; }
|
||||
.ui-icon-print { background-position: -160px -96px; }
|
||||
.ui-icon-trash { background-position: -176px -96px; }
|
||||
.ui-icon-locked { background-position: -192px -96px; }
|
||||
.ui-icon-unlocked { background-position: -208px -96px; }
|
||||
.ui-icon-bookmark { background-position: -224px -96px; }
|
||||
.ui-icon-tag { background-position: -240px -96px; }
|
||||
.ui-icon-home { background-position: 0 -112px; }
|
||||
.ui-icon-flag { background-position: -16px -112px; }
|
||||
.ui-icon-calendar { background-position: -32px -112px; }
|
||||
.ui-icon-cart { background-position: -48px -112px; }
|
||||
.ui-icon-pencil { background-position: -64px -112px; }
|
||||
.ui-icon-clock { background-position: -80px -112px; }
|
||||
.ui-icon-disk { background-position: -96px -112px; }
|
||||
.ui-icon-calculator { background-position: -112px -112px; }
|
||||
.ui-icon-zoomin { background-position: -128px -112px; }
|
||||
.ui-icon-zoomout { background-position: -144px -112px; }
|
||||
.ui-icon-search { background-position: -160px -112px; }
|
||||
.ui-icon-wrench { background-position: -176px -112px; }
|
||||
.ui-icon-gear { background-position: -192px -112px; }
|
||||
.ui-icon-heart { background-position: -208px -112px; }
|
||||
.ui-icon-star { background-position: -224px -112px; }
|
||||
.ui-icon-link { background-position: -240px -112px; }
|
||||
.ui-icon-cancel { background-position: 0 -128px; }
|
||||
.ui-icon-plus { background-position: -16px -128px; }
|
||||
.ui-icon-plusthick { background-position: -32px -128px; }
|
||||
.ui-icon-minus { background-position: -48px -128px; }
|
||||
.ui-icon-minusthick { background-position: -64px -128px; }
|
||||
.ui-icon-close { background-position: -80px -128px; }
|
||||
.ui-icon-closethick { background-position: -96px -128px; }
|
||||
.ui-icon-key { background-position: -112px -128px; }
|
||||
.ui-icon-lightbulb { background-position: -128px -128px; }
|
||||
.ui-icon-scissors { background-position: -144px -128px; }
|
||||
.ui-icon-clipboard { background-position: -160px -128px; }
|
||||
.ui-icon-copy { background-position: -176px -128px; }
|
||||
.ui-icon-contact { background-position: -192px -128px; }
|
||||
.ui-icon-image { background-position: -208px -128px; }
|
||||
.ui-icon-video { background-position: -224px -128px; }
|
||||
.ui-icon-script { background-position: -240px -128px; }
|
||||
.ui-icon-alert { background-position: 0 -144px; }
|
||||
.ui-icon-info { background-position: -16px -144px; }
|
||||
.ui-icon-notice { background-position: -32px -144px; }
|
||||
.ui-icon-help { background-position: -48px -144px; }
|
||||
.ui-icon-check { background-position: -64px -144px; }
|
||||
.ui-icon-bullet { background-position: -80px -144px; }
|
||||
.ui-icon-radio-on { background-position: -96px -144px; }
|
||||
.ui-icon-radio-off { background-position: -112px -144px; }
|
||||
.ui-icon-pin-w { background-position: -128px -144px; }
|
||||
.ui-icon-pin-s { background-position: -144px -144px; }
|
||||
.ui-icon-play { background-position: 0 -160px; }
|
||||
.ui-icon-pause { background-position: -16px -160px; }
|
||||
.ui-icon-seek-next { background-position: -32px -160px; }
|
||||
.ui-icon-seek-prev { background-position: -48px -160px; }
|
||||
.ui-icon-seek-end { background-position: -64px -160px; }
|
||||
.ui-icon-seek-start { background-position: -80px -160px; }
|
||||
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
|
||||
.ui-icon-seek-first { background-position: -80px -160px; }
|
||||
.ui-icon-stop { background-position: -96px -160px; }
|
||||
.ui-icon-eject { background-position: -112px -160px; }
|
||||
.ui-icon-volume-off { background-position: -128px -160px; }
|
||||
.ui-icon-volume-on { background-position: -144px -160px; }
|
||||
.ui-icon-power { background-position: 0 -176px; }
|
||||
.ui-icon-signal-diag { background-position: -16px -176px; }
|
||||
.ui-icon-signal { background-position: -32px -176px; }
|
||||
.ui-icon-battery-0 { background-position: -48px -176px; }
|
||||
.ui-icon-battery-1 { background-position: -64px -176px; }
|
||||
.ui-icon-battery-2 { background-position: -80px -176px; }
|
||||
.ui-icon-battery-3 { background-position: -96px -176px; }
|
||||
.ui-icon-circle-plus { background-position: 0 -192px; }
|
||||
.ui-icon-circle-minus { background-position: -16px -192px; }
|
||||
.ui-icon-circle-close { background-position: -32px -192px; }
|
||||
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
|
||||
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
|
||||
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
|
||||
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
|
||||
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
|
||||
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
|
||||
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
|
||||
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
|
||||
.ui-icon-circle-zoomin { background-position: -176px -192px; }
|
||||
.ui-icon-circle-zoomout { background-position: -192px -192px; }
|
||||
.ui-icon-circle-check { background-position: -208px -192px; }
|
||||
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
|
||||
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
|
||||
.ui-icon-circlesmall-close { background-position: -32px -208px; }
|
||||
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
|
||||
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
|
||||
.ui-icon-squaresmall-close { background-position: -80px -208px; }
|
||||
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
|
||||
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
|
||||
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
|
||||
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
|
||||
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
|
||||
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
|
||||
|
||||
|
||||
/* Misc visuals
|
||||
----------------------------------*/
|
||||
|
||||
/* Corner radius */
|
||||
.ui-corner-all,
|
||||
.ui-corner-top,
|
||||
.ui-corner-left,
|
||||
.ui-corner-tl {
|
||||
border-top-left-radius: 3px;
|
||||
}
|
||||
.ui-corner-all,
|
||||
.ui-corner-top,
|
||||
.ui-corner-right,
|
||||
.ui-corner-tr {
|
||||
border-top-right-radius: 3px;
|
||||
}
|
||||
.ui-corner-all,
|
||||
.ui-corner-bottom,
|
||||
.ui-corner-left,
|
||||
.ui-corner-bl {
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
.ui-corner-all,
|
||||
.ui-corner-bottom,
|
||||
.ui-corner-right,
|
||||
.ui-corner-br {
|
||||
border-bottom-right-radius: 3px;
|
||||
}
|
||||
|
||||
/* Overlays */
|
||||
.ui-widget-overlay {
|
||||
background: #aaaaaa;
|
||||
opacity: .003;
|
||||
filter: Alpha(Opacity=.3); /* support: IE8 */
|
||||
}
|
||||
.ui-widget-shadow {
|
||||
-webkit-box-shadow: 0px 0px 5px #666666;
|
||||
box-shadow: 0px 0px 5px #666666;
|
||||
}
|
5
rootfs/free/var/www/mynode/static/jquery_ui/jquery-ui.theme.min.css
vendored
Normal file
74
rootfs/free/var/www/mynode/static/jquery_ui/package.json
Normal file
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
"name": "jquery-ui",
|
||||
"title": "jQuery UI",
|
||||
"description": "A curated set of user interface interactions, effects, widgets, and themes built on top of the jQuery JavaScript Library.",
|
||||
"version": "1.12.1",
|
||||
"homepage": "http://jqueryui.com",
|
||||
"author": {
|
||||
"name": "jQuery Foundation and other contributors",
|
||||
"url": "https://github.com/jquery/jquery-ui/blob/1.12.1/AUTHORS.txt"
|
||||
},
|
||||
"main": "ui/widget.js",
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "Scott González",
|
||||
"email": "scott.gonzalez@gmail.com",
|
||||
"url": "http://scottgonzalez.com"
|
||||
},
|
||||
{
|
||||
"name": "Jörn Zaefferer",
|
||||
"email": "joern.zaefferer@gmail.com",
|
||||
"url": "http://bassistance.de"
|
||||
},
|
||||
{
|
||||
"name": "Mike Sherov",
|
||||
"email": "mike.sherov@gmail.com",
|
||||
"url": "http://mike.sherov.com"
|
||||
},
|
||||
{
|
||||
"name": "TJ VanToll",
|
||||
"email": "tj.vantoll@gmail.com",
|
||||
"url": "http://tjvantoll.com"
|
||||
},
|
||||
{
|
||||
"name": "Felix Nagel",
|
||||
"email": "info@felixnagel.com",
|
||||
"url": "http://www.felixnagel.com"
|
||||
},
|
||||
{
|
||||
"name": "Alex Schmitz",
|
||||
"email": "arschmitz@gmail.com",
|
||||
"url": "https://github.com/arschmitz"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/jquery/jquery-ui.git"
|
||||
},
|
||||
"bugs": "https://bugs.jqueryui.com/",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"test": "grunt"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"commitplease": "2.3.0",
|
||||
"grunt": "0.4.5",
|
||||
"grunt-bowercopy": "1.2.4",
|
||||
"grunt-cli": "0.1.13",
|
||||
"grunt-compare-size": "0.4.0",
|
||||
"grunt-contrib-concat": "0.5.1",
|
||||
"grunt-contrib-csslint": "0.5.0",
|
||||
"grunt-contrib-jshint": "0.12.0",
|
||||
"grunt-contrib-qunit": "1.0.1",
|
||||
"grunt-contrib-requirejs": "0.4.4",
|
||||
"grunt-contrib-uglify": "0.11.1",
|
||||
"grunt-git-authors": "3.1.0",
|
||||
"grunt-html": "6.0.0",
|
||||
"grunt-jscs": "2.1.0",
|
||||
"load-grunt-tasks": "3.4.0",
|
||||
"rimraf": "2.5.1",
|
||||
"testswarm": "1.1.0"
|
||||
},
|
||||
"keywords": []
|
||||
}
|
2
rootfs/free/var/www/mynode/static/js/jquery-3.3.1.min.js
vendored
Normal file
45
rootfs/free/var/www/mynode/static/js/mynode.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
// Refresh page after N seconds
|
||||
function refreshIn(seconds) {
|
||||
setTimeout(function() {
|
||||
//window.location.reload();
|
||||
alert("reload")
|
||||
}, seconds*1000);
|
||||
}
|
||||
|
||||
// Open info dialog
|
||||
function openInfoDialog(divid, title, message) {
|
||||
$("#"+divid).html("<p>"+message+"</p>")
|
||||
info_dialog = $("#"+divid).dialog({
|
||||
title: title,
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: 600,
|
||||
modal: true,
|
||||
position: { my: "center top", at: "center top", of: window, collision: "none" },
|
||||
buttons: {
|
||||
"OK": function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
});
|
||||
info_dialog.dialog("open");
|
||||
}
|
||||
|
||||
// Open confirm dialog
|
||||
function openConfirmDialog(divid, title, message, okFunction) {
|
||||
$("#"+divid).html("<p>"+message+"</p>")
|
||||
confirm_dialog = $( "#"+divid ).dialog({
|
||||
title: title,
|
||||
resizable: false,
|
||||
height: "auto",
|
||||
width: 600,
|
||||
modal: true,
|
||||
position: { my: "center top", at: "center top", of: window, collision: "none" },
|
||||
buttons: {
|
||||
"OK": okFunction,
|
||||
Cancel: function() {
|
||||
$( this ).dialog( "close" );
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
43
rootfs/free/var/www/mynode/templates/about.html
Normal file
|
@ -0,0 +1,43 @@
|
|||
<!DOCTYPE html lang="en">
|
||||
<head>
|
||||
<title>myNode About</title>
|
||||
<link rel="shortcut icon" href="{{ url_for('static', filename='images/favicon.ico') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename="css/mynode.css")}}">
|
||||
<link href="{{ url_for('static', filename="jquery_ui/jquery-ui.css")}}" rel="stylesheet">
|
||||
<meta http-equiv="Content-Language" content="en">
|
||||
<meta name="google" content="notranslate">
|
||||
<script src="{{ url_for('static', filename="js/jquery-3.3.1.min.js")}}"></script>
|
||||
<script src="{{ url_for('static', filename="jquery_ui/jquery-ui.js")}}"></script>
|
||||
<script src="{{ url_for('static', filename="js/mynode.js")}}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="logo_header"><a href="/"><img class="logo_image" src="{{ url_for('static', filename="images/logo.png")}}"/></a></div>
|
||||
<div class="mynode_back_div">
|
||||
<a class="ui-button ui-widget ui-corner-all mynode_back" href="/"><span class="ui-icon ui-icon-home"></span>home </a>
|
||||
</div>
|
||||
|
||||
<div class="main_header">About</div>
|
||||
|
||||
<br/>
|
||||
<div class="settings_block">
|
||||
<div class="settings_block_header">Contacts</div>
|
||||
<p>
|
||||
If you have any questions or comments, please contact myNode via email at the following address:
|
||||
<br/></br>
|
||||
<a href="mailto:mynode@mynodebtc.com">mynode@mynodebtc.com</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="settings_block">
|
||||
<div class="settings_block_header">Open Source</div>
|
||||
<p>Thanks to all the open source projects that make this possible!</p>
|
||||
<p>If it wasn't for these projects and people like you, Bitcoin, the Lightning Network, and all these related projects would not be possible.</p>
|
||||
|
||||
<p><b>Bitcoin</b><br/><a href="https://github.com/bitcoin/bitcoin">https://github.com/bitcoin/bitcoin</a></p>
|
||||
<p><b>LND</b><br/> <a href="https://github.com/lightningnetwork/lnd">https://github.com/lightningnetwork/lnd</a></p>
|
||||
</div>
|
||||
|
||||
{% include 'includes/footer.html' %}
|
||||
</body>
|
||||
</html>
|
106
rootfs/free/var/www/mynode/templates/bitcoind_status.html
Normal file
|
@ -0,0 +1,106 @@
|
|||
<!DOCTYPE html lang="en">
|
||||
<head>
|
||||
<title>{{ title }}</title>
|
||||
<link rel="shortcut icon" href="{{ url_for('static', filename='images/favicon.ico') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename="css/mynode.css")}}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename="css/mynode_bitcoind.css")}}">
|
||||
<link href="{{ url_for('static', filename="jquery_ui/jquery-ui.css")}}" rel="stylesheet">
|
||||
<meta http-equiv="Content-Language" content="en">
|
||||
<meta name="google" content="notranslate">
|
||||
<script src="{{ url_for('static', filename="js/jquery-3.3.1.min.js")}}"></script>
|
||||
<script src="{{ url_for('static', filename="jquery_ui/jquery-ui.js")}}"></script>
|
||||
<script src="{{ url_for('static', filename="js/mynode.js")}}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="logo_header"><a href="/"><img class="logo_image" src="{{ url_for('static', filename="images/logo.png")}}"/></a></div>
|
||||
<div class="mynode_back_div">
|
||||
<a class="ui-button ui-widget ui-corner-all mynode_back" href="/"><span class="ui-icon ui-icon-home"></span>home </a>
|
||||
</div>
|
||||
|
||||
<div class="main_header">Bitcoin Status</div>
|
||||
|
||||
<br/>
|
||||
<div class="app_tile_row">
|
||||
<div class="info_tile">
|
||||
<div class="info_tile_header">Blocks</div>
|
||||
<div class="info_tile_contents">{{block_num}}</div>
|
||||
</div>
|
||||
<div class="info_tile">
|
||||
<div class="info_tile_header">Headers</div>
|
||||
<div class="info_tile_contents">{{header_num}}</div>
|
||||
</div>
|
||||
<div class="info_tile">
|
||||
<div class="info_tile_header">Difficulty</div>
|
||||
<div class="info_tile_contents">{{difficulty}}</div>
|
||||
</div>
|
||||
<div class="info_tile">
|
||||
<div class="info_tile_header">Disk Usage</div>
|
||||
<div class="info_tile_contents">{{disk_size}} GB</div>
|
||||
</div>
|
||||
<div class="info_tile">
|
||||
<div class="info_tile_header">Version</div>
|
||||
<div class="info_tile_contents">{{version}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="app_tile_row">
|
||||
<div class="info_tile">
|
||||
<div class="info_tile_header">Mempool TX</div>
|
||||
<div class="info_tile_contents">{{mempool_tx}}</div>
|
||||
</div>
|
||||
<div class="info_tile">
|
||||
<div class="info_tile_header">Mempool Size</div>
|
||||
<div class="info_tile_contents">{{mempool_size}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<div class="main_header">Recent Blocks</div>
|
||||
<table class="bitcoind_table">
|
||||
<thead class="bitcoind_table_header">
|
||||
<td>Height</td>
|
||||
<td>Age</td>
|
||||
<td>Transactions</td>
|
||||
<td>Size (kB)</td>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for block in blocks %}
|
||||
<tr>
|
||||
<td>{{ block.height }}</td>
|
||||
<td>{{ block.age }}</td>
|
||||
<td>{{ block.nTx }}</td>
|
||||
<td>{{ block.size }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
<div class="main_header">Peers</div>
|
||||
<table class="bitcoind_table">
|
||||
<thead class="bitcoind_table_header">
|
||||
<td>ID</td>
|
||||
<td>IP</td>
|
||||
<td>Version</td>
|
||||
<td>TX (MB)</td>
|
||||
<td>RX (MB)</td>
|
||||
<td>Ping (ms)</td>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for peer in peers %}
|
||||
<tr>
|
||||
<td>{{ peer.id }}</td>
|
||||
<td>{{ peer.addr }}</td>
|
||||
<td>{{ peer.subver }}</td>
|
||||
<td>{{ peer.tx }}</td>
|
||||
<td>{{ peer.rx }}</td>
|
||||
<td>{{ peer.pingtime }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% include 'includes/footer.html' %}
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html lang="en">
|
||||
<head>
|
||||
<title>{{ title }}</title>
|
||||
<link rel="shortcut icon" href="{{ url_for('static', filename='images/favicon.ico') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename="css/mynode.css")}}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename="css/mynode_bitcoind.css")}}">
|
||||
<link href="{{ url_for('static', filename="jquery_ui/jquery-ui.css")}}" rel="stylesheet">
|
||||
<meta http-equiv="Content-Language" content="en">
|
||||
<meta name="google" content="notranslate">
|
||||
<script src="{{ url_for('static', filename="js/jquery-3.3.1.min.js")}}"></script>
|
||||
<script src="{{ url_for('static', filename="jquery_ui/jquery-ui.js")}}"></script>
|
||||
<script src="{{ url_for('static', filename="js/mynode.js")}}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="logo_header"><a href="/"><img class="logo_image" src="{{ url_for('static', filename="images/logo.png")}}"/></a></div>
|
||||
<div class="mynode_back_div">
|
||||
<a class="ui-button ui-widget ui-corner-all mynode_back" href="/"><span class="ui-icon ui-icon-home"></span>home </a>
|
||||
<a class="ui-button ui-widget ui-corner-all mynode_back" href="/bitcoind"><span class="ui-icon ui-icon-info"></span>bitcoin </a>
|
||||
</div>
|
||||
|
||||
<div class="main_header">Bitcoin Status</div>
|
||||
|
||||
<div class="bitcoind_error_message">{{message}}</div>
|
||||
|
||||
{% include 'includes/footer.html' %}
|
||||
</body>
|
||||
</html>
|
27
rootfs/free/var/www/mynode/templates/error.html
Normal file
|
@ -0,0 +1,27 @@
|
|||
<!DOCTYPE html lang="en">
|
||||
<head>
|
||||
<title>{{ title }}</title>
|
||||
<link rel="shortcut icon" href="{{ url_for('static', filename='images/favicon.ico') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename="css/mynode.css")}}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename="css/mynode_bitcoind.css")}}">
|
||||
<link href="{{ url_for('static', filename="jquery_ui/jquery-ui.css")}}" rel="stylesheet">
|
||||
<meta http-equiv="Content-Language" content="en">
|
||||
<meta name="google" content="notranslate">
|
||||
<script src="{{ url_for('static', filename="js/jquery-3.3.1.min.js")}}"></script>
|
||||
<script src="{{ url_for('static', filename="jquery_ui/jquery-ui.js")}}"></script>
|
||||
<script src="{{ url_for('static', filename="js/mynode.js")}}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="logo_header"><a href="/"><img class="logo_image" src="{{ url_for('static', filename="images/logo.png")}}"/></a></div>
|
||||
<div class="mynode_back_div">
|
||||
<a class="ui-button ui-widget ui-corner-all mynode_back" href="/"><span class="ui-icon ui-icon-home"></span>home </a>
|
||||
</div>
|
||||
|
||||
<div class="main_header">myNode Error</div>
|
||||
|
||||
<div class="bitcoind_error_message">{{message}}</div>
|
||||
|
||||
{% include 'includes/footer.html' %}
|
||||
</body>
|
||||
</html>
|