Initial copy to open source repo

This commit is contained in:
Taylor Helsper 2019-06-15 18:02:44 -05:00
parent 50174dd0ca
commit 283b190702
285 changed files with 58092 additions and 0 deletions

29
.gitignore vendored Normal file
View 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
View 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
View File

@ -0,0 +1,4 @@
#!/bin/bash
fswatch $(dirname $0)/rootfs | (while read; do $(dirname $0)/make_rootfs.sh; echo "Update rootfs!"; done)

View 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

View 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

View 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

View 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

View 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
View File

View 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

View 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

View 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

View File

@ -0,0 +1,2 @@
if $programname == 'bitcoind' then /var/log/bitcoind.log
& stop

View File

@ -0,0 +1,2 @@
if $programname == 'lnd' then /var/log/lnd.log
& stop

View File

@ -0,0 +1,2 @@
if $programname == 'lndbackup' then /var/log/lnd_backup.log
& stop

View File

@ -0,0 +1,2 @@
if $programname == 'mynode' then /var/log/mynode.log
& stop

View 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

View File

@ -0,0 +1,2 @@
if $programname == 'www' then /var/log/www.log
& stop

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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'

View 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 ""

View 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

View 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

View 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
View 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)

View 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

View 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

View 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

View File

@ -0,0 +1,7 @@
#!/bin/bash
PASSWORD=$1
# Change Linux Password
echo "admin:$PASSWORD" | chpasswd

View 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

View 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

View 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

View 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

View 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

View 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

View 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
View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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"

View File

@ -0,0 +1 @@
0.1.11

View 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
}

View 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)

View 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)

View 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)

View 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/"

View 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

View 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

View 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"))

View 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

View 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...")

View 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"

View 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;
}

View 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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View 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;
}

File diff suppressed because one or more lines are too long

View 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;
}

File diff suppressed because one or more lines are too long

View 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": []
}

File diff suppressed because one or more lines are too long

View 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" );
}
}
});
}

View 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&nbsp;</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>

View 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&nbsp;</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>

View File

@ -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&nbsp;</a>
<a class="ui-button ui-widget ui-corner-all mynode_back" href="/bitcoind"><span class="ui-icon ui-icon-info"></span>bitcoin&nbsp;</a>
</div>
<div class="main_header">Bitcoin Status</div>
<div class="bitcoind_error_message">{{message}}</div>
{% include 'includes/footer.html' %}
</body>
</html>

View 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&nbsp;</a>
</div>
<div class="main_header">myNode Error</div>
<div class="bitcoind_error_message">{{message}}</div>
{% include 'includes/footer.html' %}
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More