Skip to content

Commit bb90635

Browse files
authored
Merge pull request #62 from BlueSquare23/dev-1.9.0
Version 1.9.0 Release
2 parents b835d4d + 25efe2c commit bb90635

File tree

133 files changed

+7470
-4820
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

133 files changed

+7470
-4820
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,6 @@ jobs:
3434
./install.sh -d
3535
cp main.conf main.conf.local # Setup local copy of conf for tests
3636
37-
- name: Check sudo access
38-
run: |
39-
sudo -l
40-
4137
- name: Install & Setup Java for Mockcraft Server Tests
4238
run: |
4339
sudo apt update
@@ -53,6 +49,7 @@ jobs:
5349
- name: Run Pytest Tests
5450
run: |
5551
RUNNER_TRACKING_ID="" && $HOME/web-lgsm.py --test_full
52+
# RUNNER_TRACKING_ID="" && $HOME/web-lgsm.py --test
5653

5754
- name: Generate coverage report
5855
run: |

.secret

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
SECRET_KEY="ChangeThisValue!!!"
1+
SECRET_KEY="8a9dde427355fe4a80c8"

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,29 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [v1.9.0 - 2026-02-08]
9+
10+
### Added
11+
12+
- New form to edit server details before installation on install page.
13+
- Begin re-architecture efforts to enable continued app growth.
14+
- New new alt user management system to allow running as other users via
15+
sudoers instead of over SSH.
16+
17+
### Changed
18+
19+
- Use flask cache for tmux socket name caching now.
20+
- Restructured app directory to better house individual app components.
21+
- Broke up monolithic `views.py`, `auth.py`, and `utils.py` into modular components.
22+
- Change user permission structure (**BREAKING CHANGE!** :warning: See FAQ 13)
23+
- Rename "Command" to "Controls" through projects source (where applicable).
24+
25+
### Fixed
26+
27+
- Fix bug with npm install on Debian ([#discussion-60](https://github.com/BlueSquare23/web-lgsm/discussions/60)).
28+
- Fix bug with term not scaling on dynamic user resize.
29+
- Upgrade pip requirement `requests` to v2.32.5 (thanks dependabot!).
30+
831
## [v1.8.6 - 2025-11-22]
932

1033
### Added

SECURITY.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ security fixes.
77

88
| Version | Supported |
99
| ------- | ------------------ |
10+
| 1.9.0 | :white_check_mark: |
1011
| 1.8.6 | :white_check_mark: |
11-
| 1.8.5 | :white_check_mark: |
12-
| < 1.8.4 | :x: |
12+
| < 1.8.5 | :x: |
1313

1414
## Reporting a Vulnerability
1515

Todos.md

Lines changed: 501 additions & 86 deletions
Large diffs are not rendered by default.

app/__init__.py

Lines changed: 95 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -5,128 +5,99 @@
55
from flask import Flask
66
from pathlib import Path
77
from dotenv import load_dotenv
8-
from flask_login import LoginManager
9-
from flask_sqlalchemy import SQLAlchemy
10-
from sqlalchemy import MetaData
118
from logging.config import dictConfig
129
from flask.logging import default_handler
1310
from flask_swagger_ui import get_swaggerui_blueprint
14-
from flask_migrate import Migrate
15-
from flask_caching import Cache
11+
12+
# Import extensions
13+
from .extensions import db, login_manager, migrate, cache
1614

1715
# Prevent creation of __pycache__. Pycache messes up auth.
1816
sys.dont_write_bytecode = True
1917

2018
DB_NAME = "database.db"
2119

22-
# Naming conventions for Flask-Migrate.
23-
convention = {
24-
"ix": "ix_%(column_0_label)s",
25-
"uq": "uq_%(table_name)s_%(column_0_name)s",
26-
"ck": "ck_%(table_name)s_%(constraint_name)s",
27-
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
28-
"pk": "pk_%(table_name)s",
29-
}
30-
metadata = MetaData(naming_convention=convention)
31-
db = SQLAlchemy(metadata=metadata)
32-
3320
env_path = Path(".") / ".secret"
3421
load_dotenv(dotenv_path=env_path)
3522
SECRET_KEY = os.environ["SECRET_KEY"]
3623
SWAGGER_URL = "/docs"
3724
API_URL = "/api/spec"
38-
cache = Cache(config={'CACHE_TYPE': 'SimpleCache'})
3925

40-
def main():
41-
# Setup logging.
26+
def setup_logging():
27+
"""Configure logging settings"""
4228
log_level_map = {
43-
"info": logging.INFO, # General operational info.
44-
"warning": logging.WARNING, # Warnings and above.
45-
"debug": logging.DEBUG, # Most verbose, debug info.
29+
"info": logging.INFO,
30+
"warning": logging.WARNING,
31+
"debug": logging.DEBUG,
4632
}
4733

48-
if "DEBUG" in os.environ:
49-
# Get log_level from env var, default to info if none set.
50-
log_level_str = os.getenv("LOG_LEVEL", "info").lower()
51-
log_level = log_level_map.get(log_level_str, logging.INFO)
52-
dictConfig(
53-
{
54-
"version": 1,
55-
"formatters": {
56-
"default": {
57-
"format": "[%(asctime)s] %(levelname)s in %(module)s: %(message)s",
58-
},
59-
"audit": {
60-
"format": "[%(asctime)s] AUDIT: %(message)s",
61-
}
34+
# Get log_level from env var, default to info if none set.
35+
log_level_str = os.getenv("LOG_LEVEL", "info").lower()
36+
log_level = log_level_map.get(log_level_str, logging.INFO)
37+
38+
dictConfig(
39+
{
40+
"version": 1,
41+
'disable_existing_loggers': False,
42+
"formatters": {
43+
"default": {
44+
"format": "[%(asctime)s] %(levelname)s in %(module)s: %(message)s",
6245
},
63-
"handlers": {
64-
"wsgi": {
65-
"class": "logging.StreamHandler",
66-
"stream": "ext://flask.logging.wsgi_errors_stream",
67-
"formatter": "default",
68-
},
69-
"audit_file": {
70-
"class": "logging.FileHandler",
71-
"filename": "logs/audit.log",
72-
"formatter": "audit",
73-
}
74-
},
75-
"loggers": {
76-
"audit": {
77-
"level": "INFO",
78-
"handlers": ["audit_file"],
79-
"propagate": False,
80-
}
46+
"audit": {
47+
"format": "[%(asctime)s] AUDIT: %(message)s",
48+
}
49+
},
50+
"handlers": {
51+
"wsgi": {
52+
"class": "logging.StreamHandler",
53+
"stream": "ext://flask.logging.wsgi_errors_stream",
54+
"formatter": "default",
8155
},
82-
"root": {
83-
"level": log_level,
84-
"handlers": ["wsgi"]
56+
"audit_file": {
57+
"class": "logging.FileHandler",
58+
"filename": "logs/audit.log",
59+
"formatter": "audit",
60+
}
61+
},
62+
"loggers": {
63+
"audit": {
64+
"level": "INFO",
65+
"handlers": ["audit_file"],
66+
"propagate": False,
8567
},
86-
}
87-
)
68+
},
69+
"root": {
70+
"level": log_level,
71+
"handlers": ["wsgi"]
72+
},
73+
}
74+
)
8875

8976
current_log_level = logging.getLogger().getEffectiveLevel()
90-
91-
# Print the human-readable log level name
9277
print(f"Root logger level: {logging.getLevelName(current_log_level)}")
9378

94-
# Initialize app.
95-
app = Flask(__name__)
96-
app.config["SECRET_KEY"] = SECRET_KEY
97-
app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///{app.root_path}/{DB_NAME}"
98-
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
99-
app.config["SESSION_COOKIE_SAMESITE"] = "Lax"
100-
app.config["REMEMBER_COOKIE_SAMESITE"] = "Lax"
101-
app.logger.removeHandler(default_handler)
102-
app.audit_logger = logging.getLogger('audit')
103-
migrate = Migrate(app, db, render_as_batch=True)
104-
cache.init_app(app)
105-
app.jinja_env.add_extension('jinja2.ext.loopcontrols')
106-
107-
# Initialize DB.
79+
def register_extensions(app):
80+
"""Register Flask extensions with the app"""
10881
db.init_app(app)
109-
migrate.init_app(app, db)
110-
111-
# Load models.
112-
from .models import User
113-
114-
# Pull in our views route(s).
115-
from .views import views
116-
117-
app.register_blueprint(views, url_prefix="/")
118-
119-
# Pull in our auth route(s).
120-
from .auth import auth
82+
migrate.init_app(app, db, render_as_batch=True)
83+
cache.init_app(app)
12184

122-
app.register_blueprint(auth, url_prefix="/")
85+
# Setup LoginManager
86+
login_manager.login_view = "auth.login"
87+
login_manager.login_message = None
88+
login_manager.init_app(app)
12389

124-
# Pull in our api route(s).
125-
from .api import api_bp
90+
def register_blueprints(app):
91+
"""Register blueprints with the app"""
92+
from .blueprints.main import main_bp
93+
from .blueprints.auth import auth_bp
94+
from .blueprints.api import api_bp
12695

96+
app.register_blueprint(main_bp, url_prefix="/")
97+
app.register_blueprint(auth_bp, url_prefix="/")
12798
app.register_blueprint(api_bp, url_prefix="/api")
12899

129-
# Create Swagger UI blueprint.
100+
# Register Swagger UI blueprint
130101
swagger_ui = get_swaggerui_blueprint(
131102
SWAGGER_URL,
132103
API_URL,
@@ -147,27 +118,46 @@ def main():
147118
},
148119
},
149120
)
150-
151-
# Register Swagger UI blueprint
152121
app.register_blueprint(swagger_ui)
153122

154-
# Setup LoginManager.
155-
login_manager = LoginManager()
123+
def register_template_filters(app):
124+
"""Register custom template filters"""
125+
@app.template_filter("from_json")
126+
def from_json_filter(s):
127+
return json.loads(s)
156128

157-
# Redirect to auth.login if not already logged in.
158-
login_manager.login_view = "auth.login"
159-
login_manager.login_message = None
160-
login_manager.init_app(app)
129+
def register_user_loader():
130+
"""Register the user loader for Flask-Login"""
131+
from .models import User
161132

162-
# Decorator to set up login session.
163133
@login_manager.user_loader
164134
def load_user(id):
165135
return db.session.get(User, int(id))
166136

167-
# Filter for jinja2 json parsing for user permissions.
168-
@app.template_filter("from_json")
169-
def from_json_filter(s):
170-
return json.loads(s)
137+
def create_app():
138+
"""Application factory function"""
139+
# Setup logging first
140+
setup_logging()
171141

172-
return app
142+
# Initialize app
143+
app = Flask(__name__)
144+
app.config["SECRET_KEY"] = SECRET_KEY
145+
app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///{app.root_path}/{DB_NAME}"
146+
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
147+
app.config["SESSION_COOKIE_SAMESITE"] = "Lax"
148+
app.config["REMEMBER_COOKIE_SAMESITE"] = "Lax"
173149

150+
# Remove default handler and add audit logger
151+
app.logger.removeHandler(default_handler)
152+
app.audit_logger = logging.getLogger('audit')
153+
154+
# Add Jinja2 extension
155+
app.jinja_env.add_extension('jinja2.ext.loopcontrols')
156+
157+
# Register everything
158+
register_extensions(app)
159+
register_blueprints(app)
160+
register_template_filters(app)
161+
register_user_loader()
162+
163+
return app

0 commit comments

Comments
 (0)