page rename, successful MySQL test

This commit is contained in:
KF7EEL 2021-06-19 08:58:15 -07:00
parent c761e740bc
commit 3c461363a4
4 changed files with 212 additions and 149 deletions

View File

@ -1,8 +1,8 @@
![ ](https://raw.githubusercontent.com/kf7eel/hblink3/hbnet/HBNet.png "Logo") ![ ](https://raw.githubusercontent.com/kf7eel/hblink3/hbnet/HBNet.png "Logo")
HBNet is a fork of HBLink3 the extends the functionality of HBLink through several optional features, making it more of a usable application and less of a framework. HBNet aims to be complete and easy to use application that can be used to build, administrate, and run a DMR network. HBNet is a fork of [HBlink3](https://github.com/HBLink-org/hblink3) the extends the functionality of HBLink through several optional features, making it more of a usable application and less of a framework. HBNet aims to be complete and easy to use application that can be used to build, administrate, and run a DMR network.
HBNet consists of 2 parts, web control panel, and the actual DMR server, based on HBLink. HBNet consists of 2 parts, HBNet Web Server and the actual DMR server, based on HBLink.
### User end features: ### User end features:
@ -11,16 +11,29 @@ HBNet consists of 2 parts, web control panel, and the actual DMR server, based o
* Individual passphrases for each user * Individual passphrases for each user
* Automatic retrieval of DMR IDs on registration
* Monitor and change active talkgroups (WORK IN PROGRESS)
### Administrative features: ### Administrative features:
* Administrate multiple DMR servers through the web panel * Administrate multiple DMR servers through the web panel
* Optional manual approval of new users
* Multiple Admin user logins * Multiple Admin user logins
* Entirely configure HBLink in web panel * Entirely configure DMR server (HBlink) in web server
* Log all peer authentication
### Other features
* SQLite or MySQL backend
* APRS and SMS features (WORK IN PROGRESS)
--- ---
### FOR SUPPORT, DISCUSSION, GETTING INVOLVED ### ### FOR SUPPORT, DISCUSSION, GETTING INVOLVED ###

View File

@ -1,4 +1,25 @@
# HBLink User Managment Server # HBNet Web Server
###############################################################################
# HBNet Web Server - Copyright (C) 2020 Eric Craw, KF7EEL <kf7eel@qsl.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
###############################################################################
'''
Flask based application that is the web server for HBNet. Controls user authentication, DMR server config, etc.
'''
from flask import Flask, render_template_string, request, make_response, jsonify, render_template, Markup, flash, redirect, url_for, current_app from flask import Flask, render_template_string, request, make_response, jsonify, render_template, Markup, flash, redirect, url_for, current_app
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
@ -124,17 +145,17 @@ def create_app():
# User authentication information. The collation='NOCASE' is required # User authentication information. The collation='NOCASE' is required
# to search case insensitively when USER_IFIND_MODE is 'nocase_collation'. # to search case insensitively when USER_IFIND_MODE is 'nocase_collation'.
username = db.Column(db.String(100, collation='NOCASE'), nullable=False, unique=True) username = db.Column(db.String(100,), nullable=False, unique=True)
password = db.Column(db.String(255), nullable=False, server_default='') password = db.Column(db.String(255), nullable=False, server_default='')
email_confirmed_at = db.Column(db.DateTime()) email_confirmed_at = db.Column(db.DateTime())
email = db.Column(db.String(255, collation='NOCASE'), nullable=False, unique=True) email = db.Column(db.String(255), nullable=False, unique=True)
# User information # User information
first_name = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') first_name = db.Column(db.String(100), nullable=False, server_default='')
last_name = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') last_name = db.Column(db.String(100), nullable=False, server_default='')
dmr_ids = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') dmr_ids = db.Column(db.String(100), nullable=False, server_default='')
city = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') city = db.Column(db.String(100), nullable=False, server_default='')
notes = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') notes = db.Column(db.String(100), nullable=False, server_default='')
#Used for initial approval #Used for initial approval
initial_admin_approved = db.Column('initial_admin_approved', db.Boolean(), nullable=False, server_default='1') initial_admin_approved = db.Column('initial_admin_approved', db.Boolean(), nullable=False, server_default='1')
# Define the relationship to Role via UserRoles # Define the relationship to Role via UserRoles
@ -154,212 +175,214 @@ def create_app():
role_id = db.Column(db.Integer(), db.ForeignKey('roles.id', ondelete='CASCADE')) role_id = db.Column(db.Integer(), db.ForeignKey('roles.id', ondelete='CASCADE'))
class BurnList(db.Model): class BurnList(db.Model):
__tablename__ = 'burn_list' __tablename__ = 'burn_list'
## id = db.Column(db.Integer(), primary_key=True)
dmr_id = db.Column(db.Integer(), unique=True, primary_key=True) dmr_id = db.Column(db.Integer(), unique=True, primary_key=True)
version = db.Column(db.Integer(), primary_key=True) version = db.Column(db.Integer(), primary_key=True)
class AuthLog(db.Model): class AuthLog(db.Model):
__tablename__ = 'auth_log' __tablename__ = 'auth_log'
login_dmr_id = db.Column(db.Integer(), primary_key=True) id = db.Column(db.Integer(), primary_key=True)
login_time = db.Column(db.DateTime(), primary_key=True) login_dmr_id = db.Column(db.Integer())
peer_ip = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') login_time = db.Column(db.DateTime())
server_name = db.Column(db.Integer(), primary_key=True) peer_ip = db.Column(db.String(100), nullable=False, server_default='')
login_auth_method = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') server_name = db.Column(db.String(100))
portal_username = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') login_auth_method = db.Column(db.String(100), nullable=False, server_default='')
login_type = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') portal_username = db.Column(db.String(100), nullable=False, server_default='')
login_type = db.Column(db.String(100), nullable=False, server_default='')
class mmdvmPeer(db.Model): class mmdvmPeer(db.Model):
__tablename__ = 'MMDVM_peers' __tablename__ = 'MMDVM_peers'
id = db.Column(db.Integer(), primary_key=True) id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') name = db.Column(db.String(100), nullable=False, server_default='')
enabled = db.Column(db.Boolean(), nullable=False, server_default='1') enabled = db.Column(db.Boolean(), nullable=False, server_default='1')
loose = db.Column(db.Boolean(), nullable=False, server_default='1') loose = db.Column(db.Boolean(), nullable=False, server_default='1')
ip = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='127.0.0.1') ip = db.Column(db.String(100), nullable=False, server_default='127.0.0.1')
port = db.Column(db.Integer(), primary_key=False) port = db.Column(db.Integer(), primary_key=False)
master_ip = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') master_ip = db.Column(db.String(100), nullable=False, server_default='')
master_port = db.Column(db.Integer(), primary_key=False) master_port = db.Column(db.Integer(), primary_key=False)
passphrase = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') passphrase = db.Column(db.String(100), nullable=False, server_default='')
callsign = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') callsign = db.Column(db.String(100), nullable=False, server_default='')
radio_id = db.Column(db.Integer(), primary_key=False) radio_id = db.Column(db.Integer(), primary_key=False)
rx_freq = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') rx_freq = db.Column(db.String(100), nullable=False, server_default='')
tx_freq = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') tx_freq = db.Column(db.String(100), nullable=False, server_default='')
tx_power = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') tx_power = db.Column(db.String(100), nullable=False, server_default='')
color_code = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') color_code = db.Column(db.String(100), nullable=False, server_default='')
latitude = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') latitude = db.Column(db.String(100), nullable=False, server_default='')
longitude = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') longitude = db.Column(db.String(100), nullable=False, server_default='')
height = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') height = db.Column(db.String(100), nullable=False, server_default='')
location = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') location = db.Column(db.String(100), nullable=False, server_default='')
description = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') description = db.Column(db.String(100), nullable=False, server_default='')
slots = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') slots = db.Column(db.String(100), nullable=False, server_default='')
url = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') url = db.Column(db.String(100), nullable=False, server_default='')
group_hangtime = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') group_hangtime = db.Column(db.String(100), nullable=False, server_default='')
enable_unit = db.Column(db.Boolean(), nullable=False, server_default='1') enable_unit = db.Column(db.Boolean(), nullable=False, server_default='1')
options = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') options = db.Column(db.String(100), nullable=False, server_default='')
use_acl = db.Column(db.Boolean(), nullable=False, server_default='0') use_acl = db.Column(db.Boolean(), nullable=False, server_default='0')
sub_acl = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') sub_acl = db.Column(db.String(100), nullable=False, server_default='')
tg1_acl = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') tg1_acl = db.Column(db.String(100), nullable=False, server_default='')
tg2_acl = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') tg2_acl = db.Column(db.String(100), nullable=False, server_default='')
server = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') server = db.Column(db.String(100), nullable=False, server_default='')
notes = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') notes = db.Column(db.String(100), nullable=False, server_default='')
class xlxPeer(db.Model): class xlxPeer(db.Model):
__tablename__ = 'XLX_peers' __tablename__ = 'XLX_peers'
id = db.Column(db.Integer(), primary_key=True) id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') name = db.Column(db.String(100), nullable=False, server_default='')
enabled = db.Column(db.Boolean(), nullable=False, server_default='1') enabled = db.Column(db.Boolean(), nullable=False, server_default='1')
loose = db.Column(db.Boolean(), nullable=False, server_default='1') loose = db.Column(db.Boolean(), nullable=False, server_default='1')
ip = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='127.0.0.1') ip = db.Column(db.String(100), nullable=False, server_default='127.0.0.1')
port = db.Column(db.Integer(), primary_key=False) port = db.Column(db.Integer(), primary_key=False)
master_ip = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') master_ip = db.Column(db.String(100), nullable=False, server_default='')
master_port = db.Column(db.Integer(), primary_key=False) master_port = db.Column(db.Integer(), primary_key=False)
passphrase = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') passphrase = db.Column(db.String(100), nullable=False, server_default='')
callsign = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') callsign = db.Column(db.String(100), nullable=False, server_default='')
radio_id = db.Column(db.Integer(), primary_key=False) radio_id = db.Column(db.Integer(), primary_key=False)
rx_freq = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') rx_freq = db.Column(db.String(100), nullable=False, server_default='')
tx_freq = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') tx_freq = db.Column(db.String(100), nullable=False, server_default='')
tx_power = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') tx_power = db.Column(db.String(100), nullable=False, server_default='')
color_code = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') color_code = db.Column(db.String(100), nullable=False, server_default='')
latitude = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') latitude = db.Column(db.String(100), nullable=False, server_default='')
longitude = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') longitude = db.Column(db.String(100), nullable=False, server_default='')
height = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') height = db.Column(db.String(100), nullable=False, server_default='')
location = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') location = db.Column(db.String(100), nullable=False, server_default='')
description = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') description = db.Column(db.String(100), nullable=False, server_default='')
slots = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') slots = db.Column(db.String(100), nullable=False, server_default='')
url = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') url = db.Column(db.String(100), nullable=False, server_default='')
group_hangtime = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') group_hangtime = db.Column(db.String(100), nullable=False, server_default='')
xlxmodule = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') xlxmodule = db.Column(db.String(100), nullable=False, server_default='')
options = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') options = db.Column(db.String(100), nullable=False, server_default='')
enable_unit = db.Column(db.Boolean(), nullable=False, server_default='1') enable_unit = db.Column(db.Boolean(), nullable=False, server_default='1')
use_acl = db.Column(db.Boolean(), nullable=False, server_default='0') use_acl = db.Column(db.Boolean(), nullable=False, server_default='0')
sub_acl = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') sub_acl = db.Column(db.String(100), nullable=False, server_default='')
tg1_acl = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') tg1_acl = db.Column(db.String(100), nullable=False, server_default='')
tg2_acl = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') tg2_acl = db.Column(db.String(100), nullable=False, server_default='')
server = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') server = db.Column(db.String(100), nullable=False, server_default='')
notes = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') notes = db.Column(db.String(100), nullable=False, server_default='')
class ServerList(db.Model): class ServerList(db.Model):
__tablename__ = 'server_list' __tablename__ = 'server_list'
name = db.Column(db.String(100, collation='NOCASE'), unique=True, primary_key=True) name = db.Column(db.String(100), unique=True, primary_key=True)
secret = db.Column(db.String(255), nullable=False, server_default='') secret = db.Column(db.String(255), nullable=False, server_default='')
## public_list = db.Column(db.Boolean(), nullable=False, server_default='1') ## public_list = db.Column(db.Boolean(), nullable=False, server_default='1')
id = db.Column(db.Integer(), primary_key=False) id = db.Column(db.Integer(), primary_key=False)
ip = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') ip = db.Column(db.String(100), nullable=False, server_default='')
port = db.Column(db.Integer(), primary_key=False) port = db.Column(db.Integer(), primary_key=False)
global_path = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='./') global_path = db.Column(db.String(100), nullable=False, server_default='./')
global_ping_time = db.Column(db.Integer(), primary_key=False) global_ping_time = db.Column(db.Integer(), primary_key=False)
global_max_missed = db.Column(db.Integer(), primary_key=False) global_max_missed = db.Column(db.Integer(), primary_key=False)
global_use_acl = db.Column(db.Boolean(), nullable=False, server_default='1') global_use_acl = db.Column(db.Boolean(), nullable=False, server_default='1')
global_reg_acl = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='PERMIT:ALL') global_reg_acl = db.Column(db.String(100), nullable=False, server_default='PERMIT:ALL')
global_sub_acl = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='DENY:1') global_sub_acl = db.Column(db.String(100), nullable=False, server_default='DENY:1')
global_tg1_acl = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='PERMIT:ALL') global_tg1_acl = db.Column(db.String(100), nullable=False, server_default='PERMIT:ALL')
global_tg2_acl = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='PERMIT:ALL') global_tg2_acl = db.Column(db.String(100), nullable=False, server_default='PERMIT:ALL')
ai_try_download = db.Column(db.Boolean(), nullable=False, server_default='1') ai_try_download = db.Column(db.Boolean(), nullable=False, server_default='1')
ai_path = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='./') ai_path = db.Column(db.String(100), nullable=False, server_default='./')
ai_peer_file = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='peer_ids.json') ai_peer_file = db.Column(db.String(100), nullable=False, server_default='peer_ids.json')
ai_subscriber_file = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='subscriber_ids.json') ai_subscriber_file = db.Column(db.String(100), nullable=False, server_default='subscriber_ids.json')
ai_tgid_file = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='talkgroup_ids.json') ai_tgid_file = db.Column(db.String(100), nullable=False, server_default='talkgroup_ids.json')
ai_peer_url = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='https://www.radioid.net/static/rptrs.json') ai_peer_url = db.Column(db.String(100), nullable=False, server_default='https://www.radioid.net/static/rptrs.json')
ai_subs_url = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='https://www.radioid.net/static/users.json') ai_subs_url = db.Column(db.String(100), nullable=False, server_default='https://www.radioid.net/static/users.json')
ai_stale = db.Column(db.Integer(), primary_key=False, server_default='7') ai_stale = db.Column(db.Integer(), primary_key=False, server_default='7')
# Pull from config file for now # Pull from config file for now
## um_append_int = db.Column(db.Integer(), primary_key=False, server_default='2') ## um_append_int = db.Column(db.Integer(), primary_key=False, server_default='2')
um_shorten_passphrase = db.Column(db.Boolean(), nullable=False, server_default='0') um_shorten_passphrase = db.Column(db.Boolean(), nullable=False, server_default='0')
um_burn_file = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='./burned_ids.txt') um_burn_file = db.Column(db.String(100), nullable=False, server_default='./burned_ids.txt')
# Pull from config file for now # Pull from config file for now
## um_burn_int = db.Column(db.Integer(), primary_key=False, server_default='6') ## um_burn_int = db.Column(db.Integer(), primary_key=False, server_default='6')
report_enable = db.Column(db.Boolean(), nullable=False, server_default='1') report_enable = db.Column(db.Boolean(), nullable=False, server_default='1')
report_interval = db.Column(db.Integer(), primary_key=False, server_default='60') report_interval = db.Column(db.Integer(), primary_key=False, server_default='60')
report_port = db.Column(db.Integer(), primary_key=False, server_default='4321') report_port = db.Column(db.Integer(), primary_key=False, server_default='4321')
report_clients =db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='127.0.0.1') report_clients =db.Column(db.String(100), nullable=False, server_default='127.0.0.1')
unit_time = db.Column(db.Integer(), primary_key=False, server_default='10080') unit_time = db.Column(db.Integer(), primary_key=False, server_default='10080')
notes = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') notes = db.Column(db.String(100), nullable=False, server_default='')
class MasterList(db.Model): class MasterList(db.Model):
__tablename__ = 'master_list' __tablename__ = 'master_list'
id = db.Column(db.Integer(), primary_key=True) id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') name = db.Column(db.String(100), nullable=False, server_default='')
static_positions = db.Column(db.Boolean(), nullable=False, server_default='0') static_positions = db.Column(db.Boolean(), nullable=False, server_default='0')
repeat = db.Column(db.Boolean(), nullable=False, server_default='1') repeat = db.Column(db.Boolean(), nullable=False, server_default='1')
active = db.Column(db.Boolean(), nullable=False, server_default='1') active = db.Column(db.Boolean(), nullable=False, server_default='1')
max_peers = db.Column(db.Integer(), primary_key=False, server_default='10') max_peers = db.Column(db.Integer(), primary_key=False, server_default='10')
ip = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') ip = db.Column(db.String(100), nullable=False, server_default='')
port = db.Column(db.Integer(), primary_key=False) port = db.Column(db.Integer(), primary_key=False)
enable_um = db.Column(db.Boolean(), nullable=False, server_default='1') enable_um = db.Column(db.Boolean(), nullable=False, server_default='1')
passphrase = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') passphrase = db.Column(db.String(100), nullable=False, server_default='')
group_hang_time = db.Column(db.Integer(), primary_key=False, server_default='5') group_hang_time = db.Column(db.Integer(), primary_key=False, server_default='5')
use_acl = db.Column(db.Boolean(), nullable=False, server_default='1') use_acl = db.Column(db.Boolean(), nullable=False, server_default='1')
reg_acl = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') reg_acl = db.Column(db.String(100), nullable=False, server_default='')
sub_acl = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') sub_acl = db.Column(db.String(100), nullable=False, server_default='')
tg1_acl = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') tg1_acl = db.Column(db.String(100), nullable=False, server_default='')
tg2_acl = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') tg2_acl = db.Column(db.String(100), nullable=False, server_default='')
enable_unit = db.Column(db.Boolean(), nullable=False, server_default='1') enable_unit = db.Column(db.Boolean(), nullable=False, server_default='1')
server = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') server = db.Column(db.String(100), nullable=False, server_default='')
notes = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') notes = db.Column(db.String(100), nullable=False, server_default='')
public_list = db.Column(db.Boolean(), nullable=False, server_default='1') public_list = db.Column(db.Boolean(), nullable=False, server_default='1')
class ProxyList(db.Model): class ProxyList(db.Model):
__tablename__ = 'proxy_list' __tablename__ = 'proxy_list'
id = db.Column(db.Integer(), primary_key=True) id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') name = db.Column(db.String(100), nullable=False, server_default='')
active = db.Column(db.Boolean(), nullable=False, server_default='1') active = db.Column(db.Boolean(), nullable=False, server_default='1')
static_positions = db.Column(db.Boolean(), nullable=False, server_default='0') static_positions = db.Column(db.Boolean(), nullable=False, server_default='0')
repeat = db.Column(db.Boolean(), nullable=False, server_default='1') repeat = db.Column(db.Boolean(), nullable=False, server_default='1')
enable_um = db.Column(db.Boolean(), nullable=False, server_default='1') enable_um = db.Column(db.Boolean(), nullable=False, server_default='1')
passphrase = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') passphrase = db.Column(db.String(100), nullable=False, server_default='')
external_proxy = db.Column(db.Boolean(), nullable=False, server_default='0') external_proxy = db.Column(db.Boolean(), nullable=False, server_default='0')
external_port = db.Column(db.Integer(), primary_key=False) external_port = db.Column(db.Integer(), primary_key=False)
group_hang_time = db.Column(db.Integer(), primary_key=False) group_hang_time = db.Column(db.Integer(), primary_key=False)
internal_start_port = db.Column(db.Integer(), primary_key=False) internal_start_port = db.Column(db.Integer(), primary_key=False)
internal_stop_port = db.Column(db.Integer(), primary_key=False) internal_stop_port = db.Column(db.Integer(), primary_key=False)
use_acl = db.Column(db.Boolean(), nullable=False, server_default='1') use_acl = db.Column(db.Boolean(), nullable=False, server_default='1')
reg_acl = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') reg_acl = db.Column(db.String(100), nullable=False, server_default='')
sub_acl = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') sub_acl = db.Column(db.String(100), nullable=False, server_default='')
tg1_acl = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') tg1_acl = db.Column(db.String(100), nullable=False, server_default='')
tg2_acl = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') tg2_acl = db.Column(db.String(100), nullable=False, server_default='')
enable_unit = db.Column(db.Boolean(), nullable=False, server_default='1') enable_unit = db.Column(db.Boolean(), nullable=False, server_default='1')
server = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') server = db.Column(db.String(100), nullable=False, server_default='')
notes = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') notes = db.Column(db.String(100), nullable=False, server_default='')
public_list = db.Column(db.Boolean(), nullable=False, server_default='1') public_list = db.Column(db.Boolean(), nullable=False, server_default='1')
class OBP(db.Model): class OBP(db.Model):
__tablename__ = 'OpenBridge' __tablename__ = 'OpenBridge'
id = db.Column(db.Integer(), primary_key=True) id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') name = db.Column(db.String(100), nullable=False, server_default='')
enabled = db.Column(db.Boolean(), nullable=False, server_default='1') enabled = db.Column(db.Boolean(), nullable=False, server_default='1')
network_id = db.Column(db.Integer(), primary_key=False) network_id = db.Column(db.Integer(), primary_key=False)
ip = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') ip = db.Column(db.String(100), nullable=False, server_default='')
port = db.Column(db.Integer(), primary_key=False) port = db.Column(db.Integer(), primary_key=False)
passphrase = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') passphrase = db.Column(db.String(100), nullable=False, server_default='')
target_ip = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') target_ip = db.Column(db.String(100), nullable=False, server_default='')
target_port = db.Column(db.Integer(), primary_key=False) target_port = db.Column(db.Integer(), primary_key=False)
both_slots = db.Column(db.Boolean(), nullable=False, server_default='1') both_slots = db.Column(db.Boolean(), nullable=False, server_default='1')
use_acl = db.Column(db.Boolean(), nullable=False, server_default='1') use_acl = db.Column(db.Boolean(), nullable=False, server_default='1')
sub_acl = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') sub_acl = db.Column(db.String(100), nullable=False, server_default='')
tg_acl = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') tg_acl = db.Column(db.String(100), nullable=False, server_default='')
enable_unit = db.Column(db.Boolean(), nullable=False, server_default='1') enable_unit = db.Column(db.Boolean(), nullable=False, server_default='1')
server = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') server = db.Column(db.String(100), nullable=False, server_default='')
notes = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') notes = db.Column(db.String(100), nullable=False, server_default='')
class BridgeRules(db.Model): class BridgeRules(db.Model):
__tablename__ = 'bridge_rules' __tablename__ = 'bridge_rules'
id = db.Column(db.Integer(), primary_key=True) id = db.Column(db.Integer(), primary_key=True)
bridge_name = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') bridge_name = db.Column(db.String(100), nullable=False, server_default='')
system_name = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') system_name = db.Column(db.String(100), nullable=False, server_default='')
ts = db.Column(db.Integer(), primary_key=False) ts = db.Column(db.Integer(), primary_key=False)
tg = db.Column(db.Integer(), primary_key=False) tg = db.Column(db.Integer(), primary_key=False)
active = db.Column(db.Boolean(), nullable=False, server_default='1') active = db.Column(db.Boolean(), nullable=False, server_default='1')
timeout = db.Column(db.Integer(), primary_key=False) timeout = db.Column(db.Integer(), primary_key=False)
to_type = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') to_type = db.Column(db.String(100), nullable=False, server_default='')
on = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') on = db.Column(db.String(100), nullable=False, server_default='')
off = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') off = db.Column(db.String(100), nullable=False, server_default='')
reset = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') reset = db.Column(db.String(100), nullable=False, server_default='')
server = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') server = db.Column(db.String(100), nullable=False, server_default='')
public_list = db.Column(db.Boolean(), nullable=False, server_default='0') public_list = db.Column(db.Boolean(), nullable=False, server_default='0')
proxy = db.Column(db.Boolean(), nullable=False, server_default='0') proxy = db.Column(db.Boolean(), nullable=False, server_default='0')
class BridgeList(db.Model): class BridgeList(db.Model):
__tablename__ = 'bridge_list' __tablename__ = 'bridge_list'
id = db.Column(db.Integer(), primary_key=True) id = db.Column(db.Integer(), primary_key=True)
bridge_name = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') bridge_name = db.Column(db.String(100), nullable=False, server_default='')
description = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='') description = db.Column(db.String(100), nullable=False, server_default='')
public_list = db.Column(db.Boolean(), nullable=False, server_default='0') public_list = db.Column(db.Boolean(), nullable=False, server_default='0')
tg = db.Column(db.Integer(), primary_key=False) tg = db.Column(db.Integer(), primary_key=False)
@ -712,6 +735,7 @@ def create_app():
elif request.method == 'POST': # and request.form.get('callsign') and request.form.get('subject') and request.form.get('message'): elif request.method == 'POST': # and request.form.get('callsign') and request.form.get('subject') and request.form.get('message'):
u = User.query.filter_by(username=request.args.get('callsign')).first() u = User.query.filter_by(username=request.args.get('callsign')).first()
msg = Message(recipients=[u.email], msg = Message(recipients=[u.email],
sender=(title, MAIL_DEFAULT_SENDER),
subject=request.form.get('subject'), subject=request.form.get('subject'),
body=request.form.get('message')) body=request.form.get('message'))
mail.send(msg) mail.send(msg)
@ -880,8 +904,9 @@ def create_app():
edit_user.initial_admin_approved = True edit_user.initial_admin_approved = True
db.session.commit() db.session.commit()
msg = Message(recipients=[edit_user.email], msg = Message(recipients=[edit_user.email],
subject='Account Approval - ' + title, sender=(title, MAIL_DEFAULT_SENDER),
body='''You are receiving this message because an administrator has approved your account. You may now login and view your MMDVM passphrase(s).''') subject='Account Approval',
body='''You are receiving this message because an administrator has approved your account. You may now login and use ''' + title + '''.''')
mail.send(msg) mail.send(msg)
content = '''<p style="text-align: center;">User approved: <strong>''' + str(request.args.get('callsign')) + '''</strong></p>\n''' content = '''<p style="text-align: center;">User approved: <strong>''' + str(request.args.get('callsign')) + '''</strong></p>\n'''
@ -1457,7 +1482,7 @@ def create_app():
content = content + '</tbody></table>' content = content + '</tbody></table>'
return render_template('flask_user_layout.html', markup_content = Markup(content)) return render_template('flask_user_layout.html', markup_content = Markup(content))
@app.route('/self_care') @app.route('/user_tg')
def tg_status(): def tg_status():
cu = current_user cu = current_user
u = User.query.filter_by(username=cu.username).first() u = User.query.filter_by(username=cu.username).first()
@ -4967,4 +4992,4 @@ def create_app():
if __name__ == '__main__': if __name__ == '__main__':
app = create_app() app = create_app()
app.run(debug = True, port=ums_port, host=ums_host) app.run(debug = True, port=hws_port, host=hws_host)

