feat: shared call to createPatch

This commit is contained in:
Eli Bosley
2025-02-04 11:50:55 -05:00
parent c00789865c
commit 073a51572a
11 changed files with 81 additions and 76 deletions

View File

@@ -3,7 +3,7 @@ import { constants } from 'fs';
import { access, readFile, unlink, writeFile } from 'fs/promises'; import { access, readFile, unlink, writeFile } from 'fs/promises';
import { basename, dirname, join } from 'path'; import { basename, dirname, join } from 'path';
import { applyPatch, parsePatch, reversePatch } from 'diff'; import { applyPatch, createPatch, parsePatch, reversePatch } from 'diff';
export interface ShouldApplyWithReason { export interface ShouldApplyWithReason {
shouldApply: boolean; shouldApply: boolean;
@@ -219,4 +219,15 @@ export abstract class FileModification {
}; };
} }
} }
async createPatchWithDiff(
filePath: string,
originalContent: string,
newContent: string
): Promise<string> {
const patch = createPatch(filePath, originalContent, newContent, 'original', 'modified', {
context: 5,
});
return patch;
}
} }

View File

@@ -15,12 +15,23 @@ export default class AuthRequestModification extends FileModification {
'/usr/local/emhttp/plugins/dynamix.my.servers/unraid-components/_nuxt/' as const; '/usr/local/emhttp/plugins/dynamix.my.servers/unraid-components/_nuxt/' as const;
id: string = 'auth-request'; id: string = 'auth-request';
/**
* Get the list of .js files in the given directory
* @param dir - The directory to search for .js files
* @returns The list of .js files in the given directory
*/
private getJsFiles = async (dir: string) => { private getJsFiles = async (dir: string) => {
const { glob } = await import('glob'); const { glob } = await import('glob');
const files = await glob(join(dir, '**/*.js')); const files = await glob(join(dir, '**/*.js'));
const baseDir = '/usr/local/emhttp'; // TODO: Make this configurable const baseDir = '/usr/local/emhttp';
return files.map((file) => (file.startsWith(baseDir) ? file.slice(baseDir.length) : file)); return files.map((file) => (file.startsWith(baseDir) ? file.slice(baseDir.length) : file));
}; };
/**
* Generate a patch for the auth-request.php file
* @param overridePath - The path to override the default file path
* @returns The patch for the auth-request.php file
*/
protected async generatePatch(overridePath?: string): Promise<string> { protected async generatePatch(overridePath?: string): Promise<string> {
const jsFiles = await this.getJsFiles(this.webComponentsDirectory); const jsFiles = await this.getJsFiles(this.webComponentsDirectory);
this.logger.debug(`Found ${jsFiles.length} .js files in ${this.webComponentsDirectory}`); this.logger.debug(`Found ${jsFiles.length} .js files in ${this.webComponentsDirectory}`);
@@ -42,19 +53,7 @@ export default class AuthRequestModification extends FileModification {
// Create new content by finding the array declaration and adding our files after it // Create new content by finding the array declaration and adding our files after it
const newContent = fileContent.replace(/(\$arrWhitelist\s*=\s*\[)/, `$1\n${filesToAddString}`); const newContent = fileContent.replace(/(\$arrWhitelist\s*=\s*\[)/, `$1\n${filesToAddString}`);
// Generate and return patch return this.createPatchWithDiff(overridePath ?? this.filePath, fileContent, newContent);
const patch = createPatch(
overridePath ?? this.filePath,
fileContent,
newContent,
undefined,
undefined,
{
context: 3,
}
);
return patch;
} }
async shouldApply(): Promise<ShouldApplyWithReason> { async shouldApply(): Promise<ShouldApplyWithReason> {

View File

@@ -46,18 +46,7 @@ export default class DefaultPageLayoutModification extends FileModification {
const newContent = this.applyToSource(fileContent); const newContent = this.applyToSource(fileContent);
const patch = createPatch( return this.createPatchWithDiff(overridePath ?? this.filePath, fileContent, newContent);
overridePath ?? this.filePath,
fileContent,
newContent,
undefined,
undefined,
{
context: 2,
}
);
return patch;
} }
async shouldApply(): Promise<ShouldApplyWithReason> { async shouldApply(): Promise<ShouldApplyWithReason> {

View File

@@ -35,21 +35,11 @@ export class LogRotateModification extends FileModification {
? await readFile(this.filePath, 'utf8') ? await readFile(this.filePath, 'utf8')
: ''; : '';
const patch = createPatch( return this.createPatchWithDiff(
overridePath ?? this.filePath, overridePath ?? this.filePath,
currentContent, currentContent,
this.logRotateConfig, this.logRotateConfig
undefined,
undefined,
{
context: 3,
}
); );
// After applying patch, ensure file permissions are correct
await execa('chown', ['root:root', this.filePath]).catch((err) => this.logger.error(err));
return patch;
} }
async shouldApply(): Promise<ShouldApplyWithReason> { async shouldApply(): Promise<ShouldApplyWithReason> {

View File

@@ -17,18 +17,7 @@ export default class NotificationsPageModification extends FileModification {
const newContent = NotificationsPageModification.applyToSource(fileContent); const newContent = NotificationsPageModification.applyToSource(fileContent);
const patch = createPatch( return this.createPatchWithDiff(overridePath ?? this.filePath, fileContent, newContent);
overridePath ?? this.filePath,
fileContent,
newContent,
undefined,
undefined,
{
context: 3,
}
);
return patch;
} }
async shouldApply(): Promise<ShouldApplyWithReason> { async shouldApply(): Promise<ShouldApplyWithReason> {

View File

@@ -1,8 +1,10 @@
Index: /usr/local/emhttp/auth-request.php Index: /usr/local/emhttp/auth-request.php
=================================================================== ===================================================================
--- /usr/local/emhttp/auth-request.php --- /usr/local/emhttp/auth-request.php original
+++ /usr/local/emhttp/auth-request.php +++ /usr/local/emhttp/auth-request.php modified
@@ -15,6 +15,7 @@ @@ -13,10 +13,11 @@
}
session_write_close();
} }
$arrWhitelist = [ $arrWhitelist = [
@@ -10,3 +12,5 @@ Index: /usr/local/emhttp/auth-request.php
'/webGui/styles/clear-sans-bold-italic.eot', '/webGui/styles/clear-sans-bold-italic.eot',
'/webGui/styles/clear-sans-bold-italic.woff', '/webGui/styles/clear-sans-bold-italic.woff',
'/webGui/styles/clear-sans-bold-italic.ttf', '/webGui/styles/clear-sans-bold-italic.ttf',
'/webGui/styles/clear-sans-bold-italic.svg',
'/webGui/styles/clear-sans-bold.eot',

View File

@@ -1,8 +1,11 @@
Index: /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php Index: /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php
=================================================================== ===================================================================
--- /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php --- /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php original
+++ /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php +++ /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php modified
@@ -557,14 +557,5 @@ @@ -554,20 +554,11 @@
return 'three';
}
function openNotifier() {
$.post('/webGui/include/Notify.php',{cmd:'get',csrf_token:csrf_token},function(msg) { $.post('/webGui/include/Notify.php',{cmd:'get',csrf_token:csrf_token},function(msg) {
$.each($.parseJSON(msg), function(i, notify){ $.each($.parseJSON(msg), function(i, notify){
- $.jGrowl(notify.subject+'<br>'+notify.description,{ - $.jGrowl(notify.subject+'<br>'+notify.description,{
@@ -18,7 +21,13 @@ Index: /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php
+ +
}); });
}); });
@@ -698,6 +689,6 @@ }
function closeNotifier() {
$.post('/webGui/include/Notify.php',{cmd:'get',csrf_token:csrf_token},function(msg) {
@@ -695,12 +686,12 @@
}
// create list of nchan scripts to be started
if (isset($button['Nchan'])) nchan_merge($button['root'], $button['Nchan']);
} }
-echo "<div class='nav-user show'><a id='board' href='#' class='hand'><b id='bell' class='icon-u-bell system'></b></a></div>"; -echo "<div class='nav-user show'><a id='board' href='#' class='hand'><b id='bell' class='icon-u-bell system'></b></a></div>";
@@ -26,7 +35,13 @@ Index: /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php
+ +
if ($themes2) echo "</div>"; if ($themes2) echo "</div>";
echo "</div></div>"; echo "</div></div>";
@@ -904,20 +895,12 @@ foreach ($buttons as $button) {
annotate($button['file']);
// include page specific stylesheets (if existing)
@@ -901,26 +892,18 @@
case 'warning': bell2++; break;
case 'normal' : bell3++; break;
}
<?if ($notify['display']==0):?> <?if ($notify['display']==0):?>
if (notify.show) { if (notify.show) {
- $.jGrowl(notify.subject+'<br>'+notify.description,{ - $.jGrowl(notify.subject+'<br>'+notify.description,{
@@ -52,7 +67,13 @@ Index: /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php
+ +
break; break;
} }
@@ -1222,4 +1205,5 @@ });
var nchan_plugins = new NchanSubscriber('/sub/plugins',{subscriber:'websocket'});
@@ -1219,7 +1202,8 @@
});
}
}
}); });
</script> </script>
+<unraid-toaster rich-colors close-button position="<?= ($notify['position'] === 'center') ? 'top-center' : $notify['position'] ?>"></unraid-toaster> +<unraid-toaster rich-colors close-button position="<?= ($notify['position'] === 'center') ? 'top-center' : $notify['position'] ?>"></unraid-toaster>

View File

@@ -1,7 +1,7 @@
Index: /etc/logrotate.d/unraid-api Index: /etc/logrotate.d/unraid-api
=================================================================== ===================================================================
--- /etc/logrotate.d/unraid-api --- /etc/logrotate.d/unraid-api original
+++ /etc/logrotate.d/unraid-api +++ /etc/logrotate.d/unraid-api modified
@@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
+ +
+/var/log/unraid-api/*.log { +/var/log/unraid-api/*.log {

View File

@@ -1,8 +1,10 @@
Index: /usr/local/emhttp/plugins/dynamix/Notifications.page Index: /usr/local/emhttp/plugins/dynamix/Notifications.page
=================================================================== ===================================================================
--- /usr/local/emhttp/plugins/dynamix/Notifications.page --- /usr/local/emhttp/plugins/dynamix/Notifications.page original
+++ /usr/local/emhttp/plugins/dynamix/Notifications.page +++ /usr/local/emhttp/plugins/dynamix/Notifications.page modified
@@ -135,23 +135,7 @@ @@ -133,27 +133,11 @@
_(Auto-close)_ (_(seconds)_):
: <input type="number" name="life" class="a" min="0" max="60" value="<?=$notify['life']?>"> _(a value of zero means no automatic closure)_
:notifications_auto_close_help: :notifications_auto_close_help:
@@ -26,3 +28,5 @@ Index: /usr/local/emhttp/plugins/dynamix/Notifications.page
_(Store notifications to flash)_: _(Store notifications to flash)_:
: <select name="path" class="a"> : <select name="path" class="a">
<?=mk_option($notify['path'], "/tmp/notifications", _("No"))?> <?=mk_option($notify['path'], "/tmp/notifications", _("No"))?>
<?=mk_option($notify['path'], "/boot/config/plugins/dynamix/notifications", _("Yes"))?>
</select>

View File

@@ -2,7 +2,7 @@ Index: /usr/local/emhttp/plugins/dynamix/include/.login.php
=================================================================== ===================================================================
--- /usr/local/emhttp/plugins/dynamix/include/.login.php original --- /usr/local/emhttp/plugins/dynamix/include/.login.php original
+++ /usr/local/emhttp/plugins/dynamix/include/.login.php modified +++ /usr/local/emhttp/plugins/dynamix/include/.login.php modified
@@ -1,5 +1,33 @@ @@ -1,6 +1,34 @@
<?php <?php
+ +
+ +
@@ -36,7 +36,9 @@ Index: /usr/local/emhttp/plugins/dynamix/include/.login.php
// Only start a session to check if they have a cookie that looks like our session // Only start a session to check if they have a cookie that looks like our session
$server_name = strtok($_SERVER['HTTP_HOST'],":"); $server_name = strtok($_SERVER['HTTP_HOST'],":");
@@ -203,9 +231,9 @@ if (!empty($_COOKIE['unraid_'.md5($server_name)])) {
@@ -202,11 +230,11 @@
if ($failCount == $maxFails) my_logger("Ignoring login attempts for {$username} from {$remote_addr}");
throw new Exception(_('Too many invalid login attempts')); throw new Exception(_('Too many invalid login attempts'));
} }
@@ -47,7 +49,9 @@ Index: /usr/local/emhttp/plugins/dynamix/include/.login.php
// Bail if we need a token but it's invalid // Bail if we need a token but it's invalid
if (isWildcardCert() && $twoFactorRequired && !verifyTwoFactorToken($username, $token)) throw new Exception(_('Invalid 2FA token')); if (isWildcardCert() && $twoFactorRequired && !verifyTwoFactorToken($username, $token)) throw new Exception(_('Invalid 2FA token'));
@@ -537,8 +565,9 @@ // Successful login, start session
@@ -536,10 +564,11 @@
document.body.textContent = '';
document.body.appendChild(errorElement); document.body.appendChild(errorElement);
} }
</script> </script>
@@ -57,3 +61,4 @@ Index: /usr/local/emhttp/plugins/dynamix/include/.login.php
<? if (($twoFactorRequired && !empty($token)) || !$twoFactorRequired) { ?> <? if (($twoFactorRequired && !empty($token)) || !$twoFactorRequired) { ?>
<div class="js-addTimeout hidden"> <div class="js-addTimeout hidden">
<p class="error" style="padding-top:10px;"><?=_('Transparent 2FA Token timed out')?></p> <p class="error" style="padding-top:10px;"><?=_('Transparent 2FA Token timed out')?></p>
<a href="https://forums.unraid.net/my-servers/" class="button button--small" title="<?=_('Go to My Servers Dashboard')?>"><?=_('Go to My Servers Dashboard')?></a>

View File

@@ -64,14 +64,7 @@ function verifyUsernamePasswordAndSSO(string $username, string $password): bool
newContent = newContent.replace(/<\/form>/i, `</form>\n${tagToInject}`); newContent = newContent.replace(/<\/form>/i, `</form>\n${tagToInject}`);
// Create and return the patch // Create and return the patch
const patch = createPatch( return this.createPatchWithDiff(overridePath ?? this.filePath, originalContent, newContent);
overridePath ?? this.filePath,
originalContent,
newContent,
'original',
'modified'
);
return patch;
} }
async shouldApply(): Promise<ShouldApplyWithReason> { async shouldApply(): Promise<ShouldApplyWithReason> {