Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd0cd64849 | ||
|
|
aab671398c | ||
|
|
d64aeb25d5 | ||
|
|
aa4fa83127 | ||
|
|
81c3dc1d95 |
No files matched your search
+15
-2
@@ -19,6 +19,15 @@ Fixing other platforms In Progress.
|
||||
|
||||
[Upgrade WeKan](https://wekan.fi/upgrade/)
|
||||
|
||||
# v7.99 2025-10-11 WeKan ® release
|
||||
|
||||
This release fixed the following bugs:
|
||||
|
||||
- [Improve automatic Snap upgrades](https://github.com/wekan/wekan/commit/aab671398c7ee3d7ea4934c6c9c977ad630fa74f).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v7.98 2025-10-11 WeKan ® release
|
||||
|
||||
This release adds the following CRITICAL SECURITY FIXES:
|
||||
@@ -29,14 +38,18 @@ This release adds the following CRITICAL SECURITY FIXES:
|
||||
Thanks to Anynymous Security Researcher and xet7.
|
||||
- [Security Fix FG-VD-22-078: Prevent SVG Billion Laughs Attack](https://github.com/wekan/wekan/commit/30c1597b658b0ef50fd2efc56786e8b0f08ac72c).
|
||||
Thanks to Nguyen Thanh Nguyen of Fortinet's FortiGuard Labs and xet7.
|
||||
- [Security Fix usd-2022-0041: CWE-284 Improper Access Control](https://github.com/wekan/wekan/commit/f6591d7820e01075cba93612a5fdbf692fbe49dc).
|
||||
Thanks to Christian Pöschl of usd AG and xet7.
|
||||
- [Security Fix JVN#14269684: Broken access control](https://github.com/wekan/wekan/commit/9720e703fd9432bf0e1bfea2358f8c7ea078f1b1).
|
||||
Thanks to Ryoya Koyama of Mitsui Bussan Secure Directions, Inc and xet7.
|
||||
- [Security Fix JVN#74210258: Stored XSS](https://github.com/wekan/wekan/commit/e1fa607f87d821accb846f2deef1f388003848d1).
|
||||
Thanks to Ryoya Koyama of Mitsui Bussan Secure Directions, Inc and xet7.
|
||||
- [Security Fix JVN#86586539: Stored XSS](https://github.com/wekan/wekan/commit/ee79cab7b27f73fab62a00ec49add73fd6f7bcaa).
|
||||
Thanks to Ryoya Koyama of Mitsui Bussan Secure Directions, Inc and xet7.
|
||||
- [Security Fix usd-2022-0041: CWE-284 Improper Access Control](https://github.com/wekan/wekan/commit/f6591d7820e01075cba93612a5fdbf692fbe49dc).
|
||||
Thanks to Christian Pöschl of usd AG and xet7.
|
||||
- [Security Fix JVN#15385465: CWE-79 XSS, that affected WeKan 7.94](https://github.com/wekan/wekan/commit/81c3dc1d956cd7040655940f6569653d7b98fa9a).
|
||||
Thanks to Sho Sugiyama and xet7.
|
||||
- Security Fix JVN#80785288: CWE-79 XSS, that affected WeKan 3.94 and v3.95. This was already previously fixed.
|
||||
Thanks to xet7.
|
||||
|
||||
and adds the following new features:
|
||||
|
||||
|
||||
+3
-3
@@ -249,9 +249,9 @@ cd /home/wekan/app
|
||||
# Remove legacy webbroser bundle, so that Wekan works also at Android Firefox, iOS Safari, etc.
|
||||
#rm -rf /home/wekan/app_build/bundle/programs/web.browser.legacy
|
||||
#mv /home/wekan/app_build/bundle /build
|
||||
wget "https://github.com/wekan/wekan/releases/download/v7.98/wekan-7.98-amd64.zip"
|
||||
unzip wekan-7.98-amd64.zip
|
||||
rm wekan-7.98-amd64.zip
|
||||
wget "https://github.com/wekan/wekan/releases/download/v7.99/wekan-7.99-amd64.zip"
|
||||
unzip wekan-7.99-amd64.zip
|
||||
rm wekan-7.99-amd64.zip
|
||||
mv /home/wekan/app/bundle /build
|
||||
|
||||
# Put back the original tar
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
appId: wekan-public/apps/77b94f60-dec9-0136-304e-16ff53095928
|
||||
appVersion: "v7.98.0"
|
||||
appVersion: "v7.99.0"
|
||||
files:
|
||||
userUploads:
|
||||
- README.md
|
||||
|
||||
@@ -10,7 +10,7 @@ This is without container (without Docker or Snap).
|
||||
|
||||
Right click and download files 1-4:
|
||||
|
||||
1. [wekan-7.98-amd64-windows.zip](https://github.com/wekan/wekan/releases/download/v7.98/wekan-7.98-amd64-windows.zip)
|
||||
1. [wekan-7.99-amd64-windows.zip](https://github.com/wekan/wekan/releases/download/v7.99/wekan-7.99-amd64-windows.zip)
|
||||
|
||||
2. [node.exe](https://nodejs.org/dist/latest-v14.x/win-x64/node.exe)
|
||||
|
||||
@@ -22,7 +22,7 @@ Right click and download files 1-4:
|
||||
|
||||
6. Double click `mongodb-windows-x86_64-7.0.25-signed.msi` . In installer, uncheck downloading MongoDB compass.
|
||||
|
||||
7. Unzip `wekan-7.98-amd64-windows.zip` , inside it is directory `bundle`, to it copy other files:
|
||||
7. Unzip `wekan-7.99-amd64-windows.zip` , inside it is directory `bundle`, to it copy other files:
|
||||
|
||||
```
|
||||
bundle (directory)
|
||||
|
||||
@@ -51,14 +51,37 @@ export function getSecureDOMPurifyConfig() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Block img tags with SVG data URIs
|
||||
// Block img tags with SVG data URIs that could contain malicious JavaScript
|
||||
if (node.tagName && node.tagName.toLowerCase() === 'img') {
|
||||
const src = node.getAttribute('src');
|
||||
if (src && (src.startsWith('data:image/svg') || src.endsWith('.svg'))) {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.warn('Blocked potentially malicious SVG image:', src);
|
||||
if (src) {
|
||||
// Block all SVG data URIs to prevent XSS via embedded JavaScript
|
||||
if (src.startsWith('data:image/svg') || src.endsWith('.svg')) {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.warn('Blocked potentially malicious SVG image:', src);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Additional check for base64 encoded SVG with script tags
|
||||
if (src.startsWith('data:image/svg+xml;base64,')) {
|
||||
try {
|
||||
const base64Content = src.split(',')[1];
|
||||
const decodedContent = atob(base64Content);
|
||||
if (decodedContent.includes('<script') || decodedContent.includes('javascript:')) {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.warn('Blocked SVG with embedded JavaScript:', src.substring(0, 100) + '...');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
// If decoding fails, block it as a safety measure
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.warn('Blocked malformed SVG data URI:', src);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wekan",
|
||||
"version": "v7.98.0",
|
||||
"version": "v7.99.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wekan",
|
||||
"version": "v7.98.0",
|
||||
"version": "v7.99.0",
|
||||
"description": "Open-Source kanban",
|
||||
"private": true,
|
||||
"repository": {
|
||||
|
||||
@@ -51,14 +51,37 @@ export function getSecureDOMPurifyConfig() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Block img tags with SVG data URIs
|
||||
// Block img tags with SVG data URIs that could contain malicious JavaScript
|
||||
if (node.tagName && node.tagName.toLowerCase() === 'img') {
|
||||
const src = node.getAttribute('src');
|
||||
if (src && (src.startsWith('data:image/svg') || src.endsWith('.svg'))) {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.warn('Blocked potentially malicious SVG image:', src);
|
||||
if (src) {
|
||||
// Block all SVG data URIs to prevent XSS via embedded JavaScript
|
||||
if (src.startsWith('data:image/svg') || src.endsWith('.svg')) {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.warn('Blocked potentially malicious SVG image:', src);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Additional check for base64 encoded SVG with script tags
|
||||
if (src.startsWith('data:image/svg+xml;base64,')) {
|
||||
try {
|
||||
const base64Content = src.split(',')[1];
|
||||
const decodedContent = atob(base64Content);
|
||||
if (decodedContent.includes('<script') || decodedContent.includes('javascript:')) {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.warn('Blocked SVG with embedded JavaScript:', src.substring(0, 100) + '...');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
// If decoding fails, block it as a safety measure
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.warn('Blocked malformed SVG data URI:', src);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -103,58 +103,87 @@ Markdown.use(function(md) {
|
||||
}
|
||||
}
|
||||
|
||||
// Check for HTML tokens that might contain SVG
|
||||
// Check for HTML tokens that might contain SVG or malicious content
|
||||
if (token.type === 'html_block' || token.type === 'html_inline') {
|
||||
const content = token.content;
|
||||
if (content && (
|
||||
content.includes('<svg') ||
|
||||
content.includes('data:image/svg') ||
|
||||
content.includes('xlink:href') ||
|
||||
content.includes('<use') ||
|
||||
content.includes('<defs>')
|
||||
)) {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.warn('Blocked potentially malicious SVG content in HTML:', content.substring(0, 100) + '...');
|
||||
if (content) {
|
||||
// Check for SVG content
|
||||
const hasSVG = content.includes('<svg') ||
|
||||
content.includes('data:image/svg') ||
|
||||
content.includes('xlink:href') ||
|
||||
content.includes('<use') ||
|
||||
content.includes('<defs>');
|
||||
|
||||
// Check for malicious img tags with SVG data URIs
|
||||
const hasMaliciousImg = content.includes('<img') &&
|
||||
(content.includes('data:image/svg') ||
|
||||
content.includes('src="data:image/svg'));
|
||||
|
||||
// Check for base64 encoded SVG with script tags
|
||||
const hasBase64SVG = content.includes('data:image/svg+xml;base64,');
|
||||
|
||||
if (hasSVG || hasMaliciousImg || hasBase64SVG) {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.warn('Blocked potentially malicious SVG content in HTML:', content.substring(0, 100) + '...');
|
||||
}
|
||||
|
||||
// Additional check for base64 encoded SVG with script tags
|
||||
if (hasBase64SVG) {
|
||||
try {
|
||||
const base64Match = content.match(/data:image\/svg\+xml;base64,([^"'\s]+)/);
|
||||
if (base64Match) {
|
||||
const decodedContent = atob(base64Match[1]);
|
||||
if (decodedContent.includes('<script') || decodedContent.includes('javascript:')) {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.warn('Blocked SVG with embedded JavaScript in markdown');
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// If decoding fails, continue with blocking
|
||||
}
|
||||
}
|
||||
|
||||
// Replace with warning
|
||||
token.type = 'paragraph_open';
|
||||
token.tag = 'p';
|
||||
token.nesting = 1;
|
||||
token.attrSet('style', 'color: red; background: #ffe6e6; padding: 8px; border: 1px solid #ff9999;');
|
||||
token.attrSet('title', 'Blocked potentially malicious SVG content');
|
||||
|
||||
// Add warning text
|
||||
const warningToken = {
|
||||
type: 'text',
|
||||
content: '⚠️ Blocked potentially malicious SVG content for security reasons',
|
||||
level: token.level,
|
||||
markup: '',
|
||||
info: '',
|
||||
meta: null,
|
||||
block: true,
|
||||
hidden: false
|
||||
};
|
||||
|
||||
// Insert warning token after the paragraph open
|
||||
tokens.splice(i + 1, 0, warningToken);
|
||||
|
||||
// Add paragraph close token
|
||||
const closeToken = {
|
||||
type: 'paragraph_close',
|
||||
tag: 'p',
|
||||
nesting: -1,
|
||||
level: token.level,
|
||||
markup: '',
|
||||
info: '',
|
||||
meta: null,
|
||||
block: true,
|
||||
hidden: false
|
||||
};
|
||||
tokens.splice(i + 2, 0, closeToken);
|
||||
|
||||
// Remove the original HTML token
|
||||
tokens.splice(i, 1);
|
||||
i--; // Adjust index since we removed a token
|
||||
}
|
||||
// Replace with warning
|
||||
token.type = 'paragraph_open';
|
||||
token.tag = 'p';
|
||||
token.nesting = 1;
|
||||
token.attrSet('style', 'color: red; background: #ffe6e6; padding: 8px; border: 1px solid #ff9999;');
|
||||
token.attrSet('title', 'Blocked potentially malicious SVG content');
|
||||
|
||||
// Add warning text
|
||||
const warningToken = {
|
||||
type: 'text',
|
||||
content: '⚠️ Blocked potentially malicious SVG content for security reasons',
|
||||
level: token.level,
|
||||
markup: '',
|
||||
info: '',
|
||||
meta: null,
|
||||
block: true,
|
||||
hidden: false
|
||||
};
|
||||
|
||||
// Insert warning token after the paragraph open
|
||||
tokens.splice(i + 1, 0, warningToken);
|
||||
|
||||
// Add paragraph close token
|
||||
const closeToken = {
|
||||
type: 'paragraph_close',
|
||||
tag: 'p',
|
||||
nesting: -1,
|
||||
level: token.level,
|
||||
markup: '',
|
||||
info: '',
|
||||
meta: null,
|
||||
block: true,
|
||||
hidden: false
|
||||
};
|
||||
tokens.splice(i + 2, 0, closeToken);
|
||||
|
||||
// Remove the original HTML token
|
||||
tokens.splice(i, 1);
|
||||
i--; // Adjust index since we removed a token
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1524,7 +1524,7 @@ var n=this.pipeline.run(e.tokenizer(t)),r=new e.Vector,i=[],o=this._fields.reduc
|
||||
<ul class="toc-list-h1">
|
||||
|
||||
<li>
|
||||
<a href="#wekan-rest-api" class="toc-h1 toc-link" data-title="Wekan REST API v7.98">Wekan REST API v7.98</a>
|
||||
<a href="#wekan-rest-api" class="toc-h1 toc-link" data-title="Wekan REST API v7.99">Wekan REST API v7.99</a>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -2053,7 +2053,7 @@ var n=this.pipeline.run(e.tokenizer(t)),r=new e.Vector,i=[],o=this._fields.reduc
|
||||
<div class="page-wrapper">
|
||||
<div class="dark-box"></div>
|
||||
<div class="content">
|
||||
<h1 id="wekan-rest-api">Wekan REST API v7.98</h1>
|
||||
<h1 id="wekan-rest-api">Wekan REST API v7.99</h1>
|
||||
<blockquote>
|
||||
<p>Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.</p>
|
||||
</blockquote>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
swagger: '2.0'
|
||||
info:
|
||||
title: Wekan REST API
|
||||
version: v7.98
|
||||
version: v7.99
|
||||
description: |
|
||||
The REST API allows you to control and extend Wekan with ease.
|
||||
|
||||
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Release script for wekan versions.
|
||||
|
||||
# 1) Check that there is only 2 parameters
|
||||
# of Wekan version number:
|
||||
|
||||
if [ $# -ne 2 ]
|
||||
then
|
||||
echo "Syntax with Wekan current-version release-new-version:"
|
||||
echo " ./release.sh 7.20 7.21"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sed -i 's|$1|$2|g' snapcraft.yaml docs/Platforms/Propietary/Windows/Offline.md Dockerfile Stackerfile.yml sandstorm-pkgdef.capnp
|
||||
@@ -22,10 +22,10 @@ const pkgdef :Spk.PackageDefinition = (
|
||||
appTitle = (defaultText = "Wekan"),
|
||||
# The name of the app as it is displayed to the user.
|
||||
|
||||
appVersion = 798,
|
||||
appVersion = 799,
|
||||
# Increment this for every release.
|
||||
|
||||
appMarketingVersion = (defaultText = "7.98.0~2025-10-11"),
|
||||
appMarketingVersion = (defaultText = "7.99.0~2025-10-11"),
|
||||
# Human-readable presentation of the app version.
|
||||
|
||||
minUpgradableAppVersion = 0,
|
||||
|
||||
Executable
+188
@@ -0,0 +1,188 @@
|
||||
#!/bin/bash
|
||||
|
||||
# MongoDB Log Rotation Script for Wekan Snap
|
||||
# This script handles log rotation for MongoDB logs in the Wekan snap environment
|
||||
|
||||
set -e
|
||||
|
||||
# Source settings if available, otherwise use defaults
|
||||
if [ -f "$SNAP/bin/wekan-read-settings" ]; then
|
||||
source $SNAP/bin/wekan-read-settings
|
||||
else
|
||||
# Default values when wekan-read-settings is not available
|
||||
SNAP_COMMON="/var/snap/wekan/common"
|
||||
SNAP_NAME="wekan"
|
||||
fi
|
||||
|
||||
# Configuration
|
||||
MONGODB_LOG="${SNAP_COMMON}/mongodb.log"
|
||||
MAX_SIZE_MB=100
|
||||
KEEP_COPIES=10
|
||||
COMPRESS_LOGS=true
|
||||
|
||||
# Logging functions
|
||||
log_message() {
|
||||
local message="$1"
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
echo "[$timestamp] $message"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
local message="$1"
|
||||
log_message "ERROR: $message"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
local message="$1"
|
||||
log_message "SUCCESS: $message"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
local message="$1"
|
||||
log_message "WARNING: $message"
|
||||
}
|
||||
|
||||
# Check if log file exists and is large enough to rotate
|
||||
check_rotation_needed() {
|
||||
if [ ! -f "$MONGODB_LOG" ]; then
|
||||
log_message "MongoDB log file not found: $MONGODB_LOG"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Get log file size in MB
|
||||
local log_size_mb=$(du -m "$MONGODB_LOG" | cut -f1)
|
||||
|
||||
if [ "$log_size_mb" -lt "$MAX_SIZE_MB" ]; then
|
||||
log_message "MongoDB log size (${log_size_mb}MB) is below rotation threshold (${MAX_SIZE_MB}MB)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_message "MongoDB log size (${log_size_mb}MB) exceeds rotation threshold (${MAX_SIZE_MB}MB)"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Rotate MongoDB log file
|
||||
rotate_log() {
|
||||
local mongodb_log="$1"
|
||||
local max_size_mb="$2"
|
||||
local keep_copies="$3"
|
||||
local compress="$4"
|
||||
|
||||
log_message "Starting MongoDB log rotation"
|
||||
|
||||
# Create rotated log file with timestamp
|
||||
local timestamp=$(date +%Y%m%d-%H%M%S)
|
||||
local rotated_log="${mongodb_log}.${timestamp}"
|
||||
|
||||
# Copy current log to rotated file
|
||||
if cp "$mongodb_log" "$rotated_log"; then
|
||||
log_message "Created rotated log file: $rotated_log"
|
||||
|
||||
# Truncate original log file
|
||||
if > "$mongodb_log"; then
|
||||
log_message "Truncated original log file"
|
||||
else
|
||||
log_error "Failed to truncate original log file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Compress rotated log file if requested
|
||||
if [ "$compress" = "true" ]; then
|
||||
if gzip "$rotated_log"; then
|
||||
log_message "Compressed rotated log file: ${rotated_log}.gz"
|
||||
else
|
||||
log_warning "Failed to compress rotated log file"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Clean up old rotated logs (keep only specified number)
|
||||
local old_logs=$(ls -t "${mongodb_log}".* 2>/dev/null | tail -n +$((keep_copies + 1)))
|
||||
if [ -n "$old_logs" ]; then
|
||||
echo "$old_logs" | xargs rm -f
|
||||
log_message "Cleaned up old rotated log files"
|
||||
fi
|
||||
|
||||
log_success "MongoDB log rotation completed successfully"
|
||||
return 0
|
||||
else
|
||||
log_error "Failed to create rotated log file"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Show log file statistics
|
||||
show_log_stats() {
|
||||
if [ ! -f "$MONGODB_LOG" ]; then
|
||||
log_message "MongoDB log file not found: $MONGODB_LOG"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local log_size_mb=$(du -m "$MONGODB_LOG" | cut -f1)
|
||||
local log_lines=$(wc -l < "$MONGODB_LOG" 2>/dev/null || echo "0")
|
||||
local rotated_count=$(ls -1 "${MONGODB_LOG}".* 2>/dev/null | wc -l)
|
||||
|
||||
log_message "MongoDB Log Statistics:"
|
||||
log_message " Current log size: ${log_size_mb}MB"
|
||||
log_message " Current log lines: ${log_lines}"
|
||||
log_message " Rotated log files: ${rotated_count}"
|
||||
log_message " Rotation threshold: ${MAX_SIZE_MB}MB"
|
||||
log_message " Keep copies: ${KEEP_COPIES}"
|
||||
}
|
||||
|
||||
# Force rotation regardless of size
|
||||
force_rotation() {
|
||||
log_message "Force rotating MongoDB log file"
|
||||
|
||||
if [ ! -f "$MONGODB_LOG" ]; then
|
||||
log_error "MongoDB log file not found: $MONGODB_LOG"
|
||||
return 1
|
||||
fi
|
||||
|
||||
rotate_log "$MONGODB_LOG" "$MAX_SIZE_MB" "$KEEP_COPIES" "$COMPRESS_LOGS"
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
local action="${1:-check}"
|
||||
|
||||
case "$action" in
|
||||
"check")
|
||||
log_message "Checking if MongoDB log rotation is needed"
|
||||
if check_rotation_needed; then
|
||||
log_message "Log rotation is needed"
|
||||
rotate_log "$MONGODB_LOG" "$MAX_SIZE_MB" "$KEEP_COPIES" "$COMPRESS_LOGS"
|
||||
else
|
||||
log_message "Log rotation is not needed"
|
||||
fi
|
||||
;;
|
||||
"force")
|
||||
force_rotation
|
||||
;;
|
||||
"stats")
|
||||
show_log_stats
|
||||
;;
|
||||
"help"|"-h"|"--help")
|
||||
echo "Usage: $0 [check|force|stats|help]"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " check - Check if rotation is needed and rotate if so (default)"
|
||||
echo " force - Force rotation regardless of log size"
|
||||
echo " stats - Show log file statistics"
|
||||
echo " help - Show this help message"
|
||||
echo ""
|
||||
echo "Configuration:"
|
||||
echo " Log file: $MONGODB_LOG"
|
||||
echo " Max size: ${MAX_SIZE_MB}MB"
|
||||
echo " Keep copies: $KEEP_COPIES"
|
||||
echo " Compress: $COMPRESS_LOGS"
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown action: $action"
|
||||
echo "Use '$0 help' for usage information"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
@@ -0,0 +1,175 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Wekan Log Rotation Setup Script
|
||||
# This script sets up log rotation for Wekan snap installation
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
SNAP_NAME="wekan"
|
||||
SNAP_COMMON="/var/snap/${SNAP_NAME}/common"
|
||||
LOGROTATE_DIR="/etc/logrotate.d"
|
||||
WEKAN_LOGROTATE_CONF="${LOGROTATE_DIR}/${SNAP_NAME}"
|
||||
|
||||
# Log file paths
|
||||
MONGODB_LOG="${SNAP_COMMON}/mongodb.log"
|
||||
WEKAN_APP_LOG="${SNAP_COMMON}/wekan-app.log"
|
||||
WEKAN_ERROR_LOG="${SNAP_COMMON}/wekan-error.log"
|
||||
|
||||
# Log rotation configuration
|
||||
ROTATE_SIZE="100M"
|
||||
KEEP_DAYS="30"
|
||||
KEEP_COPIES="10"
|
||||
|
||||
log_message() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $1" >&2
|
||||
}
|
||||
|
||||
# Check if running as root
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
log_error "This script must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if snap is installed
|
||||
if ! snap list | grep -q "^${SNAP_NAME} "; then
|
||||
log_error "Snap ${SNAP_NAME} is not installed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_message "Setting up log rotation for Wekan snap..."
|
||||
|
||||
# Create logrotate configuration
|
||||
cat > "${WEKAN_LOGROTATE_CONF}" << EOF
|
||||
# Wekan Snap Log Rotation Configuration
|
||||
# Generated by wekan logrotate-setup script
|
||||
|
||||
# MongoDB logs
|
||||
${MONGODB_LOG} {
|
||||
daily
|
||||
missingok
|
||||
rotate ${KEEP_COPIES}
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 644 root root
|
||||
postrotate
|
||||
# Send SIGUSR1 to MongoDB to reopen log file
|
||||
if [ -f "${SNAP_COMMON}/mongodb.pid" ]; then
|
||||
kill -USR1 \$(cat "${SNAP_COMMON}/mongodb.pid") 2>/dev/null || true
|
||||
fi
|
||||
# Alternative: restart MongoDB service if PID file doesn't exist
|
||||
if [ ! -f "${SNAP_COMMON}/mongodb.pid" ]; then
|
||||
snap restart ${SNAP_NAME}.mongodb 2>/dev/null || true
|
||||
fi
|
||||
endscript
|
||||
}
|
||||
|
||||
# Wekan application logs
|
||||
${WEKAN_APP_LOG} {
|
||||
daily
|
||||
missingok
|
||||
rotate ${KEEP_COPIES}
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 644 root root
|
||||
postrotate
|
||||
# Send SIGUSR1 to Wekan application to reopen log file
|
||||
if [ -f "${SNAP_COMMON}/wekan.pid" ]; then
|
||||
kill -USR1 \$(cat "${SNAP_COMMON}/wekan.pid") 2>/dev/null || true
|
||||
fi
|
||||
# Alternative: restart Wekan service if PID file doesn't exist
|
||||
if [ ! -f "${SNAP_COMMON}/wekan.pid" ]; then
|
||||
snap restart ${SNAP_NAME}.wekan 2>/dev/null || true
|
||||
fi
|
||||
endscript
|
||||
}
|
||||
|
||||
# Wekan error logs
|
||||
${WEKAN_ERROR_LOG} {
|
||||
daily
|
||||
missingok
|
||||
rotate ${KEEP_COPIES}
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 644 root root
|
||||
postrotate
|
||||
# Send SIGUSR1 to Wekan application to reopen log file
|
||||
if [ -f "${SNAP_COMMON}/wekan.pid" ]; then
|
||||
kill -USR1 \$(cat "${SNAP_COMMON}/wekan.pid") 2>/dev/null || true
|
||||
fi
|
||||
# Alternative: restart Wekan service if PID file doesn't exist
|
||||
if [ ! -f "${SNAP_COMMON}/wekan.pid" ]; then
|
||||
snap restart ${SNAP_NAME}.wekan 2>/dev/null || true
|
||||
fi
|
||||
endscript
|
||||
}
|
||||
|
||||
# Size-based rotation for large log files
|
||||
${SNAP_COMMON}/*.log {
|
||||
size ${ROTATE_SIZE}
|
||||
missingok
|
||||
rotate ${KEEP_COPIES}
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 644 root root
|
||||
sharedscripts
|
||||
postrotate
|
||||
# Generic postrotate for all log files
|
||||
# Try to signal processes to reopen log files
|
||||
for pidfile in "${SNAP_COMMON}"/*.pid; do
|
||||
if [ -f "\$pidfile" ]; then
|
||||
kill -USR1 \$(cat "\$pidfile") 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
# Restart services if no PID files found
|
||||
if [ ! -f "${SNAP_COMMON}/mongodb.pid" ] && [ ! -f "${SNAP_COMMON}/wekan.pid" ]; then
|
||||
snap restart ${SNAP_NAME}.mongodb 2>/dev/null || true
|
||||
snap restart ${SNAP_NAME}.wekan 2>/dev/null || true
|
||||
fi
|
||||
endscript
|
||||
}
|
||||
EOF
|
||||
|
||||
log_message "Created logrotate configuration: ${WEKAN_LOGROTATE_CONF}"
|
||||
|
||||
# Test logrotate configuration
|
||||
if logrotate -d "${WEKAN_LOGROTATE_CONF}" >/dev/null 2>&1; then
|
||||
log_message "Logrotate configuration test passed"
|
||||
else
|
||||
log_error "Logrotate configuration test failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create log directory if it doesn't exist
|
||||
mkdir -p "${SNAP_COMMON}"
|
||||
|
||||
# Set proper permissions
|
||||
chown root:root "${WEKAN_LOGROTATE_CONF}"
|
||||
chmod 644 "${WEKAN_LOGROTATE_CONF}"
|
||||
|
||||
# Create initial log files if they don't exist
|
||||
touch "${MONGODB_LOG}" "${WEKAN_APP_LOG}" "${WEKAN_ERROR_LOG}"
|
||||
chown root:root "${SNAP_COMMON}"/*.log
|
||||
chmod 644 "${SNAP_COMMON}"/*.log
|
||||
|
||||
log_message "Log rotation setup completed successfully"
|
||||
log_message "Configuration file: ${WEKAN_LOGROTATE_CONF}"
|
||||
log_message "Log files will be rotated daily and when they exceed ${ROTATE_SIZE}"
|
||||
log_message "Log files will be kept for ${KEEP_DAYS} days (${KEEP_COPIES} copies)"
|
||||
log_message "To test log rotation manually: sudo logrotate -f ${WEKAN_LOGROTATE_CONF}"
|
||||
log_message "To view logrotate status: sudo logrotate -d ${WEKAN_LOGROTATE_CONF}"
|
||||
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo "1. Configure MongoDB to log to file: sudo snap set ${SNAP_NAME} mongo-log-destination=snapcommon"
|
||||
echo "2. Configure Wekan to log to file (if not already done)"
|
||||
echo "3. Test log rotation: sudo logrotate -f ${WEKAN_LOGROTATE_CONF}"
|
||||
echo "4. Monitor log files: ls -la ${SNAP_COMMON}/*.log*"
|
||||
@@ -77,6 +77,11 @@ log_success() {
|
||||
log_message "SUCCESS: $message"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
local message="$1"
|
||||
log_message "WARNING: $message"
|
||||
}
|
||||
|
||||
# Disk space checking functions
|
||||
check_disk_space() {
|
||||
local required_space_gb="$1"
|
||||
@@ -222,6 +227,28 @@ check_migration_needed() {
|
||||
return 1
|
||||
}
|
||||
|
||||
# Display MongoDB log content for debugging
|
||||
display_mongodb_log_content() {
|
||||
local mongodb_log="${SNAP_COMMON}/mongodb.log"
|
||||
|
||||
if [ ! -f "$mongodb_log" ]; then
|
||||
log_message "MongoDB log file not found: $mongodb_log"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_message "MongoDB log file content (last 50 lines):"
|
||||
if [ -r "$mongodb_log" ]; then
|
||||
tail -50 "$mongodb_log" | while read -r line; do
|
||||
log_message "LOG: $line"
|
||||
done
|
||||
else
|
||||
log_message "MongoDB log file not readable, trying with sudo"
|
||||
sudo tail -50 "$mongodb_log" 2>/dev/null | while read -r line; do
|
||||
log_message "LOG: $line"
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
# Detect if MongoDB upgrade is needed by checking log file
|
||||
detect_mongodb_upgrade_needed() {
|
||||
local mongodb_log="${SNAP_COMMON}/mongodb.log"
|
||||
@@ -232,20 +259,168 @@ detect_mongodb_upgrade_needed() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check for the specific error message indicating upgrade is needed
|
||||
if grep -q "This version of MongoDB is too recent to start up on the existing data files. Try MongoDB 4.2 or earlier." "$mongodb_log"; then
|
||||
log_message "MongoDB upgrade needed detected in log file"
|
||||
# Display log content for debugging
|
||||
display_mongodb_log_content
|
||||
|
||||
# Check file permissions and try to read with appropriate method
|
||||
if [ ! -r "$mongodb_log" ]; then
|
||||
log_message "MongoDB log file not readable, trying with sudo"
|
||||
# Try to read with sudo if not readable
|
||||
if ! sudo grep -q "too recent to start up on the existing data files" "$mongodb_log" 2>/dev/null; then
|
||||
log_message "No MongoDB upgrade needed detected in log file (via sudo)"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
# Check for various error messages that indicate upgrade is needed
|
||||
# The exact message may vary between MongoDB versions
|
||||
local upgrade_patterns=(
|
||||
"This version of MongoDB is too recent to start up on the existing data files"
|
||||
"too recent to start up on the existing data files"
|
||||
"Try MongoDB 4.2 or earlier"
|
||||
"unsupported format version"
|
||||
"data files are incompatible"
|
||||
"database files are incompatible"
|
||||
"version too new"
|
||||
"version too recent"
|
||||
)
|
||||
|
||||
local found_upgrade_needed=false
|
||||
for pattern in "${upgrade_patterns[@]}"; do
|
||||
if grep -q "$pattern" "$mongodb_log" 2>/dev/null; then
|
||||
log_message "Found upgrade pattern in log: '$pattern'"
|
||||
found_upgrade_needed=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$found_upgrade_needed" = false ]; then
|
||||
log_message "No MongoDB upgrade needed detected in log file"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
log_message "MongoDB upgrade needed detected in log file"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Log rotation function for MongoDB logs
|
||||
rotate_mongodb_logs() {
|
||||
local mongodb_log="${SNAP_COMMON}/mongodb.log"
|
||||
local max_size_mb=100
|
||||
local keep_copies=10
|
||||
|
||||
# Check if log file exists and is large enough to rotate
|
||||
if [ ! -f "$mongodb_log" ]; then
|
||||
log_message "MongoDB log file not found, skipping rotation"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Also check for similar error messages that might indicate upgrade issues
|
||||
if grep -q "too recent to start up on the existing data files" "$mongodb_log"; then
|
||||
log_message "MongoDB upgrade needed detected in log file (alternative message)"
|
||||
# Get log file size in MB
|
||||
local log_size_mb=$(du -m "$mongodb_log" | cut -f1)
|
||||
|
||||
if [ "$log_size_mb" -lt "$max_size_mb" ]; then
|
||||
log_message "MongoDB log size (${log_size_mb}MB) is below rotation threshold (${max_size_mb}MB)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_message "No MongoDB upgrade needed detected in log file"
|
||||
return 1
|
||||
log_message "Rotating MongoDB log file (size: ${log_size_mb}MB)"
|
||||
|
||||
# Create rotated log file with timestamp
|
||||
local timestamp=$(date +%Y%m%d-%H%M%S)
|
||||
local rotated_log="${mongodb_log}.${timestamp}"
|
||||
|
||||
# Copy current log to rotated file
|
||||
if cp "$mongodb_log" "$rotated_log"; then
|
||||
log_message "Created rotated log file: $rotated_log"
|
||||
|
||||
# Truncate original log file
|
||||
if > "$mongodb_log"; then
|
||||
log_message "Truncated original log file"
|
||||
else
|
||||
log_error "Failed to truncate original log file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Compress rotated log file
|
||||
if gzip "$rotated_log"; then
|
||||
log_message "Compressed rotated log file: ${rotated_log}.gz"
|
||||
else
|
||||
log_warning "Failed to compress rotated log file"
|
||||
fi
|
||||
|
||||
# Clean up old rotated logs (keep only specified number)
|
||||
local old_logs=$(ls -t "${mongodb_log}".* 2>/dev/null | tail -n +$((keep_copies + 1)))
|
||||
if [ -n "$old_logs" ]; then
|
||||
echo "$old_logs" | xargs rm -f
|
||||
log_message "Cleaned up old rotated log files"
|
||||
fi
|
||||
|
||||
log_success "MongoDB log rotation completed successfully"
|
||||
return 0
|
||||
else
|
||||
log_error "Failed to create rotated log file"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Enhanced log rotation function for migration logs
|
||||
rotate_migration_logs() {
|
||||
local migration_log="${SNAP_COMMON}/mongodb-migration-log.txt"
|
||||
local max_size_mb=50
|
||||
local keep_copies=5
|
||||
|
||||
# Check if migration log file exists and is large enough to rotate
|
||||
if [ ! -f "$migration_log" ]; then
|
||||
log_message "Migration log file not found, skipping rotation"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Get log file size in MB
|
||||
local log_size_mb=$(du -m "$migration_log" | cut -f1)
|
||||
|
||||
if [ "$log_size_mb" -lt "$max_size_mb" ]; then
|
||||
log_message "Migration log size (${log_size_mb}MB) is below rotation threshold (${max_size_mb}MB)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_message "Rotating migration log file (size: ${log_size_mb}MB)"
|
||||
|
||||
# Create rotated log file with timestamp
|
||||
local timestamp=$(date +%Y%m%d-%H%M%S)
|
||||
local rotated_log="${migration_log}.${timestamp}"
|
||||
|
||||
# Copy current log to rotated file
|
||||
if cp "$migration_log" "$rotated_log"; then
|
||||
log_message "Created rotated migration log file: $rotated_log"
|
||||
|
||||
# Truncate original log file
|
||||
if > "$migration_log"; then
|
||||
log_message "Truncated original migration log file"
|
||||
else
|
||||
log_error "Failed to truncate original migration log file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Compress rotated log file
|
||||
if gzip "$rotated_log"; then
|
||||
log_message "Compressed rotated migration log file: ${rotated_log}.gz"
|
||||
else
|
||||
log_warning "Failed to compress rotated migration log file"
|
||||
fi
|
||||
|
||||
# Clean up old rotated logs (keep only specified number)
|
||||
local old_logs=$(ls -t "${migration_log}".* 2>/dev/null | tail -n +$((keep_copies + 1)))
|
||||
if [ -n "$old_logs" ]; then
|
||||
echo "$old_logs" | xargs rm -f
|
||||
log_message "Cleaned up old rotated migration log files"
|
||||
fi
|
||||
|
||||
log_success "Migration log rotation completed successfully"
|
||||
return 0
|
||||
else
|
||||
log_error "Failed to create rotated migration log file"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Reset MONGO_LOG_DESTINATION to devnull after successful migration
|
||||
@@ -493,6 +668,18 @@ perform_migration() {
|
||||
|
||||
log_message "Starting MongoDB migration from version 3 to 7"
|
||||
|
||||
# Rotate MongoDB logs before migration if needed
|
||||
log_message "Checking if MongoDB log rotation is needed"
|
||||
if ! rotate_mongodb_logs; then
|
||||
log_warning "MongoDB log rotation failed, continuing with migration"
|
||||
fi
|
||||
|
||||
# Rotate migration logs before migration if needed
|
||||
log_message "Checking if migration log rotation is needed"
|
||||
if ! rotate_migration_logs; then
|
||||
log_warning "Migration log rotation failed, continuing with migration"
|
||||
fi
|
||||
|
||||
# Create backup before migration
|
||||
log_message "Creating backup before migration"
|
||||
if ! create_backup; then
|
||||
@@ -572,6 +759,18 @@ EOF
|
||||
|
||||
log_success "MongoDB migration completed successfully"
|
||||
|
||||
# Rotate MongoDB logs after successful migration
|
||||
log_message "Rotating MongoDB logs after successful migration"
|
||||
if ! rotate_mongodb_logs; then
|
||||
log_warning "MongoDB log rotation after migration failed"
|
||||
fi
|
||||
|
||||
# Rotate migration logs after successful migration
|
||||
log_message "Rotating migration logs after successful migration"
|
||||
if ! rotate_migration_logs; then
|
||||
log_warning "Migration log rotation after migration failed"
|
||||
fi
|
||||
|
||||
# Reset MONGO_LOG_DESTINATION to devnull after successful migration
|
||||
reset_mongo_log_destination
|
||||
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
name: wekan
|
||||
version: '7.98'
|
||||
version: '7.99'
|
||||
base: core24
|
||||
summary: Open Source kanban
|
||||
description: |
|
||||
@@ -203,9 +203,9 @@ parts:
|
||||
# Cleanup
|
||||
mkdir .build
|
||||
cd .build
|
||||
wget https://github.com/wekan/wekan/releases/download/v7.98/wekan-7.98-amd64.zip
|
||||
unzip wekan-7.98-amd64.zip
|
||||
rm wekan-7.98-amd64.zip
|
||||
wget https://github.com/wekan/wekan/releases/download/v7.99/wekan-7.99-amd64.zip
|
||||
unzip wekan-7.99-amd64.zip
|
||||
rm wekan-7.99-amd64.zip
|
||||
cd ..
|
||||
##cd .build/bundle
|
||||
##find . -type d -name '*-garbage*' | xargs rm -rf
|
||||
|
||||
Reference in new issue
Block a user