View File

@ -1,33 +1,65 @@
''' '''
Settings for user management portal. Settings for HBNet Web Server.
''' '''
# Database location # Database options
db_location = 'sqlite:///./users.db' # Using SQLite is simple and easiest. Comment out this line and uncomment the MySQL
# line to use a MySQL/MariaDB server.
db_location = 'sqlite:///hbnet.sqlite'
# Uncomment and change this line to use a MySQL DB. It is best to start with a fresh
# DB without data in it.
#db_location = 'mysql+pymysql://DB_USERNAME:DB_PASSWORD@DB_HOST:MySQL_PORT/DB_NAME'
# Title of the HBNet Web Server
title = 'HBNet DMR server'
# Port to run server
hws_port = 8080
# IP to run server on
hws_host = '127.0.0.1'
# Publicly accessible URL of the web server. THIS IS REQUIRED AND MUST BE CORRECT.
url = 'http://localhost:8080'
# Replace below with some random string such as an SHA256
secret_key = 'SUPER SECRET LONG KEY'
# Default state for newly created user accounts. Setting to False will require
# the approval of an admin user before the user can login.
default_account_state = True
# Legacy passphrase used in hblink.cfg # Legacy passphrase used in hblink.cfg
legacy_passphrase = 'passw0rd' #legacy_passphrase = 'passw0rd'
# Trim passphrases to 8 characters
use_short_passphrase = False
# Title of the Dashboard # Passphrase calculation config. If REMOTE_CONFIG is not used in your DMR server config
title = 'MMDVM User Portal' # (hblink.cfg), then the values in section [USER_MANAGER] MUST match the values below.
# Port to run server # If REMOTE_CONFIG is enabled, the DMR server (hblink) will automatically use the values below.
ums_port = 8080 # These config options affect the generation of user passphrases.
# IP to run server on
ums_host = '127.0.0.1'
url = 'http://localhost:8080'
# Set to a value between 1 - 99. This value is used in the normal calculation.
append_int = 1 append_int = 1
shared_secrets = ['test'] # Set to a value between 1 - 99. This value is used for compromised passphrases.
burn_int = 5 burn_int = 5
legacy_passphrase = 'passw0rd' # Set to a value between 1 - 99 This value is used in the normal calculation.
extra_int_1 = 5
# Set to a value between 1 - 99 This value is used in the normal calculation.
extra_int_2 = 8
# Set to a length of about 10 characters.
extra_1 = 'TeSt'
extra_2 = 'DmR4'
# Shorten generated passphrases
use_short_passphrase = True
# Character length of shortened passphrase
shorten_length = 6
# How often to pick character from long passphrase when shortening.
shorten_sample = 4
# Email settings # Email settings
MAIL_SERVER = 'smtp.gmail.com' MAIL_SERVER = 'smtp.gmail.com'
@ -38,12 +70,10 @@ MAIL_USERNAME = 'app@gmail.com'
MAIL_PASSWORD = 'password' MAIL_PASSWORD = 'password'
MAIL_DEFAULT_SENDER = '"' + title + '" <app@gmail.com>' MAIL_DEFAULT_SENDER = '"' + title + '" <app@gmail.com>'
# UMS settings # User settings settings
secret_key = 'SUPER SECRET LONG KEY'
USER_ENABLE_EMAIL = True USER_ENABLE_EMAIL = True
USER_ENABLE_USERNAME = True # Enable username authentication USER_ENABLE_USERNAME = True
USER_REQUIRE_RETYPE_PASSWORD = True # Simplify register form USER_REQUIRE_RETYPE_PASSWORD = True
USER_ENABLE_CHANGE_USERNAME = False USER_ENABLE_CHANGE_USERNAME = False
USER_ENABLE_MULTIPLE_EMAILS = True USER_ENABLE_MULTIPLE_EMAILS = True
USER_ENABLE_CONFIRM_EMAIL = True USER_ENABLE_CONFIRM_EMAIL = True
@ -51,12 +81,7 @@ USER_ENABLE_REGISTER = True
USER_AUTO_LOGIN_AFTER_CONFIRM = False USER_AUTO_LOGIN_AFTER_CONFIRM = False
USER_SHOW_USERNAME_DOES_NOT_EXIST = True USER_SHOW_USERNAME_DOES_NOT_EXIST = True
# Gateway contact info displayed on about page.
contact_name = 'your name'
contact_call = 'N0CALL'
contact_email = 'email@example.org'
contact_website = 'https://hbl.ink'
# Time format for display # Time format for display on some pages
time_format = '%H:%M:%S - %m/%d/%y' time_format = '%H:%M:%S - %m/%d/%y'

View File

@ -53,7 +53,7 @@
{% endif %} {% endif %}
<td style="text-align: center;"><a href={{url}}/help>Help</a></td> <td style="text-align: center;"><a href={{url}}/help>Help</a></td>
<td style="text-align: center;"><a href={{url}}/generate_passphrase>View Passphrase(s)</a></td> <td style="text-align: center;"><a href={{url}}/generate_passphrase>View Passphrase(s)</a></td>
<td style="text-align: center;"><a href={{url}}/self_care>Self Care</a></td> <td style="text-align: center;"><a href={{url}}/user_tg>Current TGs</a></td>
<td style="text-align: center;"><a href="{{ url_for('user.edit_user_profile') }}">Edit {{ current_user.username or current_user.email }}</a></td> <td style="text-align: center;"><a href="{{ url_for('user.edit_user_profile') }}">Edit {{ current_user.username or current_user.email }}</a></td>
<td style="text-align: center;"><a href={{ url_for('user.logout') }}>Sign out</a></td> <td style="text-align: center;"><a href={{ url_for('user.logout') }}>Sign out</a></td>
{% endif %} {% endif %}