mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-07-16 18:43:43 +01:00
Merge branch 'master' into dev
This commit is contained in:
@@ -57,44 +57,6 @@ jobs:
|
||||
- name: GitHub Requires at Least One Step for a Job
|
||||
run: exit 0
|
||||
|
||||
analyze:
|
||||
name: Code Scanning
|
||||
needs: start-ci-run-gate
|
||||
if: "!(cancelled() || failure()) && needs.start-ci-run-gate.result == 'success'"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install Node 12.X
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 12.x
|
||||
|
||||
- name: Upgrade NPM
|
||||
run: npm install -g npm
|
||||
|
||||
- name: Checkout (Branch)
|
||||
uses: actions/checkout@v3
|
||||
if: github.event_name == 'push' || github.event_name == 'schedule'
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: Checkout (PR Merge)
|
||||
uses: actions/checkout@v3
|
||||
if: github.event_name != 'push' && github.event_name != 'schedule'
|
||||
with:
|
||||
fetch-depth: 2
|
||||
ref: "refs/pull/${{ github.event.number }}/merge"
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: csharp
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
|
||||
dmapi-build:
|
||||
name: Build DMAPI
|
||||
needs: start-ci-run-gate
|
||||
@@ -114,7 +76,7 @@ jobs:
|
||||
uses: actions/cache@v3
|
||||
id: cache-byond
|
||||
with:
|
||||
path: $HOME/BYOND-${{ env.BYOND_MAJOR }}.${{ env.BYOND_MINOR }}
|
||||
path: ~/BYOND-${{ env.BYOND_MAJOR }}.${{ env.BYOND_MINOR }}
|
||||
key: ${{ env.BYOND_MAJOR }}-${{ env.BYOND_MINOR }}-dmapibyond
|
||||
|
||||
- name: Install BYOND
|
||||
@@ -338,7 +300,7 @@ jobs:
|
||||
uses: actions/cache@v3
|
||||
id: cache-byond
|
||||
with:
|
||||
path: $HOME/BYOND-${{ env.BYOND_MAJOR }}.${{ env.BYOND_MINOR }}
|
||||
path: ~/BYOND-${{ env.BYOND_MAJOR }}.${{ env.BYOND_MINOR }}
|
||||
key: ${{ env.BYOND_MAJOR }}-${{ env.BYOND_MINOR }}-livebyond
|
||||
|
||||
- name: Download BYOND
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
name: 'Code Scanning'
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: 0 23 * * *
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
- master
|
||||
|
||||
concurrency:
|
||||
group: "code-scanning-${{ github.head_ref || github.run_id }}-${{ github.event_name }}"
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Code Scanning
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install Node 12.X
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 12.x
|
||||
|
||||
- name: Upgrade NPM
|
||||
run: npm install -g npm
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: csharp
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
@@ -70,8 +70,7 @@ namespace Tgstation.Server.Host.Components.Byond
|
||||
IOManager.ConcatPath(
|
||||
PathToUserByondFolder,
|
||||
CacheDirectoryName),
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
|
||||
@@ -383,8 +383,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
|
||||
cancellationToken,
|
||||
DefaultIOManager.BlockingTaskCreationOptions,
|
||||
TaskScheduler.Current)
|
||||
.WithToken(cancellationToken)
|
||||
;
|
||||
.WithToken(cancellationToken);
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
@@ -480,8 +479,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
|
||||
},
|
||||
cancellationToken,
|
||||
DefaultIOManager.BlockingTaskCreationOptions,
|
||||
TaskScheduler.Current)
|
||||
;
|
||||
TaskScheduler.Current);
|
||||
await HardDisconnect(cancellationToken);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
|
||||
@@ -145,8 +145,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
job);
|
||||
await remoteDeploymentManager.StageDeployment(
|
||||
newProvider.CompileJob,
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
lock (jobLockCounts)
|
||||
@@ -188,10 +187,8 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
.AsQueryable()
|
||||
.Where(x => x.Job.Instance.Id == metadata.Id)
|
||||
.OrderByDescending(x => x.Job.StoppedAt)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
})
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
});
|
||||
|
||||
if (cj == default(CompileJob))
|
||||
return;
|
||||
@@ -267,8 +264,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
ioManager.ConcatPath(
|
||||
newProvider.Directory,
|
||||
newProvider.DmbName),
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
|
||||
if (!dmbExistsAtRoot)
|
||||
{
|
||||
|
||||
@@ -241,8 +241,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
StartupTimeout = x.StartupTimeout,
|
||||
LogOutput = x.LogOutput,
|
||||
})
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
if (ddSettings == default)
|
||||
throw new JobException(ErrorCode.InstanceMissingDreamDaemonSettings);
|
||||
|
||||
@@ -250,8 +249,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
.DreamMakerSettings
|
||||
.AsQueryable()
|
||||
.Where(x => x.InstanceId == metadata.Id)
|
||||
.FirstAsync(cancellationToken)
|
||||
;
|
||||
.FirstAsync(cancellationToken);
|
||||
if (dreamMakerSettings == default)
|
||||
throw new JobException(ErrorCode.InstanceMissingDreamMakerSettings);
|
||||
|
||||
@@ -267,8 +265,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
PushTestMergeCommits = x.PushTestMergeCommits,
|
||||
PostTestMergeComment = x.PostTestMergeComment,
|
||||
})
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
if (repositorySettings == default)
|
||||
throw new JobException(ErrorCode.InstanceMissingRepositorySettings);
|
||||
|
||||
@@ -291,8 +288,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
.Include(x => x.ActiveTestMerges)
|
||||
.ThenInclude(x => x.TestMerge)
|
||||
.ThenInclude(x => x.MergedBy)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (revInfo == default)
|
||||
{
|
||||
@@ -319,8 +315,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
repo?.Dispose();
|
||||
throw;
|
||||
}
|
||||
})
|
||||
;
|
||||
});
|
||||
|
||||
var likelyPushedTestMergeCommit =
|
||||
repositorySettings.PushTestMergeCommits.Value
|
||||
@@ -336,8 +331,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
progressReporter,
|
||||
averageSpan,
|
||||
likelyPushedTestMergeCommit,
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
|
||||
var activeCompileJob = compileJobConsumer.LatestCompileJob();
|
||||
try
|
||||
@@ -379,8 +373,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
|
||||
compileJob.Job = fullJob;
|
||||
compileJob.RevisionInformation = fullRevInfo;
|
||||
})
|
||||
;
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -447,8 +440,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
StoppedAt = x.Job.StoppedAt,
|
||||
StartedAt = x.Job.StartedAt,
|
||||
})
|
||||
.ToListAsync(cancellationToken)
|
||||
;
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
TimeSpan? averageSpan = null;
|
||||
if (previousCompileJobs.Count != 0)
|
||||
@@ -605,8 +597,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
repoOrigin.ToString(),
|
||||
$"{byondLock.Version.Major}.{byondLock.Version.Minor}",
|
||||
},
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
|
||||
// determine the dme
|
||||
progressReporter.StageName = "Determining .dme";
|
||||
@@ -978,8 +969,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
remoteDeploymentManager.FailDeployment(
|
||||
job,
|
||||
FormatExceptionForUsers(exception),
|
||||
default))
|
||||
;
|
||||
default));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,8 +73,7 @@ namespace Tgstation.Server.Host.Components.Deployment
|
||||
await symlinkFactory.CreateSymbolicLink(
|
||||
ioManager.ResolvePath(baseProvider.Directory),
|
||||
ioManager.ResolvePath(LiveGameDirectory),
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,8 +185,7 @@ namespace Tgstation.Server.Host.Components
|
||||
Configuration.StartAsync(cancellationToken),
|
||||
ByondManager.StartAsync(cancellationToken),
|
||||
Chat.StartAsync(cancellationToken),
|
||||
dmbFactory.StartAsync(cancellationToken))
|
||||
;
|
||||
dmbFactory.StartAsync(cancellationToken));
|
||||
|
||||
// dependent on so many things, its just safer this way
|
||||
await Watchdog.StartAsync(cancellationToken);
|
||||
@@ -310,8 +309,7 @@ namespace Tgstation.Server.Host.Components
|
||||
repositorySettings.AccessUser,
|
||||
repositorySettings.AccessToken,
|
||||
NextProgressReporter("Fetch Origin"),
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
|
||||
var hasDbChanges = false;
|
||||
RevisionInformation currentRevInfo = null;
|
||||
@@ -385,8 +383,7 @@ namespace Tgstation.Server.Host.Components
|
||||
repositorySettings.CommitterName,
|
||||
repositorySettings.CommitterEmail,
|
||||
NextProgressReporter("Merge Origin"),
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
|
||||
var preserveTestMerges = repositorySettings.AutoUpdatesKeepTestMerges.Value;
|
||||
var remoteDeploymentManager = remoteDeploymentManagerFactory.CreateRemoteDeploymentManager(
|
||||
@@ -435,16 +432,14 @@ namespace Tgstation.Server.Host.Components
|
||||
repositorySettings.AccessToken,
|
||||
repositorySettings.UpdateSubmodules.Value,
|
||||
NextProgressReporter(StageName),
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
|
||||
var currentHead = repo.Head;
|
||||
|
||||
currentRevInfo = await databaseContext.RevisionInformations
|
||||
.AsQueryable()
|
||||
.Where(x => x.CommitSha == currentHead && x.Instance.Id == metadata.Id)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (currentHead != startSha && currentRevInfo == default)
|
||||
await UpdateRevInfo(currentHead, true, null);
|
||||
@@ -555,8 +550,7 @@ namespace Tgstation.Server.Host.Components
|
||||
progressReporter,
|
||||
jobCancellationToken);
|
||||
},
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
await jobManager.WaitForJobCompletion(compileProcessJob, null, default, cancellationToken);
|
||||
|
||||
@@ -284,8 +284,7 @@ namespace Tgstation.Server.Host.Components
|
||||
await ioManager.WriteAllBytes(
|
||||
ioManager.ConcatPath(oldPath, InstanceController.InstanceAttachFileName),
|
||||
Array.Empty<byte>(),
|
||||
default)
|
||||
;
|
||||
default);
|
||||
}
|
||||
catch (Exception tripleEx)
|
||||
{
|
||||
|
||||
@@ -66,8 +66,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
var mr = await client
|
||||
.MergeRequests
|
||||
.GetAsync($"{RemoteRepositoryOwner}/{RemoteRepositoryName}", parameters.Number)
|
||||
.WithToken(cancellationToken)
|
||||
;
|
||||
.WithToken(cancellationToken);
|
||||
|
||||
var revisionToUse = parameters.TargetCommitSha == null
|
||||
|| mr.Sha.StartsWith(parameters.TargetCommitSha, StringComparison.OrdinalIgnoreCase)
|
||||
|
||||
@@ -356,8 +356,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
}),
|
||||
cancellationToken,
|
||||
DefaultIOManager.BlockingTaskCreationOptions,
|
||||
TaskScheduler.Current)
|
||||
;
|
||||
TaskScheduler.Current);
|
||||
|
||||
if (updateSubmodules)
|
||||
{
|
||||
@@ -412,8 +411,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
},
|
||||
cancellationToken,
|
||||
DefaultIOManager.BlockingTaskCreationOptions,
|
||||
TaskScheduler.Current)
|
||||
;
|
||||
TaskScheduler.Current);
|
||||
|
||||
if (updateSubmodules)
|
||||
await UpdateSubmodules(
|
||||
@@ -463,8 +461,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
},
|
||||
cancellationToken,
|
||||
DefaultIOManager.BlockingTaskCreationOptions,
|
||||
TaskScheduler.Current)
|
||||
;
|
||||
TaskScheduler.Current);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -485,8 +482,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
await ResetToSha(
|
||||
trackedBranch.Tip.Sha,
|
||||
progressReporter.CreateSection(null, updateSubmodules ? 2.0 / 3 : 1.0),
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
|
||||
if (updateSubmodules)
|
||||
await UpdateSubmodules(
|
||||
@@ -619,8 +615,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
},
|
||||
cancellationToken,
|
||||
DefaultIOManager.BlockingTaskCreationOptions,
|
||||
TaskScheduler.Current)
|
||||
;
|
||||
TaskScheduler.Current);
|
||||
|
||||
if (result.Status == MergeStatus.Conflicts)
|
||||
{
|
||||
@@ -684,8 +679,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
{
|
||||
ioMananger.ResolvePath(),
|
||||
},
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -702,8 +696,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
},
|
||||
cancellationToken,
|
||||
DefaultIOManager.BlockingTaskCreationOptions,
|
||||
TaskScheduler.Current)
|
||||
;
|
||||
TaskScheduler.Current);
|
||||
}
|
||||
|
||||
var remainingProgressFactor = 0.9;
|
||||
@@ -759,8 +752,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
},
|
||||
cancellationToken,
|
||||
DefaultIOManager.BlockingTaskCreationOptions,
|
||||
TaskScheduler.Current)
|
||||
;
|
||||
TaskScheduler.Current);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -1040,8 +1032,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
|
||||
await Task.WhenAll(
|
||||
ioMananger.DeleteDirectory($".git/modules/{submodule.Path}", cancellationToken),
|
||||
ioMananger.DeleteDirectory(submodule.Path, cancellationToken))
|
||||
;
|
||||
ioMananger.DeleteDirectory(submodule.Path, cancellationToken));
|
||||
|
||||
logger.LogTrace("Second update attempt for submodule {submoduleName}...", submodule.Name);
|
||||
try
|
||||
|
||||
@@ -270,8 +270,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
currentModel.CommitterEmail,
|
||||
NextProgressReporter("Sychronize"),
|
||||
true,
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
postUpdateSha = repo.Head;
|
||||
}
|
||||
else
|
||||
@@ -305,8 +304,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
currentModel.AccessToken,
|
||||
updateSubmodules,
|
||||
NextProgressReporter("Checkout"),
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
await CallLoadRevInfo(); // we've either seen origin before or what we're checking out is on origin
|
||||
}
|
||||
else
|
||||
@@ -321,8 +319,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
currentModel.AccessToken,
|
||||
updateSubmodules,
|
||||
NextProgressReporter("Reset to Origin"),
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
await repo.Sychronize(
|
||||
currentModel.AccessUser,
|
||||
currentModel.AccessToken,
|
||||
@@ -330,8 +327,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
currentModel.CommitterEmail,
|
||||
NextProgressReporter("Synchronize"),
|
||||
true,
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
await CallLoadRevInfo();
|
||||
|
||||
// repo head is on origin so force this
|
||||
@@ -545,8 +541,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
currentModel.CommitterEmail,
|
||||
NextProgressReporter("Synchronize"),
|
||||
false,
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
await UpdateRevInfo();
|
||||
}
|
||||
|
||||
|
||||
@@ -444,8 +444,7 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
{
|
||||
var commandResult = await SendCommand(
|
||||
new TopicParameters(port),
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
|
||||
if (commandResult?.ErrorMessage != null)
|
||||
return false;
|
||||
@@ -478,8 +477,7 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
ReattachInformation.RebootState = newRebootState;
|
||||
var result = await SendCommand(
|
||||
new TopicParameters(newRebootState),
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
|
||||
return result?.ErrorMessage == null;
|
||||
}
|
||||
|
||||
@@ -140,8 +140,7 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
.AsQueryable()
|
||||
.Where(x => x.Id == metadata.Id)
|
||||
.Select(x => x.DreamDaemonSettings.TopicRequestTimeout)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (timeoutMilliseconds == default)
|
||||
{
|
||||
@@ -238,8 +237,7 @@ namespace Tgstation.Server.Host.Components.Session
|
||||
|
||||
if (instant)
|
||||
await baseQuery
|
||||
.DeleteAsync(cancellationToken)
|
||||
;
|
||||
.DeleteAsync(cancellationToken);
|
||||
else
|
||||
{
|
||||
var results = await baseQuery.ToListAsync(cancellationToken);
|
||||
|
||||
@@ -652,8 +652,7 @@ namespace Tgstation.Server.Host.Components.StaticFiles
|
||||
await Task.WhenAll(
|
||||
ioManager.CreateDirectory(CodeModificationsSubdirectory, cancellationToken),
|
||||
ioManager.CreateDirectory(EventScriptsSubdirectory, cancellationToken),
|
||||
ValidateStaticFolder())
|
||||
;
|
||||
ValidateStaticFolder());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -102,8 +102,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
|
||||
await GameIOManager.MoveDirectory(
|
||||
ActiveSwappable.CompileJob.DirectoryName.ToString(),
|
||||
ActiveSwappable.Directory,
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
|
||||
hardLinkedDmb = ActiveSwappable;
|
||||
}
|
||||
@@ -131,8 +130,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
|
||||
await GameIOManager.MoveDirectory(
|
||||
hardLink,
|
||||
originalPosition,
|
||||
default)
|
||||
;
|
||||
default);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -465,8 +465,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
|
||||
var notification = new EventNotification(eventType, parameters);
|
||||
var result = await activeServer.SendCommand(
|
||||
new TopicParameters(notification),
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
|
||||
HandleChatResponses(result);
|
||||
}
|
||||
|
||||
@@ -122,8 +122,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
await StatusCode(
|
||||
HttpStatusCode.UpgradeRequired,
|
||||
new ErrorMessageResponse(ErrorCode.ApiMismatch))
|
||||
.ExecuteResultAsync(context)
|
||||
;
|
||||
.ExecuteResultAsync(context);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -139,8 +138,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
if (requireHeaders)
|
||||
{
|
||||
await HeadersIssue(false)
|
||||
.ExecuteResultAsync(context)
|
||||
;
|
||||
.ExecuteResultAsync(context);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -221,8 +219,13 @@ namespace Tgstation.Server.Host.Controllers
|
||||
/// <summary>
|
||||
/// Generic 501 response.
|
||||
/// </summary>
|
||||
/// <param name="ex">The <see cref="NotImplementedException"/> that was thrown.</param>
|
||||
/// <returns>An <see cref="ObjectResult"/> with <see cref="HttpStatusCode.NotImplemented"/>.</returns>
|
||||
protected ObjectResult RequiresPosixSystemIdentity() => StatusCode(HttpStatusCode.NotImplemented, new ErrorMessageResponse(ErrorCode.RequiresPosixSystemIdentity));
|
||||
protected ObjectResult RequiresPosixSystemIdentity(NotImplementedException ex)
|
||||
{
|
||||
Logger.LogTrace(ex, "System identities not implemented!");
|
||||
return StatusCode(HttpStatusCode.NotImplemented, new ErrorMessageResponse(ErrorCode.RequiresPosixSystemIdentity));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Strongly type calls to <see cref="ControllerBase.StatusCode(int)"/>.
|
||||
@@ -395,8 +398,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
{
|
||||
totalResults = await paginationResult.Results.CountAsync(cancellationToken);
|
||||
pagedResults = await queriedResults
|
||||
.ToListAsync(cancellationToken)
|
||||
;
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -188,8 +188,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.ChatBots
|
||||
.AsQueryable()
|
||||
.Where(x => x.Id == id)
|
||||
.DeleteAsync(cancellationToken))
|
||||
;
|
||||
.DeleteAsync(cancellationToken));
|
||||
return null;
|
||||
})
|
||||
|
||||
@@ -364,8 +363,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
await chat.ChangeChannels(current.Id.Value, current.Channels, cancellationToken);
|
||||
|
||||
return null;
|
||||
})
|
||||
;
|
||||
});
|
||||
if (earlyOut != null)
|
||||
return earlyOut;
|
||||
|
||||
|
||||
@@ -84,12 +84,10 @@ namespace Tgstation.Server.Host.Controllers
|
||||
model.Path,
|
||||
systemIdentity,
|
||||
model.LastReadHash,
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
|
||||
return model.LastReadHash == null ? Accepted(newFile) : Json(newFile);
|
||||
})
|
||||
;
|
||||
});
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
@@ -99,9 +97,9 @@ namespace Tgstation.Server.Host.Controllers
|
||||
AdditionalData = e.Message,
|
||||
});
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
catch (NotImplementedException ex)
|
||||
{
|
||||
return RequiresPosixSystemIdentity();
|
||||
return RequiresPosixSystemIdentity(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,14 +127,12 @@ namespace Tgstation.Server.Host.Controllers
|
||||
{
|
||||
var result = await instance
|
||||
.Configuration
|
||||
.Read(filePath, systemIdentity, cancellationToken)
|
||||
;
|
||||
.Read(filePath, systemIdentity, cancellationToken);
|
||||
if (result == null)
|
||||
return Gone();
|
||||
|
||||
return Json(result);
|
||||
})
|
||||
;
|
||||
});
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
@@ -146,9 +142,9 @@ namespace Tgstation.Server.Host.Controllers
|
||||
AdditionalData = e.Message,
|
||||
});
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
catch (NotImplementedException ex)
|
||||
{
|
||||
return RequiresPosixSystemIdentity();
|
||||
return RequiresPosixSystemIdentity(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,8 +179,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
{
|
||||
var result = await instance
|
||||
.Configuration
|
||||
.ListDirectory(directoryPath, systemIdentity, cancellationToken)
|
||||
;
|
||||
.ListDirectory(directoryPath, systemIdentity, cancellationToken);
|
||||
if (result == null)
|
||||
return new PaginatableResult<ConfigurationFileResponse>(Gone());
|
||||
|
||||
@@ -193,10 +188,10 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.AsQueryable()
|
||||
.OrderBy(x => x.Path));
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
catch (NotImplementedException ex)
|
||||
{
|
||||
return new PaginatableResult<ConfigurationFileResponse>(
|
||||
RequiresPosixSystemIdentity());
|
||||
RequiresPosixSystemIdentity(ex));
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
@@ -257,8 +252,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.Configuration
|
||||
.CreateDirectory(model.Path, systemIdentity, cancellationToken)
|
||||
? Json(resultModel)
|
||||
: Created(resultModel))
|
||||
;
|
||||
: Created(resultModel));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
@@ -268,9 +262,9 @@ namespace Tgstation.Server.Host.Controllers
|
||||
Message = e.Message,
|
||||
});
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
catch (NotImplementedException ex)
|
||||
{
|
||||
return RequiresPosixSystemIdentity();
|
||||
return RequiresPosixSystemIdentity(ex);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
@@ -308,9 +302,9 @@ namespace Tgstation.Server.Host.Controllers
|
||||
? NoContent()
|
||||
: Conflict(new ErrorMessageResponse(ErrorCode.ConfigurationDirectoryNotEmpty)));
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
catch (NotImplementedException ex)
|
||||
{
|
||||
return RequiresPosixSystemIdentity();
|
||||
return RequiresPosixSystemIdentity(ex);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
|
||||
@@ -94,8 +94,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
await jobManager.RegisterOperation(
|
||||
job,
|
||||
(core, databaseContextFactory, paramJob, progressHandler, innerCt) => core.Watchdog.Launch(innerCt),
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
return Accepted(job.ToApi());
|
||||
});
|
||||
|
||||
@@ -241,8 +240,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
await watchdog.ResetRebootState(cancellationToken);
|
||||
|
||||
return await ReadImpl(current, cancellationToken);
|
||||
})
|
||||
;
|
||||
});
|
||||
}
|
||||
#pragma warning restore CA1506
|
||||
#pragma warning restore CA1502
|
||||
@@ -276,8 +274,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
await jobManager.RegisterOperation(
|
||||
job,
|
||||
(core, paramJob, databaseContextFactory, progressReporter, ct) => core.Watchdog.Restart(false, ct),
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
return Accepted(job.ToApi());
|
||||
});
|
||||
|
||||
@@ -310,8 +307,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
await jobManager.RegisterOperation(
|
||||
job,
|
||||
(core, databaseContextFactory, paramJob, progressReporter, ct) => core.Watchdog.CreateDump(ct),
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
return Accepted(job.ToApi());
|
||||
});
|
||||
|
||||
@@ -336,8 +332,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.AsQueryable()
|
||||
.Where(x => x.Id == Instance.Id)
|
||||
.Select(x => x.DreamDaemonSettings)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
if (settings == default)
|
||||
return Gone();
|
||||
}
|
||||
|
||||
@@ -79,8 +79,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.DreamMakerSettings
|
||||
.AsQueryable()
|
||||
.Where(x => x.InstanceId == Instance.Id)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
return Json(dreamMakerSettings.ToApi());
|
||||
}
|
||||
|
||||
@@ -152,8 +151,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
job,
|
||||
(core, databaseContextFactory, paramJob, progressReporter, jobCancellationToken)
|
||||
=> core.DreamMaker.DeploymentProcess(paramJob, databaseContextFactory, progressReporter, jobCancellationToken),
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
return Accepted(job.ToApi());
|
||||
}
|
||||
|
||||
@@ -188,8 +186,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.DreamMakerSettings
|
||||
.AsQueryable()
|
||||
.Where(x => x.InstanceId == Instance.Id)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
if (hostModel == null)
|
||||
return Gone();
|
||||
|
||||
@@ -214,8 +211,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.GetAvailablePort(
|
||||
model.ApiValidationPort.Value,
|
||||
true,
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
if (verifiedPort != model.ApiValidationPort)
|
||||
return Conflict(new ErrorMessageResponse(ErrorCode.PortNotAvailable));
|
||||
|
||||
|
||||
@@ -241,7 +241,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
}
|
||||
catch (NotImplementedException ex)
|
||||
{
|
||||
Logger.LogTrace(ex, "System identities not implemented!");
|
||||
RequiresPosixSystemIdentity(ex);
|
||||
}
|
||||
|
||||
using (systemIdentity)
|
||||
@@ -297,6 +297,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
PasswordHash = x.PasswordHash,
|
||||
Enabled = x.Enabled,
|
||||
Name = x.Name,
|
||||
SystemIdentifier = x.SystemIdentifier,
|
||||
})
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
@@ -315,13 +316,13 @@ namespace Tgstation.Server.Host.Controllers
|
||||
// FALLBACK TO THE DB USER HERE, DO NOT REVEAL A SYSTEM LOGIN!!!
|
||||
// This of course, allows system users to discover TGS users in this (HIGHLY IMPROBABLE) case but that is not our fault
|
||||
var originalHash = user.PasswordHash;
|
||||
var isDbUser = originalHash != null;
|
||||
bool usingSystemIdentity = systemIdentity != null && !isDbUser;
|
||||
var isLikelyDbUser = originalHash != null;
|
||||
bool usingSystemIdentity = systemIdentity != null && !isLikelyDbUser;
|
||||
if (!oAuthLogin)
|
||||
if (!usingSystemIdentity)
|
||||
{
|
||||
// DB User password check and update
|
||||
if (originalHash == null || !cryptographySuite.CheckUserPassword(user, ApiHeaders.Password))
|
||||
if (!isLikelyDbUser || !cryptographySuite.CheckUserPassword(user, ApiHeaders.Password))
|
||||
return Unauthorized();
|
||||
if (user.PasswordHash != originalHash)
|
||||
{
|
||||
@@ -335,14 +336,30 @@ namespace Tgstation.Server.Host.Controllers
|
||||
await DatabaseContext.Save(cancellationToken);
|
||||
}
|
||||
}
|
||||
else if (systemIdentity.Username != user.Name)
|
||||
else
|
||||
{
|
||||
// System identity username change update
|
||||
Logger.LogDebug("User ID {userId}'s system identity needs a refresh, updating database.", user.Id);
|
||||
DatabaseContext.Users.Attach(user);
|
||||
user.Name = systemIdentity.Username;
|
||||
user.CanonicalName = Models.User.CanonicalizeName(user.Name);
|
||||
await DatabaseContext.Save(cancellationToken);
|
||||
var usernameMismatch = systemIdentity.Username != user.Name;
|
||||
if (isLikelyDbUser || usernameMismatch)
|
||||
{
|
||||
DatabaseContext.Users.Attach(user);
|
||||
if (isLikelyDbUser)
|
||||
{
|
||||
// cleanup from https://github.com/tgstation/tgstation-server/issues/1528
|
||||
Logger.LogDebug("System user ID {userId}'s PasswordHash is polluted, updating database.", user.Id);
|
||||
user.PasswordHash = null;
|
||||
user.LastPasswordUpdate = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
if (usernameMismatch)
|
||||
{
|
||||
// System identity username change update
|
||||
Logger.LogDebug("User ID {userId}'s system identity needs a refresh, updating database.", user.Id);
|
||||
user.Name = systemIdentity.Username;
|
||||
user.CanonicalName = Models.User.CanonicalizeName(user.Name);
|
||||
}
|
||||
|
||||
await DatabaseContext.Save(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
// Now that the bookeeping is done, tell them to fuck off if necessary
|
||||
|
||||
@@ -182,8 +182,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
if (earlyOut != null && !newCancellationToken.IsCancellationRequested)
|
||||
cts.Cancel();
|
||||
},
|
||||
newCancellationToken)
|
||||
;
|
||||
newCancellationToken);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
@@ -419,8 +418,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.ChatBots
|
||||
.AsQueryable()
|
||||
.Where(x => x.InstanceId == originalModel.Id)
|
||||
.CountAsync(cancellationToken)
|
||||
;
|
||||
.CountAsync(cancellationToken);
|
||||
|
||||
if (countOfExistingChatBots > model.ChatBotLimit.Value)
|
||||
return Conflict(new ErrorMessageResponse(ErrorCode.ChatBotMax));
|
||||
@@ -486,8 +484,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
job,
|
||||
(core, databaseContextFactory, paramJob, progressHandler, ct) // core will be null here since the instance is offline
|
||||
=> InstanceOperations.MoveInstance(originalModel, originalModelPath, ct),
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
api.MoveJob = job.ToApi();
|
||||
}
|
||||
|
||||
@@ -548,8 +545,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.Where(x => !x.StoppedAt.HasValue && x.Description.StartsWith(MoveInstanceJobPrefix))
|
||||
.Include(x => x.StartedBy).ThenInclude(x => x.CreatedBy)
|
||||
.Include(x => x.Instance)
|
||||
.ToListAsync(cancellationToken)
|
||||
;
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var needsUpdate = false;
|
||||
var result = await Paginated<Models.Instance, InstanceResponse>(
|
||||
@@ -565,8 +561,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
},
|
||||
page,
|
||||
pageSize,
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
|
||||
if (needsUpdate)
|
||||
await DatabaseContext.Save(cancellationToken);
|
||||
@@ -625,8 +620,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.SelectMany(x => x.Jobs)
|
||||
.Where(x => !x.StoppedAt.HasValue && x.Description.StartsWith(MoveInstanceJobPrefix))
|
||||
.Include(x => x.StartedBy).ThenInclude(x => x.CreatedBy)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
api.MoveJob = moveJob?.ToApi();
|
||||
await CheckAccessible(api, cancellationToken);
|
||||
return Json(api);
|
||||
@@ -654,14 +648,12 @@ namespace Tgstation.Server.Host.Controllers
|
||||
var usersInstancePermissionSet = await BaseQuery()
|
||||
.SelectMany(x => x.InstancePermissionSets)
|
||||
.Where(x => x.PermissionSetId == AuthenticationContext.PermissionSet.Id.Value)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
if (usersInstancePermissionSet == default)
|
||||
{
|
||||
// does the instance actually exist?
|
||||
var instanceExists = await BaseQuery()
|
||||
.AnyAsync(cancellationToken)
|
||||
;
|
||||
.AnyAsync(cancellationToken);
|
||||
|
||||
if (!instanceExists)
|
||||
return Gone();
|
||||
@@ -700,8 +692,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.GetAvailablePort(
|
||||
Math.Min((ushort)(ddPort.Value + 1), DefaultApiValidationPort),
|
||||
false,
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
if (!dmPort.HasValue)
|
||||
return null;
|
||||
|
||||
|
||||
@@ -73,8 +73,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
{
|
||||
UserId = x.UserId,
|
||||
})
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (existingPermissionSet == default)
|
||||
return Gone();
|
||||
@@ -86,8 +85,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.AsQueryable()
|
||||
.Where(x => x.Id == existingPermissionSet.UserId.Value)
|
||||
.Select(x => x.CanonicalName)
|
||||
.FirstAsync(cancellationToken)
|
||||
;
|
||||
.FirstAsync(cancellationToken);
|
||||
|
||||
if (userCanonicalName == Models.User.CanonicalizeName(Models.User.TgsSystemUserName))
|
||||
return Forbid();
|
||||
@@ -137,8 +135,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.Where(x => x.Id == Instance.Id)
|
||||
.SelectMany(x => x.InstancePermissionSets)
|
||||
.Where(x => x.PermissionSetId == model.PermissionSetId)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
if (originalPermissionSet == null)
|
||||
return Gone();
|
||||
|
||||
@@ -219,8 +216,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.Where(x => x.Id == Instance.Id)
|
||||
.SelectMany(x => x.InstancePermissionSets)
|
||||
.Where(x => x.PermissionSetId == id)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
if (permissionSet == default)
|
||||
return Gone();
|
||||
return Json(permissionSet.ToApi());
|
||||
@@ -246,8 +242,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.Where(x => x.Id == Instance.Id)
|
||||
.SelectMany(x => x.InstancePermissionSets)
|
||||
.Where(x => x.PermissionSetId == id)
|
||||
.DeleteAsync(cancellationToken)
|
||||
;
|
||||
.DeleteAsync(cancellationToken);
|
||||
return numDeleted > 0 ? NoContent() : Gone();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,8 +127,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.AsQueryable()
|
||||
.Include(x => x.StartedBy)
|
||||
.Where(x => x.Id == id && x.Instance.Id == Instance.Id)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
if (job == default)
|
||||
return NotFound();
|
||||
|
||||
@@ -162,8 +161,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.Where(x => x.Id == id && x.Instance.Id == Instance.Id)
|
||||
.Include(x => x.StartedBy)
|
||||
.Include(x => x.CancelledBy)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
if (job == default)
|
||||
return NotFound();
|
||||
var api = job.ToApi();
|
||||
|
||||
@@ -50,8 +50,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
outputStream,
|
||||
contentLength,
|
||||
BufferSize,
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -61,8 +60,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
outputStream,
|
||||
rangeLength,
|
||||
BufferSize,
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
|
||||
@@ -103,8 +103,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.RepositorySettings
|
||||
.AsQueryable()
|
||||
.Where(x => x.InstanceId == Instance.Id)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (currentModel == default)
|
||||
return Gone();
|
||||
@@ -178,19 +177,16 @@ namespace Tgstation.Server.Host.Controllers
|
||||
databaseContext.Instances.Attach(instance);
|
||||
if (await PopulateApi(api, repos, databaseContext, instance, ct))
|
||||
await databaseContext.Save(ct);
|
||||
})
|
||||
;
|
||||
});
|
||||
},
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
|
||||
api.Origin = model.Origin;
|
||||
api.Reference = model.Reference;
|
||||
api.ActiveJob = job.ToApi();
|
||||
|
||||
return Created(api);
|
||||
})
|
||||
;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -210,8 +206,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.RepositorySettings
|
||||
.AsQueryable()
|
||||
.Where(x => x.InstanceId == Instance.Id)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (currentModel == default)
|
||||
return Gone();
|
||||
@@ -233,8 +228,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
await jobManager.RegisterOperation(
|
||||
job,
|
||||
(core, databaseContextFactory, paramJob, progressReporter, ct) => core.RepositoryManager.DeleteRepository(ct),
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
api.ActiveJob = job.ToApi();
|
||||
return Accepted(api);
|
||||
}
|
||||
@@ -258,8 +252,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.RepositorySettings
|
||||
.AsQueryable()
|
||||
.Where(x => x.InstanceId == Instance.Id)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (currentModel == default)
|
||||
return Gone();
|
||||
@@ -286,8 +279,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
}
|
||||
|
||||
return Json(api);
|
||||
})
|
||||
;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -347,8 +339,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.RepositorySettings
|
||||
.AsQueryable()
|
||||
.Where(x => x.InstanceId == Instance.Id)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (currentModel == default)
|
||||
return Gone();
|
||||
@@ -412,8 +403,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
await PopulateApi(api, repo, DatabaseContext, Instance, cancellationToken);
|
||||
|
||||
return null;
|
||||
})
|
||||
;
|
||||
});
|
||||
|
||||
if (earlyOut != null)
|
||||
return earlyOut;
|
||||
|
||||
@@ -127,9 +127,9 @@ namespace Tgstation.Server.Host.Controllers
|
||||
dbUser.Name = sysIdentity.Username;
|
||||
dbUser.SystemIdentifier = sysIdentity.Uid;
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
catch (NotImplementedException ex)
|
||||
{
|
||||
return RequiresPosixSystemIdentity();
|
||||
return RequiresPosixSystemIdentity(ex);
|
||||
}
|
||||
else if (!(model.Password?.Length == 0 && model.OAuthConnections?.Any() == true))
|
||||
{
|
||||
@@ -144,7 +144,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
|
||||
await DatabaseContext.Save(cancellationToken);
|
||||
|
||||
Logger.LogInformation("Created new user {0} ({1})", dbUser.Name, dbUser.Id);
|
||||
Logger.LogInformation("Created new user {name} ({id})", dbUser.Name, dbUser.Id);
|
||||
|
||||
return Created(dbUser.ToApi());
|
||||
}
|
||||
@@ -195,8 +195,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.Include(x => x.Group)
|
||||
.ThenInclude(x => x.PermissionSet)
|
||||
.Include(x => x.PermissionSet)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (originalUser == default)
|
||||
return NotFound();
|
||||
@@ -215,12 +214,21 @@ namespace Tgstation.Server.Host.Controllers
|
||||
|| (!oAuthEdit && model.OAuthConnections != null))
|
||||
return Forbid();
|
||||
|
||||
var originalUserHasSid = originalUser.SystemIdentifier != null;
|
||||
if (originalUserHasSid && originalUser.PasswordHash != null)
|
||||
{
|
||||
// cleanup from https://github.com/tgstation/tgstation-server/issues/1528
|
||||
Logger.LogDebug("System user ID {userId}'s PasswordHash is polluted, updating database.", originalUser.Id);
|
||||
originalUser.PasswordHash = null;
|
||||
originalUser.LastPasswordUpdate = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
if (model.SystemIdentifier != null && model.SystemIdentifier != originalUser.SystemIdentifier)
|
||||
return BadRequest(new ErrorMessageResponse(ErrorCode.UserSidChange));
|
||||
|
||||
if (model.Password != null)
|
||||
{
|
||||
if (model.SystemIdentifier != null)
|
||||
if (originalUserHasSid)
|
||||
return BadRequest(new ErrorMessageResponse(ErrorCode.UserMismatchPasswordSid));
|
||||
|
||||
var result = TrySetPassword(originalUser, model.Password, false);
|
||||
@@ -265,8 +273,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.AsQueryable()
|
||||
.Where(x => x.Id == model.Group.Id)
|
||||
.Include(x => x.PermissionSet)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (originalUser.Group == default)
|
||||
return Gone();
|
||||
@@ -408,8 +415,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.AsQueryable()
|
||||
.Where(x => x.Id == model.Group.Id)
|
||||
.Include(x => x.PermissionSet)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
else
|
||||
permissionSet = new Models.PermissionSet
|
||||
{
|
||||
|
||||
@@ -75,8 +75,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
var totalGroups = await DatabaseContext
|
||||
.Groups
|
||||
.AsQueryable()
|
||||
.CountAsync(cancellationToken)
|
||||
;
|
||||
.CountAsync(cancellationToken);
|
||||
if (totalGroups >= generalConfiguration.UserGroupLimit)
|
||||
return Conflict(new ErrorMessageResponse(ErrorCode.UserGroupLimitReached));
|
||||
|
||||
@@ -121,8 +120,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.Where(x => x.Id == model.Id)
|
||||
.Include(x => x.PermissionSet)
|
||||
.Include(x => x.Users)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (currentGroup == default)
|
||||
return Gone();
|
||||
@@ -167,8 +165,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.Where(x => x.Id == id)
|
||||
.Include(x => x.Users)
|
||||
.Include(x => x.PermissionSet)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
if (group == default)
|
||||
return Gone();
|
||||
return Json(group.ToApi(true));
|
||||
@@ -220,8 +217,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.Groups
|
||||
.AsQueryable()
|
||||
.Where(x => x.Id == id && x.Users.Count == 0)
|
||||
.DeleteAsync(cancellationToken)
|
||||
;
|
||||
.DeleteAsync(cancellationToken);
|
||||
|
||||
if (numDeleted > 0)
|
||||
return NoContent();
|
||||
@@ -231,8 +227,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.Groups
|
||||
.AsQueryable()
|
||||
.Where(x => x.Id == id)
|
||||
.AnyAsync(cancellationToken)
|
||||
;
|
||||
.AnyAsync(cancellationToken);
|
||||
|
||||
return groupExists
|
||||
? Conflict(new ErrorMessageResponse(ErrorCode.UserGroupNotEmpty))
|
||||
|
||||
@@ -215,8 +215,7 @@ namespace Tgstation.Server.Host.Database
|
||||
.Users
|
||||
.AsQueryable()
|
||||
.Where(x => x.CanonicalName == User.CanonicalizeName(User.TgsSystemUserName))
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (tgsUser != null)
|
||||
logger.LogError(
|
||||
@@ -233,8 +232,7 @@ namespace Tgstation.Server.Host.Database
|
||||
var allInstances = await databaseContext
|
||||
.Instances
|
||||
.AsQueryable()
|
||||
.ToListAsync(cancellationToken)
|
||||
;
|
||||
.ToListAsync(cancellationToken);
|
||||
foreach (var instance in allInstances)
|
||||
instance.Path = instance.Path.Replace('\\', '/');
|
||||
}
|
||||
@@ -246,8 +244,7 @@ namespace Tgstation.Server.Host.Database
|
||||
.AsQueryable()
|
||||
.Where(x => x.TopicRequestTimeout == 0)
|
||||
.Select(x => x.Id)
|
||||
.ToListAsync(cancellationToken)
|
||||
;
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var rowsUpdated = ids.Count;
|
||||
foreach (var id in ids)
|
||||
@@ -318,8 +315,7 @@ namespace Tgstation.Server.Host.Database
|
||||
.Include(x => x.CreatedBy)
|
||||
.Include(x => x.PermissionSet)
|
||||
.Include(x => x.Group)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
if (admin == default)
|
||||
SeedAdminUser(databaseContext);
|
||||
|
||||
|
||||
@@ -108,8 +108,7 @@ namespace Tgstation.Server.Host.Jobs
|
||||
if (job.StartedBy == null)
|
||||
job.StartedBy = await databaseContext
|
||||
.Users
|
||||
.GetTgsUser(cancellationToken)
|
||||
;
|
||||
.GetTgsUser(cancellationToken);
|
||||
else
|
||||
job.StartedBy = new User
|
||||
{
|
||||
|
||||
@@ -76,8 +76,7 @@ namespace Tgstation.Server.Host.Security
|
||||
.Include(x => x.Group)
|
||||
.ThenInclude(x => x.PermissionSet)
|
||||
.Include(x => x.OAuthConnections)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
if (user == default)
|
||||
{
|
||||
logger.LogWarning("Unable to find user with ID {0}!", userId);
|
||||
@@ -110,8 +109,7 @@ namespace Tgstation.Server.Host.Security
|
||||
.AsQueryable()
|
||||
.Where(x => x.PermissionSetId == userPermissionSet.Id && x.InstanceId == instanceId && x.Instance.SwarmIdentifer == swarmConfiguration.Identifier)
|
||||
.Include(x => x.Instance)
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
;
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (instancePermissionSet == null)
|
||||
logger.LogDebug("User {0} does not have permissions on instance {1}!", userId, instanceId.Value);
|
||||
|
||||
@@ -68,8 +68,7 @@ namespace Tgstation.Server.Host.Security
|
||||
userId,
|
||||
apiHeaders.InstanceId,
|
||||
tokenValidatedContext.SecurityToken.ValidFrom,
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
|
||||
var authenticationContext = authenticationContextFactory.CurrentAuthenticationContext;
|
||||
|
||||
|
||||
@@ -63,11 +63,15 @@ namespace Tgstation.Server.Host.Security
|
||||
PrincipalContext pc = null;
|
||||
UserPrincipal principal = null;
|
||||
|
||||
GetUserAndDomainName(user.SystemIdentifier, out _, out var domainName);
|
||||
|
||||
bool TryGetPrincipalFromContextType(ContextType contextType)
|
||||
{
|
||||
try
|
||||
{
|
||||
pc = new PrincipalContext(contextType);
|
||||
pc = domainName != null
|
||||
? new PrincipalContext(contextType, domainName)
|
||||
: new PrincipalContext(contextType);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
principal = UserPrincipal.FindByIdentity(pc, user.SystemIdentifier);
|
||||
}
|
||||
@@ -75,9 +79,13 @@ namespace Tgstation.Server.Host.Security
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception e)
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogWarning(e, "Error loading user for context type {0}!", contextType);
|
||||
logger.LogDebug(
|
||||
ex,
|
||||
"Error loading user for context type {contextType} and principal \"{domainName}\"!",
|
||||
contextType,
|
||||
domainName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -176,8 +176,7 @@ namespace Tgstation.Server.Host.Setup
|
||||
await console.WriteAsync(
|
||||
$"API Port (leave blank for default of {GeneralConfiguration.DefaultApiPort}): ",
|
||||
false,
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
var portString = await console.ReadLineAsync(false, cancellationToken);
|
||||
if (String.IsNullOrWhiteSpace(portString))
|
||||
return null;
|
||||
@@ -319,8 +318,7 @@ namespace Tgstation.Server.Host.Setup
|
||||
await console.WriteAsync(resolvedPath, true, cancellationToken);
|
||||
bool writeResolved = await PromptYesNo(
|
||||
"Would you like to save the relative path in the configuration? If not, the full path will be saved. (y/n): ",
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
|
||||
if (writeResolved)
|
||||
databaseName = resolvedPath;
|
||||
@@ -344,23 +342,19 @@ namespace Tgstation.Server.Host.Setup
|
||||
await console.WriteAsync(
|
||||
"NOTE: It is HIGHLY reccommended that TGS runs on a complete relational database, specfically *NOT* Sqlite.",
|
||||
true,
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
await console.WriteAsync(
|
||||
"Sqlite, by nature cannot perform several DDL operations. Because of this future compatiblility cannot be guaranteed.",
|
||||
true,
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
await console.WriteAsync(
|
||||
"This means that you may not be able to update to the next minor version of TGS without a clean re-installation!",
|
||||
true,
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
await console.WriteAsync(
|
||||
"Please consider taking the time to set up a relational database if this is meant to be a long-standing server.",
|
||||
true,
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
await console.WriteAsync(String.Empty, true, cancellationToken);
|
||||
|
||||
await asyncDelayer.Delay(TimeSpan.FromSeconds(3), cancellationToken);
|
||||
@@ -379,8 +373,7 @@ namespace Tgstation.Server.Host.Setup
|
||||
DatabaseType.SqlServer,
|
||||
DatabaseType.Sqlite),
|
||||
false,
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
var databaseTypeString = await console.ReadLineAsync(false, cancellationToken);
|
||||
if (Enum.TryParse<DatabaseType>(databaseTypeString, out var databaseType))
|
||||
return databaseType;
|
||||
@@ -1007,8 +1000,7 @@ namespace Tgstation.Server.Host.Setup
|
||||
elasticSearchConfiguration,
|
||||
controlPanelConfiguration,
|
||||
swarmConfiguration,
|
||||
cancellationToken)
|
||||
;
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -965,8 +965,7 @@ namespace Tgstation.Server.Host.Swarm
|
||||
await Task.WhenAll(
|
||||
currentSwarmServers
|
||||
.Where(x => !x.Controller)
|
||||
.Select(HealthRequestForServer))
|
||||
;
|
||||
.Select(HealthRequestForServer));
|
||||
|
||||
lock (swarmServers)
|
||||
if (swarmServers.Count != currentSwarmServers.Count)
|
||||
|
||||
@@ -67,16 +67,14 @@ namespace Tgstation.Server.Host.Utils
|
||||
.AsQueryable()
|
||||
.Where(x => x.Instance.SwarmIdentifer == swarmConfiguration.Identifier)
|
||||
.Select(x => x.Port)
|
||||
.ToListAsync(cancellationToken)
|
||||
;
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var dmPorts = await databaseContext
|
||||
.DreamMakerSettings
|
||||
.AsQueryable()
|
||||
.Where(x => x.Instance.SwarmIdentifer == swarmConfiguration.Identifier)
|
||||
.Select(x => x.ApiValidationPort)
|
||||
.ToListAsync(cancellationToken)
|
||||
;
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var exceptions = new List<Exception>();
|
||||
ushort port = 0;
|
||||
|
||||
@@ -224,35 +224,45 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
Assert.AreEqual(1, dumpFiles.Length);
|
||||
File.Delete(dumpFiles.Single());
|
||||
|
||||
KillDD(true);
|
||||
var jobTcs = new TaskCompletionSource();
|
||||
var killTaskStarted = new TaskCompletionSource();
|
||||
var killTask = Task.Run(() =>
|
||||
{
|
||||
killTaskStarted.SetResult();
|
||||
while (!jobTcs.Task.IsCompleted)
|
||||
KillDD(false);
|
||||
}, cancellationToken);
|
||||
|
||||
JobResponse job;
|
||||
try
|
||||
while (true)
|
||||
{
|
||||
await killTaskStarted.Task;
|
||||
var dumpTask = instanceClient.DreamDaemon.CreateDump(cancellationToken);
|
||||
job = await WaitForJob(await dumpTask, 20, true, null, cancellationToken);
|
||||
}
|
||||
finally
|
||||
{
|
||||
jobTcs.SetResult();
|
||||
await killTask;
|
||||
KillDD(true);
|
||||
var jobTcs = new TaskCompletionSource();
|
||||
var killTaskStarted = new TaskCompletionSource();
|
||||
var killTask = Task.Run(() =>
|
||||
{
|
||||
killTaskStarted.SetResult();
|
||||
while (!jobTcs.Task.IsCompleted)
|
||||
KillDD(false);
|
||||
}, cancellationToken);
|
||||
|
||||
try
|
||||
{
|
||||
await killTaskStarted.Task;
|
||||
var dumpTask = instanceClient.DreamDaemon.CreateDump(cancellationToken);
|
||||
job = await WaitForJob(await dumpTask, 20, true, null, cancellationToken);
|
||||
}
|
||||
finally
|
||||
{
|
||||
jobTcs.SetResult();
|
||||
await killTask;
|
||||
}
|
||||
|
||||
// these can also happen
|
||||
|
||||
if (!(new PlatformIdentifier().IsWindows
|
||||
&& (job.ExceptionDetails.Contains("BetterWin32Errors.Win32Exception: E_ACCESSDENIED: Access is denied.")
|
||||
|| job.ExceptionDetails.Contains("BetterWin32Errors.Win32Exception: E_HANDLE: The handle is invalid.")
|
||||
|| job.ExceptionDetails.Contains("BetterWin32Errors.Win32Exception: 3489660936: Unknown error (0xd0000008)")
|
||||
|| job.ExceptionDetails.Contains("System.InvalidOperationException: No process is associated with this object."))))
|
||||
break;
|
||||
|
||||
var restartJob = await instanceClient.DreamDaemon.Restart(cancellationToken);
|
||||
await WaitForJob(restartJob, 20, false, null, cancellationToken);
|
||||
}
|
||||
|
||||
// these can also happen
|
||||
if (!(new PlatformIdentifier().IsWindows
|
||||
&& (job.ExceptionDetails.Contains("BetterWin32Errors.Win32Exception: E_ACCESSDENIED: Access is denied.")
|
||||
|| job.ExceptionDetails.Contains("BetterWin32Errors.Win32Exception: E_HANDLE: The handle is invalid.")
|
||||
|| job.ExceptionDetails.Contains("BetterWin32Errors.Win32Exception: 3489660936: Unknown error (0xd0000008)")))) // kek
|
||||
Assert.IsTrue(job.ErrorCode == ErrorCode.DreamDaemonOffline || job.ErrorCode == ErrorCode.GCoreFailure, $"{job.ErrorCode}: {job.ExceptionDetails}");
|
||||
Assert.IsTrue(job.ErrorCode == ErrorCode.DreamDaemonOffline || job.ErrorCode == ErrorCode.GCoreFailure, $"{job.ErrorCode}: {job.ExceptionDetails}");
|
||||
|
||||
await Task.Delay(TimeSpan.FromSeconds(20), cancellationToken);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user