diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 4348930e99..e6c9393e81 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -41,14 +41,36 @@ The recommended IDE is Visual Studio 2019 which has installation options for bot
In order to run the integration tests you must have the following environment variables set. To run them more accurately, include the optional ones.
- `TGS_TEST_DATABASE_TYPE`: `MySql`, `MariaDB`, `PostgresSql`, or `SqlServer`.
- `TGS_TEST_CONNECTION_STRING`: To a valid database connection string. You can use the setup wizard to create one.
-- `TGS_TEST_BRANCH`: Should be either `dev` or `master` depending on what you are working off of. Used for repository tests.
- (Optional) `TGS_TEST_GITHUB_TOKEN`: A GitHub personal access token with no scopes used to bypass rate limits.
- (Optional) The following variables are all interdependent, so if one is set they all must be.
- - `TSG_TEST_DISCORD_TOKEN`: To a valid discord bot token.
+ - `TGS_TEST_DISCORD_TOKEN`: To a valid discord bot token.
- `TGS_TEST_DISCORD_CHANNEL`: To a valid discord channel ID that the above bot can access.
- `TGS_TEST_IRC_CONNECTION_STRING`: To a valid IRC connection string. See the code for [IrcConnectionStringBuilder](../src/Tgstation.Server.Api/Models/IrcConnectionStringBuilder.cs) for details.
- `TGS_TEST_IRC_CHANNEL`: To a valid IRC channel accessible with the above connection.
+### Notes About Forks
+
+For the full CI gambit, the following repository configuration must be set:
+
+- Setting `Workflow Permissions` to `Read and write permissions`: Enables CodeQL uploads and GitHub Actions comments.
+
+- Label `CI Cleared`: To allow PRs from forks to run CI with secrets after approval.
+- Variable `TGS_ENABLE_CODE_QL` to `true`: Enables CodeQL scanning in actions.
+- Integration [CodeCov](https://github.com/apps/codecov): Enables CodeCov status checks.
+- Secret `CODECOV_TOKEN`: A CodeCov repo token to work around https://github.com/codecov/codecov-action/issues/837.
+- Secret `LIVE_TESTS_TOKEN`: A GitHub token with read access to the repository and write access to https://github.com/Cyberboss/common_core (TODO: Make the target repository here configurable). Despite it's name, it may be used across the entire test suite.
+- Secret `TGS_TEST_DISCORD_TOKEN`: See above note about test environment variables.
+- Secret `TGS_TEST_DISCORD_CHANNEL`: See above note about test environment variables.
+- Secret `TGS_TEST_IRC_CONNECTION_STRING`: See above note about test environment variables.
+- Secret `TGS_TEST_IRC_CHANNEL`: See above note about test environment variables.
+
+If you don't plan on deploying TGS, the following secrets can be omitted:
+
+- Secret `DEV_PUSH_TOKEN`: A GitHub token with write access to the repository. Enables doxygen pushes to `gh-pages` branch, and releases creation.
+- Secret `DOCKER_USERNAME`: Login username for Docker image push.
+- Secret `DOCKER_PASSWORD`: Login password for Docker image push.
+- Secret `NUGET_API_KEY`: Nuget.org API Key for client libraries push.
+
### Know your Code
- All feature work should be submitted to the `dev` branch for the next minor release.
@@ -224,6 +246,7 @@ We have several subcomponent APIs we ship with the core server that have their o
- HTTP API
- DreamMaker API
+- Interop API
- Configuration File
- Host Watchdog
- Web Control Panel
@@ -237,19 +260,19 @@ All versions are stored in the master file [build/Version.props](../build/Versio
The NuGet package Tgstation.Server.Client is another part of the suite which should be versioned separately. However, Tgstation.Server.Api is also a package that is published, and breaking changes can happen independantly of each other.
- Consider Tgstation.Server.Client it's own product, perform major and minor bumps according to semver semantics including the Tgstation.Server.Api code (but not the version).
-- Tgstation.Server.Api is a bit tricky as breaking code changes may occur without affecting the actual HTTP contract. For this reason, all code changes that do this should be pushed out as patches, even if they contain breaking changes.
+- Tgstation.Server.Api is a bit tricky as breaking code changes may occur without affecting the actual HTTP contract. For this reason, the library itself is versioned separately from the API contract.
## Triage, Deployment, and Releasing
_This section mainly applies to people with write access to the repository. Anyone is free to propose their work and maintainers will triage it appropriately._
-When issues affecting the server come in, they should be lebeled appropriately and either put into the `Backlog` milestone or current patch milestone depending on if it's a feature request or bug.
+When issues affecting the server come in, they should be labeled appropriately and either put into the `Backlog` milestone or current patch milestone depending on if it's a feature request or bug.
After a minor release, the team should decide at that time what will go into it and setup the milestone accordingly. At this point the `Backlog` label should be removed and replaced with `Ready` and the milestone changed from `Backlog` to `vX.Y.0` with X/Y being the major/minor release versions respectively.
Assign work before beginning on it. When work is started, replace the `Ready` label with the `Work In Progress` label.
-Word commit names descriptively. Only submit work through pull requests. When doing so, link the issue you'll be closing and set the milestone appropriately. Don't forget a changelog. **WARNING** Remember to submit patches to the `master` branch. Also at the time of this writing there appears to be an issue where GitHub won't close issues with PRs to the non-default branch. Maintainers may need to do this manually after merging.
+Word commit names descriptively. Only submit work through pull requests (With the exception of resolving conflicts in the `master` -> `dev` automatic merge). When doing so, link the issue you'll be closing and set the milestone appropriately. Don't forget a changelog. **WARNING** Remember to submit patches to the `master` branch. Also at the time of this writing there appears to be an issue where GitHub won't close issues with PRs to the non-default branch. Maintainers may need to do this manually after merging. Alternatively, add closing keywords to the commit message and let the `master` -> `dev` merge do the closing.
At the time of this writing, the repository is configured to automate much of the deployment/release process.
@@ -259,10 +282,10 @@ That step should be taken for the latest API and client before releasing the cor
Before releasing the core version, ensure the following:
-- For minor releases, ensure your changes are merging `dev` into `master`.
+- For minor/major releases, ensure your changes are merging `dev` into `master`.
- Ensure all issues and pull requests in the associated milestone are closed (aside from the PR you are using to cut the release).
-To perform the release, merge the PR with `[TGSDeploy]` in the commit message. The build system will handle generating release notes, packaging, and pushing the build to GitHub releases. This will also make it available for servers to self update.
+To perform the release, merge the PR with `[TGSDeploy]` in the commit message. The build system will handle generating release notes, packaging, and pushing the build to GitHub releases. This will also make it available for servers to self update. Note that `[TGSDeploy]` only affects commits on the `master` branch.
The build system will also handle closing the current milestone and creating new minor/patch milestones where applicable.
diff --git a/.github/workflows/auto-approve-dominions-prs.yml b/.github/workflows/auto-approve-dominions-prs.yml
index c12ea6df32..a4d04fdf59 100644
--- a/.github/workflows/auto-approve-dominions-prs.yml
+++ b/.github/workflows/auto-approve-dominions-prs.yml
@@ -16,7 +16,7 @@ concurrency:
jobs:
approve-pr-if-dominion-is-author:
name: Approve PR if Dominion is Author
- if: github.event.pull_request.user.login == 'Cyberboss'
+ if: github.event.pull_request.user.login == 'Cyberboss' && (github.event.pull_request.base.repo.owner.login == 'tgstation' || && github.event.pull_request.base.repo.owner.login == 'Cyberboss')
runs-on: ubuntu-latest
steps:
- name: GitHub API Call
diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml
index 6641c4cd5c..6a380a86d9 100644
--- a/.github/workflows/ci-suite.yml
+++ b/.github/workflows/ci-suite.yml
@@ -21,6 +21,7 @@ env:
TGS_DOTNET_VERSION: 6.0.x
TGS_TEST_GITHUB_TOKEN: ${{ secrets.LIVE_TESTS_TOKEN }}
TGS_RELEASE_NOTES_TOKEN: ${{ secrets.DEV_PUSH_TOKEN }}
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
concurrency:
group: "ci-${{ github.head_ref || github.run_id }}-${{ github.event_name }}"
@@ -57,44 +58,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 +77,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
@@ -186,7 +149,7 @@ jobs:
doxyfile-path: 'docs/Doxyfile'
- name: gh-pages push
- if: github.event_name == 'push' && github.event.ref == 'refs/heads/dev'
+ if: github.event_name == 'push' && github.event.ref == 'refs/heads/dev' && env.TGS_RELEASE_NOTES_TOKEN != ''
run: |
git clone -b gh-pages --single-branch "https://git@github.com/tgstation/tgstation-server" $HOME/tgsdox
pushd $HOME/tgsdox
@@ -324,7 +287,7 @@ jobs:
database-type: [ 'SqlServer', 'Sqlite', 'PostgresSql', 'MariaDB', 'MySql' ]
watchdog-type: [ 'Basic', 'System' ]
configuration: [ 'Debug', 'Release' ]
- runs-on: windows-2019
+ runs-on: windows-latest
env:
BYOND_MAJOR: 514
BYOND_MINOR: 1588
@@ -338,7 +301,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
diff --git a/.github/workflows/code-scanning.yml b/.github/workflows/code-scanning.yml
new file mode 100644
index 0000000000..617148d18a
--- /dev/null
+++ b/.github/workflows/code-scanning.yml
@@ -0,0 +1,51 @@
+name: 'Code Scanning'
+
+on:
+ schedule:
+ - cron: 0 23 * * 1
+ 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
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+ if: ${{ vars.TGS_ENABLE_CODE_QL }} == 'true'
+ 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
+ with:
+ category: "/language:csharp"
diff --git a/SECURITY.md b/SECURITY.md
index 5d79c18579..1e624e68bb 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -16,6 +16,6 @@ Vulnerabilities should ideally be reported by directly messaging one of the TGS
Here is a list of their discord IDs.
-@Cyberboss - Dominion#0444 (<@133295178197893120>)
+@Cyberboss - dominion (<@133295178197893120>)
Once reported, they will handle the processing of the security advisory.
diff --git a/build/Version.props b/build/Version.props
index 9aa88ff147..d9e18b8d86 100644
--- a/build/Version.props
+++ b/build/Version.props
@@ -3,7 +3,7 @@
- 5.12.4
+ 5.12.5
4.6.0
9.10.2
11.0.0
diff --git a/src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs b/src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs
index dcc4f234c3..3fc5d4d152 100644
--- a/src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs
+++ b/src/Tgstation.Server.Host/Components/Byond/ByondInstallerBase.cs
@@ -70,8 +70,7 @@ namespace Tgstation.Server.Host.Components.Byond
IOManager.ConcatPath(
PathToUserByondFolder,
CacheDirectoryName),
- cancellationToken)
- ;
+ cancellationToken);
}
catch (OperationCanceledException)
{
diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs
index 08d4b7a1ce..e8db69db69 100644
--- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs
@@ -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)
diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs
index f9ef3396c6..bfc541e6f9 100644
--- a/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/Providers/Provider.cs
@@ -309,7 +309,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
cancellationToken);
// DCT: Always wait for the job to complete here
- await jobManager.WaitForJobCompletion(job, null, cancellationToken, default);
+ await jobManager.WaitForJobCompletion(job, null, cancellationToken, cancellationToken);
}
}
catch (OperationCanceledException e)
diff --git a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs
index 7d57085eff..2c5abb0541 100644
--- a/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs
+++ b/src/Tgstation.Server.Host/Components/Deployment/DmbFactory.cs
@@ -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)
{
diff --git a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs
index 8470210425..31e8e3a956 100644
--- a/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs
+++ b/src/Tgstation.Server.Host/Components/Deployment/DreamMaker.cs
@@ -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));
}
}
}
diff --git a/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs b/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs
index 0acc80828c..a794135d13 100644
--- a/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs
+++ b/src/Tgstation.Server.Host/Components/Deployment/SwappableDmbProvider.cs
@@ -73,8 +73,7 @@ namespace Tgstation.Server.Host.Components.Deployment
await symlinkFactory.CreateSymbolicLink(
ioManager.ResolvePath(baseProvider.Directory),
ioManager.ResolvePath(LiveGameDirectory),
- cancellationToken)
- ;
+ cancellationToken);
}
}
}
diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs
index 95ca246c42..42e18fa43b 100644
--- a/src/Tgstation.Server.Host/Components/Instance.cs
+++ b/src/Tgstation.Server.Host/Components/Instance.cs
@@ -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);
@@ -514,11 +509,9 @@ namespace Tgstation.Server.Host.Components
await jobManager.RegisterOperation(
repositoryUpdateJob,
RepositoryAutoUpdateJob,
- cancellationToken)
- ;
+ cancellationToken);
- // DCT: First token will cancel the job, second is for cancelling the cancellation, unwanted
- await jobManager.WaitForJobCompletion(repositoryUpdateJob, null, cancellationToken, default);
+ await jobManager.WaitForJobCompletion(repositoryUpdateJob, null, cancellationToken, cancellationToken);
Job compileProcessJob;
using (var repo = await RepositoryManager.LoadRepository(cancellationToken))
@@ -557,8 +550,7 @@ namespace Tgstation.Server.Host.Components
progressReporter,
jobCancellationToken);
},
- cancellationToken)
- ;
+ cancellationToken);
}
await jobManager.WaitForJobCompletion(compileProcessJob, null, default, cancellationToken);
diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs
index a0c7f8ceec..1ffb944912 100644
--- a/src/Tgstation.Server.Host/Components/InstanceManager.cs
+++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs
@@ -284,8 +284,7 @@ namespace Tgstation.Server.Host.Components
await ioManager.WriteAllBytes(
ioManager.ConcatPath(oldPath, InstanceController.InstanceAttachFileName),
Array.Empty(),
- default)
- ;
+ default);
}
catch (Exception tripleEx)
{
diff --git a/src/Tgstation.Server.Host/Components/Repository/GitLabRemoteFeatures.cs b/src/Tgstation.Server.Host/Components/Repository/GitLabRemoteFeatures.cs
index b66c98f3e1..fbb43a62ef 100644
--- a/src/Tgstation.Server.Host/Components/Repository/GitLabRemoteFeatures.cs
+++ b/src/Tgstation.Server.Host/Components/Repository/GitLabRemoteFeatures.cs
@@ -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)
diff --git a/src/Tgstation.Server.Host/Components/Repository/Repository.cs b/src/Tgstation.Server.Host/Components/Repository/Repository.cs
index 6025be0cff..f0256c05e1 100644
--- a/src/Tgstation.Server.Host/Components/Repository/Repository.cs
+++ b/src/Tgstation.Server.Host/Components/Repository/Repository.cs
@@ -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);
}
///
@@ -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);
}
///
@@ -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
diff --git a/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs b/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs
index 4f283079de..53de9c45c3 100644
--- a/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs
+++ b/src/Tgstation.Server.Host/Components/Repository/RepositoryUpdateService.cs
@@ -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();
}
diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs
index 164fb6e218..b7978ff051 100644
--- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs
+++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs
@@ -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;
}
diff --git a/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs b/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs
index 34b46db93c..6b1020fd92 100644
--- a/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs
+++ b/src/Tgstation.Server.Host/Components/Session/SessionPersistor.cs
@@ -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);
diff --git a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs
index de5600c7ea..54ec2fa416 100644
--- a/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs
+++ b/src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs
@@ -652,8 +652,7 @@ namespace Tgstation.Server.Host.Components.StaticFiles
await Task.WhenAll(
ioManager.CreateDirectory(CodeModificationsSubdirectory, cancellationToken),
ioManager.CreateDirectory(EventScriptsSubdirectory, cancellationToken),
- ValidateStaticFolder())
- ;
+ ValidateStaticFolder());
}
///
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdog.cs
index f9f3e6bbb4..9eacfc2f17 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdog.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/PosixWatchdog.cs
@@ -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)
{
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs
index 9bad7226ad..4a748ee869 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/WatchdogBase.cs
@@ -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);
}
@@ -853,7 +852,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
var healthCheckSeconds = ActiveLaunchParameters.HeartbeatSeconds.Value;
var healthCheck = healthCheckSeconds == 0
|| !controller.DMApiAvailable
- ? Extensions.TaskExtensions.InfiniteTask()
+ ? Extensions.TaskExtensions.InfiniteTask
: Task.Delay(
TimeSpan.FromSeconds(healthCheckSeconds),
cancellationToken);
diff --git a/src/Tgstation.Server.Host/Controllers/ApiController.cs b/src/Tgstation.Server.Host/Controllers/ApiController.cs
index c3e64cfdac..2e0841d409 100644
--- a/src/Tgstation.Server.Host/Controllers/ApiController.cs
+++ b/src/Tgstation.Server.Host/Controllers/ApiController.cs
@@ -125,8 +125,7 @@ namespace Tgstation.Server.Host.Controllers
await this.StatusCode(
HttpStatusCode.UpgradeRequired,
new ErrorMessageResponse(ErrorCode.ApiMismatch))
- .ExecuteResultAsync(context)
- ;
+ .ExecuteResultAsync(context);
return;
}
@@ -142,8 +141,7 @@ namespace Tgstation.Server.Host.Controllers
if (requireHeaders)
{
await HeadersIssue(false)
- .ExecuteResultAsync(context)
- ;
+ .ExecuteResultAsync(context);
return;
}
}
@@ -218,8 +216,13 @@ namespace Tgstation.Server.Host.Controllers
///
/// Generic 501 response.
///
+ /// The that was thrown.
/// An with .
- protected ObjectResult RequiresPosixSystemIdentity() => this.StatusCode(HttpStatusCode.NotImplemented, new ErrorMessageResponse(ErrorCode.RequiresPosixSystemIdentity));
+ protected ObjectResult RequiresPosixSystemIdentity(NotImplementedException ex)
+ {
+ Logger.LogTrace(ex, "System identities not implemented!");
+ return this.StatusCode(HttpStatusCode.NotImplemented, new ErrorMessageResponse(ErrorCode.RequiresPosixSystemIdentity));
+ }
///
/// Strongly type calls to .
@@ -384,8 +387,7 @@ namespace Tgstation.Server.Host.Controllers
{
totalResults = await paginationResult.Results.CountAsync(cancellationToken);
pagedResults = await queriedResults
- .ToListAsync(cancellationToken)
- ;
+ .ToListAsync(cancellationToken);
}
else
{
diff --git a/src/Tgstation.Server.Host/Controllers/ChatController.cs b/src/Tgstation.Server.Host/Controllers/ChatController.cs
index d54d7c8fdc..0b9931f05a 100644
--- a/src/Tgstation.Server.Host/Controllers/ChatController.cs
+++ b/src/Tgstation.Server.Host/Controllers/ChatController.cs
@@ -189,8 +189,7 @@ namespace Tgstation.Server.Host.Controllers
.ChatBots
.AsQueryable()
.Where(x => x.Id == id)
- .DeleteAsync(cancellationToken))
- ;
+ .DeleteAsync(cancellationToken));
return null;
})
@@ -365,8 +364,7 @@ namespace Tgstation.Server.Host.Controllers
await chat.ChangeChannels(current.Id.Value, current.Channels, cancellationToken);
return null;
- })
- ;
+ });
if (earlyOut != null)
return earlyOut;
diff --git a/src/Tgstation.Server.Host/Controllers/ConfigurationController.cs b/src/Tgstation.Server.Host/Controllers/ConfigurationController.cs
index 4f86feb9a1..61acf2d216 100644
--- a/src/Tgstation.Server.Host/Controllers/ConfigurationController.cs
+++ b/src/Tgstation.Server.Host/Controllers/ConfigurationController.cs
@@ -85,12 +85,10 @@ namespace Tgstation.Server.Host.Controllers
model.Path,
systemIdentity,
model.LastReadHash,
- cancellationToken)
- ;
+ cancellationToken);
return model.LastReadHash == null ? Accepted(newFile) : Json(newFile);
- })
- ;
+ });
}
catch (IOException e)
{
@@ -100,9 +98,9 @@ namespace Tgstation.Server.Host.Controllers
AdditionalData = e.Message,
});
}
- catch (NotImplementedException)
+ catch (NotImplementedException ex)
{
- return RequiresPosixSystemIdentity();
+ return RequiresPosixSystemIdentity(ex);
}
}
@@ -130,14 +128,12 @@ namespace Tgstation.Server.Host.Controllers
{
var result = await instance
.Configuration
- .Read(filePath, systemIdentity, cancellationToken)
- ;
+ .Read(filePath, systemIdentity, cancellationToken);
if (result == null)
return this.Gone();
return Json(result);
- })
- ;
+ });
}
catch (IOException e)
{
@@ -147,9 +143,9 @@ namespace Tgstation.Server.Host.Controllers
AdditionalData = e.Message,
});
}
- catch (NotImplementedException)
+ catch (NotImplementedException ex)
{
- return RequiresPosixSystemIdentity();
+ return RequiresPosixSystemIdentity(ex);
}
}
@@ -184,8 +180,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(this.Gone());
@@ -194,10 +189,10 @@ namespace Tgstation.Server.Host.Controllers
.AsQueryable()
.OrderBy(x => x.Path));
}
- catch (NotImplementedException)
+ catch (NotImplementedException ex)
{
return new PaginatableResult(
- RequiresPosixSystemIdentity());
+ RequiresPosixSystemIdentity(ex));
}
catch (UnauthorizedAccessException)
{
@@ -258,8 +253,7 @@ namespace Tgstation.Server.Host.Controllers
.Configuration
.CreateDirectory(model.Path, systemIdentity, cancellationToken)
? Json(resultModel)
- : Created(resultModel))
- ;
+ : Created(resultModel));
}
catch (IOException e)
{
@@ -269,9 +263,9 @@ namespace Tgstation.Server.Host.Controllers
Message = e.Message,
});
}
- catch (NotImplementedException)
+ catch (NotImplementedException ex)
{
- return RequiresPosixSystemIdentity();
+ return RequiresPosixSystemIdentity(ex);
}
catch (UnauthorizedAccessException)
{
@@ -309,9 +303,9 @@ namespace Tgstation.Server.Host.Controllers
? NoContent()
: Conflict(new ErrorMessageResponse(ErrorCode.ConfigurationDirectoryNotEmpty)));
}
- catch (NotImplementedException)
+ catch (NotImplementedException ex)
{
- return RequiresPosixSystemIdentity();
+ return RequiresPosixSystemIdentity(ex);
}
catch (UnauthorizedAccessException)
{
diff --git a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs
index 7f82032066..0b57cbc87e 100644
--- a/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs
+++ b/src/Tgstation.Server.Host/Controllers/DreamDaemonController.cs
@@ -95,8 +95,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());
});
@@ -242,8 +241,7 @@ namespace Tgstation.Server.Host.Controllers
await watchdog.ResetRebootState(cancellationToken);
return await ReadImpl(current, cancellationToken);
- })
- ;
+ });
}
#pragma warning restore CA1506
#pragma warning restore CA1502
@@ -277,8 +275,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());
});
@@ -311,8 +308,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());
});
@@ -337,8 +333,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 this.Gone();
}
diff --git a/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs b/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs
index 6709e60929..fb0c805f40 100644
--- a/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs
+++ b/src/Tgstation.Server.Host/Controllers/DreamMakerController.cs
@@ -80,8 +80,7 @@ namespace Tgstation.Server.Host.Controllers
.DreamMakerSettings
.AsQueryable()
.Where(x => x.InstanceId == Instance.Id)
- .FirstOrDefaultAsync(cancellationToken)
- ;
+ .FirstOrDefaultAsync(cancellationToken);
return Json(dreamMakerSettings.ToApi());
}
@@ -153,8 +152,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());
}
@@ -189,8 +187,7 @@ namespace Tgstation.Server.Host.Controllers
.DreamMakerSettings
.AsQueryable()
.Where(x => x.InstanceId == Instance.Id)
- .FirstOrDefaultAsync(cancellationToken)
- ;
+ .FirstOrDefaultAsync(cancellationToken);
if (hostModel == null)
return this.Gone();
@@ -215,8 +212,7 @@ namespace Tgstation.Server.Host.Controllers
.GetAvailablePort(
model.ApiValidationPort.Value,
true,
- cancellationToken)
- ;
+ cancellationToken);
if (verifiedPort != model.ApiValidationPort)
return Conflict(new ErrorMessageResponse(ErrorCode.PortNotAvailable));
diff --git a/src/Tgstation.Server.Host/Controllers/HomeController.cs b/src/Tgstation.Server.Host/Controllers/HomeController.cs
index 1774329e64..a7286839a2 100644
--- a/src/Tgstation.Server.Host/Controllers/HomeController.cs
+++ b/src/Tgstation.Server.Host/Controllers/HomeController.cs
@@ -242,7 +242,7 @@ namespace Tgstation.Server.Host.Controllers
}
catch (NotImplementedException ex)
{
- Logger.LogTrace(ex, "System identities not implemented!");
+ RequiresPosixSystemIdentity(ex);
}
using (systemIdentity)
@@ -298,9 +298,9 @@ namespace Tgstation.Server.Host.Controllers
PasswordHash = x.PasswordHash,
Enabled = x.Enabled,
Name = x.Name,
+ SystemIdentifier = x.SystemIdentifier,
})
- .ToListAsync(cancellationToken)
- ;
+ .ToListAsync(cancellationToken);
// Pick the DB user first
var user = users
@@ -317,13 +317,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 (!cryptographySuite.CheckUserPassword(user, ApiHeaders.Password))
+ if (!isLikelyDbUser || !cryptographySuite.CheckUserPassword(user, ApiHeaders.Password))
return Unauthorized();
if (user.PasswordHash != originalHash)
{
@@ -337,14 +337,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
diff --git a/src/Tgstation.Server.Host/Controllers/InstanceController.cs b/src/Tgstation.Server.Host/Controllers/InstanceController.cs
index 443eec1021..ca248ef1cb 100644
--- a/src/Tgstation.Server.Host/Controllers/InstanceController.cs
+++ b/src/Tgstation.Server.Host/Controllers/InstanceController.cs
@@ -183,8 +183,7 @@ namespace Tgstation.Server.Host.Controllers
if (earlyOut != null && !newCancellationToken.IsCancellationRequested)
cts.Cancel();
},
- newCancellationToken)
- ;
+ newCancellationToken);
}
catch (OperationCanceledException)
{
@@ -420,8 +419,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));
@@ -487,8 +485,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();
}
@@ -549,8 +546,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(
@@ -566,8 +562,7 @@ namespace Tgstation.Server.Host.Controllers
},
page,
pageSize,
- cancellationToken)
- ;
+ cancellationToken);
if (needsUpdate)
await DatabaseContext.Save(cancellationToken);
@@ -626,8 +621,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);
@@ -655,14 +649,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 this.Gone();
@@ -701,8 +693,7 @@ namespace Tgstation.Server.Host.Controllers
.GetAvailablePort(
Math.Min((ushort)(ddPort.Value + 1), DefaultApiValidationPort),
false,
- cancellationToken)
- ;
+ cancellationToken);
if (!dmPort.HasValue)
return null;
diff --git a/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs b/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs
index b8fafa0466..da32651a38 100644
--- a/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs
+++ b/src/Tgstation.Server.Host/Controllers/InstancePermissionSetController.cs
@@ -74,8 +74,7 @@ namespace Tgstation.Server.Host.Controllers
{
UserId = x.UserId,
})
- .FirstOrDefaultAsync(cancellationToken)
- ;
+ .FirstOrDefaultAsync(cancellationToken);
if (existingPermissionSet == default)
return this.Gone();
@@ -87,8 +86,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();
@@ -138,8 +136,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 this.Gone();
@@ -220,8 +217,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 this.Gone();
return Json(permissionSet.ToApi());
@@ -247,8 +243,8 @@ 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() : this.Gone();
}
}
diff --git a/src/Tgstation.Server.Host/Controllers/JobController.cs b/src/Tgstation.Server.Host/Controllers/JobController.cs
index 2c92b651dd..77f1221b51 100644
--- a/src/Tgstation.Server.Host/Controllers/JobController.cs
+++ b/src/Tgstation.Server.Host/Controllers/JobController.cs
@@ -128,8 +128,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();
@@ -163,8 +162,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();
diff --git a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs
index 5e99aff62e..b27d45530f 100644
--- a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs
+++ b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs
@@ -104,8 +104,7 @@ namespace Tgstation.Server.Host.Controllers
.RepositorySettings
.AsQueryable()
.Where(x => x.InstanceId == Instance.Id)
- .FirstOrDefaultAsync(cancellationToken)
- ;
+ .FirstOrDefaultAsync(cancellationToken);
if (currentModel == default)
return this.Gone();
@@ -179,19 +178,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);
- })
- ;
+ });
}
///
@@ -211,8 +207,7 @@ namespace Tgstation.Server.Host.Controllers
.RepositorySettings
.AsQueryable()
.Where(x => x.InstanceId == Instance.Id)
- .FirstOrDefaultAsync(cancellationToken)
- ;
+ .FirstOrDefaultAsync(cancellationToken);
if (currentModel == default)
return this.Gone();
@@ -234,8 +229,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);
}
@@ -259,8 +253,7 @@ namespace Tgstation.Server.Host.Controllers
.RepositorySettings
.AsQueryable()
.Where(x => x.InstanceId == Instance.Id)
- .FirstOrDefaultAsync(cancellationToken)
- ;
+ .FirstOrDefaultAsync(cancellationToken);
if (currentModel == default)
return this.Gone();
@@ -287,8 +280,7 @@ namespace Tgstation.Server.Host.Controllers
}
return Json(api);
- })
- ;
+ });
}
///
@@ -348,8 +340,7 @@ namespace Tgstation.Server.Host.Controllers
.RepositorySettings
.AsQueryable()
.Where(x => x.InstanceId == Instance.Id)
- .FirstOrDefaultAsync(cancellationToken)
- ;
+ .FirstOrDefaultAsync(cancellationToken);
if (currentModel == default)
return this.Gone();
@@ -413,8 +404,7 @@ namespace Tgstation.Server.Host.Controllers
await PopulateApi(api, repo, DatabaseContext, Instance, cancellationToken);
return null;
- })
- ;
+ });
if (earlyOut != null)
return earlyOut;
diff --git a/src/Tgstation.Server.Host/Controllers/UserController.cs b/src/Tgstation.Server.Host/Controllers/UserController.cs
index a2dc87f763..4dd7f7b0fc 100644
--- a/src/Tgstation.Server.Host/Controllers/UserController.cs
+++ b/src/Tgstation.Server.Host/Controllers/UserController.cs
@@ -128,9 +128,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))
{
@@ -145,7 +145,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());
}
@@ -196,8 +196,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();
@@ -216,12 +215,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);
@@ -266,8 +274,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 this.Gone();
@@ -409,8 +416,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
{
diff --git a/src/Tgstation.Server.Host/Controllers/UserGroupController.cs b/src/Tgstation.Server.Host/Controllers/UserGroupController.cs
index b3670eb668..743edcf2a5 100644
--- a/src/Tgstation.Server.Host/Controllers/UserGroupController.cs
+++ b/src/Tgstation.Server.Host/Controllers/UserGroupController.cs
@@ -76,8 +76,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));
@@ -122,8 +121,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 this.Gone();
@@ -168,8 +166,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 this.Gone();
return Json(group.ToApi(true));
@@ -221,8 +218,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();
@@ -232,8 +228,7 @@ namespace Tgstation.Server.Host.Controllers
.Groups
.AsQueryable()
.Where(x => x.Id == id)
- .AnyAsync(cancellationToken)
- ;
+ .AnyAsync(cancellationToken);
return groupExists
? Conflict(new ErrorMessageResponse(ErrorCode.UserGroupNotEmpty))
diff --git a/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs b/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs
index b0dd4eb436..66e74968e0 100644
--- a/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs
+++ b/src/Tgstation.Server.Host/Database/DatabaseSeeder.cs
@@ -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);
diff --git a/src/Tgstation.Server.Host/Extensions/TaskExtensions.cs b/src/Tgstation.Server.Host/Extensions/TaskExtensions.cs
index a8ee467d1e..bd65a629d9 100644
--- a/src/Tgstation.Server.Host/Extensions/TaskExtensions.cs
+++ b/src/Tgstation.Server.Host/Extensions/TaskExtensions.cs
@@ -14,6 +14,11 @@ namespace Tgstation.Server.Host.Extensions
///
static readonly TaskCompletionSource InfiniteTaskCompletionSource = new ();
+ ///
+ /// Gets a that never completes.
+ ///
+ public static Task InfiniteTask => InfiniteTaskCompletionSource.Task;
+
///
/// Create a that can be awaited while respecting a given .
///
@@ -53,11 +58,5 @@ namespace Tgstation.Server.Host.Extensions
return await task;
}
-
- ///
- /// Creates a that never completes.
- ///
- /// A never ending .
- public static Task InfiniteTask() => InfiniteTaskCompletionSource.Task;
}
}
diff --git a/src/Tgstation.Server.Host/Jobs/JobHandler.cs b/src/Tgstation.Server.Host/Jobs/JobHandler.cs
index 19941fbefd..98cbe88651 100644
--- a/src/Tgstation.Server.Host/Jobs/JobHandler.cs
+++ b/src/Tgstation.Server.Host/Jobs/JobHandler.cs
@@ -11,6 +11,21 @@ namespace Tgstation.Server.Host.Jobs
///
sealed class JobHandler : IDisposable
{
+ ///
+ /// If the job has started.
+ ///
+ public bool Started => task != null;
+
+ ///
+ /// The progress of the job.
+ ///
+ public int? Progress { get; set; }
+
+ ///
+ /// The stage of the job.
+ ///
+ public string Stage { get; set; }
+
///
/// The for .
///
@@ -39,16 +54,6 @@ namespace Tgstation.Server.Host.Jobs
///
public void Dispose() => cancellationTokenSource.Dispose();
- ///
- /// The progress of the job.
- ///
- public int? Progress { get; set; }
-
- ///
- /// The stage of the job.
- ///
- public string Stage { get; set; }
-
///
/// Wait for to complete.
///
diff --git a/src/Tgstation.Server.Host/Jobs/JobService.cs b/src/Tgstation.Server.Host/Jobs/JobService.cs
index c0d01f2dcf..efa0b09137 100644
--- a/src/Tgstation.Server.Host/Jobs/JobService.cs
+++ b/src/Tgstation.Server.Host/Jobs/JobService.cs
@@ -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
{
@@ -256,13 +255,23 @@ namespace Tgstation.Server.Host.Jobs
{
if (job == null)
throw new ArgumentNullException(nameof(job));
+
+ if (!cancellationToken.CanBeCanceled)
+ throw new ArgumentException("A cancellable CancellationToken should be provided!", nameof(cancellationToken));
+
JobHandler handler;
+ bool noMoreJobsShouldStart;
lock (synchronizationLock)
{
if (!jobs.TryGetValue(job.Id.Value, out handler))
return;
+
+ noMoreJobsShouldStart = this.noMoreJobsShouldStart;
}
+ if (noMoreJobsShouldStart && !handler.Started)
+ await Extensions.TaskExtensions.InfiniteTask.WithToken(cancellationToken);
+
Task cancelTask = null;
using (jobCancellationToken.Register(() => cancelTask = CancelJob(job, canceller, true, cancellationToken)))
await handler.Wait(cancellationToken);
diff --git a/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs b/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs
index c28d1e1da1..24ab9707ea 100644
--- a/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs
+++ b/src/Tgstation.Server.Host/Security/AuthenticationContextFactory.cs
@@ -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);
diff --git a/src/Tgstation.Server.Host/Security/ClaimsInjector.cs b/src/Tgstation.Server.Host/Security/ClaimsInjector.cs
index 933e073ec0..de5dacc66e 100644
--- a/src/Tgstation.Server.Host/Security/ClaimsInjector.cs
+++ b/src/Tgstation.Server.Host/Security/ClaimsInjector.cs
@@ -68,8 +68,7 @@ namespace Tgstation.Server.Host.Security
userId,
apiHeaders.InstanceId,
tokenValidatedContext.SecurityToken.ValidFrom,
- cancellationToken)
- ;
+ cancellationToken);
var authenticationContext = authenticationContextFactory.CurrentAuthenticationContext;
diff --git a/src/Tgstation.Server.Host/Security/CryptographySuite.cs b/src/Tgstation.Server.Host/Security/CryptographySuite.cs
index 27a780453e..21051e2163 100644
--- a/src/Tgstation.Server.Host/Security/CryptographySuite.cs
+++ b/src/Tgstation.Server.Host/Security/CryptographySuite.cs
@@ -54,6 +54,11 @@ namespace Tgstation.Server.Host.Security
///
public bool CheckUserPassword(User user, string password)
{
+ if (user == null)
+ throw new ArgumentNullException(nameof(user));
+ if (password == null)
+ throw new ArgumentNullException(nameof(password));
+
var result = passwordHasher.VerifyHashedPassword(user, user.PasswordHash, password);
switch (result)
{
diff --git a/src/Tgstation.Server.Host/Security/WindowsSystemIdentityFactory.cs b/src/Tgstation.Server.Host/Security/WindowsSystemIdentityFactory.cs
index 3646d71cd1..47ec0f3e3d 100644
--- a/src/Tgstation.Server.Host/Security/WindowsSystemIdentityFactory.cs
+++ b/src/Tgstation.Server.Host/Security/WindowsSystemIdentityFactory.cs
@@ -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
{
diff --git a/src/Tgstation.Server.Host/Setup/SetupWizard.cs b/src/Tgstation.Server.Host/Setup/SetupWizard.cs
index 629dbf0a41..c4633f0846 100644
--- a/src/Tgstation.Server.Host/Setup/SetupWizard.cs
+++ b/src/Tgstation.Server.Host/Setup/SetupWizard.cs
@@ -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(databaseTypeString, out var databaseType))
return databaseType;
@@ -1007,8 +1000,7 @@ namespace Tgstation.Server.Host.Setup
elasticSearchConfiguration,
controlPanelConfiguration,
swarmConfiguration,
- cancellationToken)
- ;
+ cancellationToken);
}
///
diff --git a/src/Tgstation.Server.Host/Swarm/SwarmService.cs b/src/Tgstation.Server.Host/Swarm/SwarmService.cs
index 266d45e245..a993689f00 100644
--- a/src/Tgstation.Server.Host/Swarm/SwarmService.cs
+++ b/src/Tgstation.Server.Host/Swarm/SwarmService.cs
@@ -380,7 +380,7 @@ namespace Tgstation.Server.Host.Swarm
? asyncDelayer.Delay(
TimeSpan.FromMinutes(UpdateCommitTimeoutMinutes),
cancellationToken)
- : Extensions.TaskExtensions.InfiniteTask().WithToken(cancellationToken);
+ : Extensions.TaskExtensions.InfiniteTask.WithToken(cancellationToken);
var commitTask = Task.WhenAny(commitTcsTask, timeoutTask);
@@ -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)
diff --git a/src/Tgstation.Server.Host/Utils/PortAllocator.cs b/src/Tgstation.Server.Host/Utils/PortAllocator.cs
index 87ac3ecd05..9b125103d0 100644
--- a/src/Tgstation.Server.Host/Utils/PortAllocator.cs
+++ b/src/Tgstation.Server.Host/Utils/PortAllocator.cs
@@ -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();
ushort port = 0;
diff --git a/tests/Tgstation.Server.Tests/Live/Instance/RepositoryTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/RepositoryTest.cs
index c35ccd70dd..05f3b90ec2 100644
--- a/tests/Tgstation.Server.Tests/Live/Instance/RepositoryTest.cs
+++ b/tests/Tgstation.Server.Tests/Live/Instance/RepositoryTest.cs
@@ -59,8 +59,8 @@ namespace Tgstation.Server.Tests.Live.Instance
if (!targetActiveJob.Progress.HasValue)
{
- // give it 15 more seconds
- targetActiveJob = await WaitForJobProgress(targetActiveJob, 15, cancellationToken);
+ // give it a few more seconds
+ targetActiveJob = await WaitForJobProgress(targetActiveJob, 30, cancellationToken);
allJobs = await JobsClient.List(null, cancellationToken);
}
diff --git a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs
index 5745c0d21f..275e47e765 100644
--- a/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs
+++ b/tests/Tgstation.Server.Tests/Live/Instance/WatchdogTest.cs
@@ -224,29 +224,47 @@ 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.")
+ || job.ExceptionDetails.Contains("BetterWin32Errors.Win32Exception: 2147942424: The program issued a command but the command length is incorrect."))))
+ break;
+
+ var restartJob = await instanceClient.DreamDaemon.Restart(cancellationToken);
+ await WaitForJob(restartJob, 20, false, null, cancellationToken);
}
+
Assert.IsTrue(job.ErrorCode == ErrorCode.DreamDaemonOffline || job.ErrorCode == ErrorCode.GCoreFailure, $"{job.ErrorCode}: {job.ExceptionDetails}");
+
await Task.Delay(TimeSpan.FromSeconds(20), cancellationToken);
var ddStatus = await instanceClient.DreamDaemon.Read(cancellationToken);
@@ -543,7 +561,7 @@ namespace Tgstation.Server.Tests.Live.Instance
TopicResponse topicRequestResult = null;
try
{
- System.Console.WriteLine($"Topic limit test S:{payloadSize}...");
+ System.Console.WriteLine($"Topic send limit test S:{currentSize}...");
topicRequestResult = await TopicClientNoLogger.SendTopic(
IPAddress.Loopback,
$"tgs_integration_test_tactics3={TopicClient.SanitizeString(JsonConvert.SerializeObject(topic, DMApiConstants.SerializerSettings))}",
@@ -575,6 +593,8 @@ namespace Tgstation.Server.Tests.Live.Instance
Assert.AreEqual(DMApiConstants.MaximumTopicRequestLength, (uint)lastSize);
+ System.Console.WriteLine("TEST: Receiving Topic tests topics...");
+
// Receive
baseSize = 1;
nextPow = 0;
@@ -582,6 +602,7 @@ namespace Tgstation.Server.Tests.Live.Instance
while (!cancellationToken.IsCancellationRequested)
{
var currentSize = baseSize + (int)Math.Pow(2, nextPow);
+ System.Console.WriteLine($"Topic recieve limit test S:{currentSize}...");
var topicRequestResult = await TopicClientNoLogger.SendTopic(
IPAddress.Loopback,
$"tgs_integration_test_tactics4={TopicClient.SanitizeString(currentSize.ToString())}",