Browse Source

Implemented dynamic CSP and added nonces to all inline script tags, and fixed inline js.

tags/3.0.0
Teknikode 1 year ago
parent
commit
37424956db
49 changed files with 296 additions and 128 deletions
  1. 4
    2
      Teknik/App_Data/robots.txt
  2. 1
    1
      Teknik/App_Start/BundleConfig.cs
  3. 3
    3
      Teknik/Areas/Admin/Views/Admin/UploadResult.cshtml
  4. 3
    3
      Teknik/Areas/Admin/Views/Admin/UploadSearch.cshtml
  5. 1
    1
      Teknik/Areas/Admin/Views/Admin/UserInfo.cshtml
  6. 1
    1
      Teknik/Areas/Admin/Views/Admin/UserSearch.cshtml
  7. 4
    4
      Teknik/Areas/Blog/Views/Blog/Blog.cshtml
  8. 3
    3
      Teknik/Areas/Blog/Views/Blog/EditPost.cshtml
  9. 3
    3
      Teknik/Areas/Blog/Views/Blog/NewPost.cshtml
  10. 4
    4
      Teknik/Areas/Blog/Views/Blog/ViewPost.cshtml
  11. 1
    1
      Teknik/Areas/Error/Views/Error/Exception.cshtml
  12. 1
    1
      Teknik/Areas/Error/Views/Error/Http500.cshtml
  13. 3
    3
      Teknik/Areas/Paste/Views/Paste/Full.cshtml
  14. 3
    3
      Teknik/Areas/Paste/Views/Paste/Index.cshtml
  15. 5
    3
      Teknik/Areas/Paste/Views/Paste/Simple.cshtml
  16. 3
    3
      Teknik/Areas/Podcast/Views/Podcast/Main.cshtml
  17. 3
    3
      Teknik/Areas/Podcast/Views/Podcast/ViewPodcast.cshtml
  18. 2
    2
      Teknik/Areas/Status/Views/Status/Index.cshtml
  19. 3
    3
      Teknik/Areas/Upload/Scripts/EncryptionWorker.js
  20. 18
    2
      Teknik/Areas/Upload/Scripts/Upload.js
  21. 2
    2
      Teknik/Areas/Upload/Views/Upload/Download.cshtml
  22. 3
    3
      Teknik/Areas/Upload/Views/Upload/Index.cshtml
  23. 19
    7
      Teknik/Areas/User/Scripts/InviteSettings.js
  24. 4
    0
      Teknik/Areas/User/Scripts/Profile.js
  25. 34
    3
      Teknik/Areas/User/Scripts/SecuritySettings.js
  26. 3
    3
      Teknik/Areas/User/Views/User/Settings/AuthToken.cshtml
  27. 1
    1
      Teknik/Areas/User/Views/User/Settings/BlogSettings.cshtml
  28. 2
    2
      Teknik/Areas/User/Views/User/Settings/InviteCode.cshtml
  29. 1
    1
      Teknik/Areas/User/Views/User/Settings/InviteSettings.cshtml
  30. 1
    1
      Teknik/Areas/User/Views/User/Settings/ProfileSettings.cshtml
  31. 1
    1
      Teknik/Areas/User/Views/User/Settings/SecuritySettings.cshtml
  32. 1
    1
      Teknik/Areas/User/Views/User/Settings/Settings.cshtml
  33. 1
    1
      Teknik/Areas/User/Views/User/Settings/UploadSettings.cshtml
  34. 3
    3
      Teknik/Areas/User/Views/User/TwoFactorCheck.cshtml
  35. 2
    2
      Teknik/Areas/User/Views/User/ViewProfile.cshtml
  36. 2
    2
      Teknik/Areas/Vault/Views/Vault/ModifyVault.cshtml
  37. 4
    3
      Teknik/Areas/Vault/Views/Vault/ModifyVaultItem.cshtml
  38. 3
    3
      Teknik/Areas/Vault/Views/Vault/ViewVault.cshtml
  39. 6
    9
      Teknik/Global.asax.cs
  40. 45
    0
      Teknik/Modules/CORSModule.cs
  41. 49
    0
      Teknik/Modules/CSPModule.cs
  42. 3
    2
      Teknik/Modules/PerformanceMonitorModule.cs
  43. 5
    1
      Teknik/Scripts/common.js
  44. 2
    0
      Teknik/Teknik.csproj
  45. 1
    1
      Teknik/Views/Shared/_Footer.cshtml
  46. 2
    2
      Teknik/Views/Shared/_Layout.cshtml
  47. 17
    12
      Teknik/Web.config
  48. 5
    12
      Utilities/Utilities/BundleExtensions.cs
  49. 5
    1
      Utilities/Utilities/Constants.cs

+ 4
- 2
Teknik/App_Data/robots.txt View File

@@ -1,2 +1,4 @@
User-agent: *
Disallow: /
User-agent: *
Disallow: /Content/
Disallow: /Scripts/
Disallow: /Images/

+ 1
- 1
Teknik/App_Start/BundleConfig.cs View File

@@ -1,4 +1,4 @@
using System.Web;
using System.Web;
using System.Web.Optimization;
using Teknik.Configuration;
using Teknik.Utilities;

+ 3
- 3
Teknik/Areas/Admin/Views/Admin/UploadResult.cshtml View File

@@ -1,4 +1,4 @@
@model Teknik.Areas.Admin.ViewModels.UploadResultViewModel
@model Teknik.Areas.Admin.ViewModels.UploadResultViewModel

@using Teknik.Utilities

@@ -23,11 +23,11 @@
<label for="downloads">Downloads</label>
<p id="downloads">@Model.Downloads</p>
</div>
<div class="col-sm-2 text-center" style="overflow-x: hidden">
<div class="col-sm-2 text-center">
@{
string deleteUrl = (string.IsNullOrEmpty(Model.DeleteKey)) ? string.Empty : Url.SubRouteUrl("u", "Upload.Delete", new { file = Model.Url, key = Model.DeleteKey });
}
<p id="delete-upload"><button role="button" class="btn btn-danger delete-upload-button" id="@deleteUrl" data-upload-id="@Model.Url">Delete</button></p>
</div>
</div>
</div>
</div>

+ 3
- 3
Teknik/Areas/Admin/Views/Admin/UploadSearch.cshtml View File

@@ -1,8 +1,8 @@
@model Teknik.Areas.Admin.ViewModels.UploadSearchViewModel
@model Teknik.Areas.Admin.ViewModels.UploadSearchViewModel

@using Teknik.Utilities

<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
// We need to define the action URLs for the script
var searchResultsURL = '@Url.SubRouteUrl("admin", "Admin.Action", new { action = "GetUploadSearchResults" })';
var generateDeleteKeyURL = '@Url.SubRouteUrl("u", "Upload.GenerateDeleteKey")';
@@ -25,4 +25,4 @@
<div class="results" id="results"></div>
</div>
</div>
</div>
</div>

+ 1
- 1
Teknik/Areas/Admin/Views/Admin/UserInfo.cshtml View File

@@ -2,7 +2,7 @@

@using Teknik.Utilities

<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
// We need to define the action URLs for the script
var homeUrl = '@Url.SubRouteUrl("admin", "Admin.UserSearch")';
var deleteUserURL = '@Url.SubRouteUrl("admin", "Admin.Action", new { action = "DeleteAccount" })';

+ 1
- 1
Teknik/Areas/Admin/Views/Admin/UserSearch.cshtml View File

@@ -2,7 +2,7 @@

@using Teknik.Utilities

<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
// We need to define the action URLs for the script
var userSearchResultsURL = '@Url.SubRouteUrl("admin", "Admin.Action", new { action = "GetUserSearchResults" })';
</script>

+ 4
- 4
Teknik/Areas/Blog/Views/Blog/Blog.cshtml View File

@@ -1,8 +1,8 @@
@model Teknik.Areas.Blog.ViewModels.BlogViewModel
@model Teknik.Areas.Blog.ViewModels.BlogViewModel

@using Teknik.Utilities

<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
// We need to define the action URLs for the script
var uploadURL = '@Url.SubRouteUrl("upload", "Upload.Upload")';
var helpURL = '@Url.SubRouteUrl("help", "Help.Markdown")';
@@ -49,7 +49,7 @@
if (Model.HasPosts)
{
<div class="blog-main" id="@Model.BlogId"></div>
<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
var posts = @Model.Config.BlogConfig.PostsToLoad;
var start_post = 0;
loadMorePosts(start_post, posts);
@@ -73,4 +73,4 @@
</div>
</div>
}
</div>
</div>

+ 3
- 3
Teknik/Areas/Blog/Views/Blog/EditPost.cshtml View File

@@ -1,8 +1,8 @@
@model Teknik.Areas.Blog.ViewModels.PostViewModel
@model Teknik.Areas.Blog.ViewModels.PostViewModel

@using Teknik.Utilities

<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
// We need to define the action URLs for the script
var helpURL = '@Url.SubRouteUrl("help", "Help.Markdown")';
</script>
@@ -56,4 +56,4 @@
</div>
</div>
</form>
</div>
</div>

+ 3
- 3
Teknik/Areas/Blog/Views/Blog/NewPost.cshtml View File

@@ -1,8 +1,8 @@
@model Teknik.Areas.Blog.ViewModels.BlogViewModel
@model Teknik.Areas.Blog.ViewModels.BlogViewModel

@using Teknik.Utilities

<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
// We need to define the action URLs for the script
var helpURL = '@Url.SubRouteUrl("help", "Help.Markdown")';
</script>
@@ -56,4 +56,4 @@
</div>
</div>
</form>
</div>
</div>

+ 4
- 4
Teknik/Areas/Blog/Views/Blog/ViewPost.cshtml View File

@@ -1,8 +1,8 @@
@model Teknik.Areas.Blog.ViewModels.PostViewModel
@model Teknik.Areas.Blog.ViewModels.PostViewModel

@using Teknik.Utilities

<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
// We need to define the action URLs for the script
var uploadURL = '@Url.SubRouteUrl("upload", "Upload.Upload")';
var helpURL = '@Url.SubRouteUrl("help", "Help.Markdown")';
@@ -92,7 +92,7 @@
}
<a name="replies"></a>
<div class="post-comments" id="@Model.PostId"></div>
<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
linkPostDelete('.delete_post');
linkPostPublish('.publish_post');
linkPostUnpublish('.unpublish_post');
@@ -112,4 +112,4 @@ else
</div>
</div>
}
</div>
</div>

+ 1
- 1
Teknik/Areas/Error/Views/Error/Exception.cshtml View File

@@ -3,7 +3,7 @@
@using Teknik.Utilities

@Scripts.Render("~/bundles/error")
<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
var submitErrorReportURL = '@Url.SubRouteUrl("error", "Error.Action", new { action = "SubmitErrorReport" })';
</script>


+ 1
- 1
Teknik/Areas/Error/Views/Error/Http500.cshtml View File

@@ -3,7 +3,7 @@
@using Teknik.Utilities

@Scripts.Render("~/bundles/error")
<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
var submitErrorReportURL = '@Url.SubRouteUrl("error", "Error.Action", new { action = "SubmitErrorReport" })';
</script>


+ 3
- 3
Teknik/Areas/Paste/Views/Paste/Full.cshtml View File

@@ -1,11 +1,11 @@
@model Teknik.Areas.Paste.ViewModels.PasteViewModel
@model Teknik.Areas.Paste.ViewModels.PasteViewModel

@using Teknik.Utilities
@using Teknik.Areas.Vault.Models

@Styles.Render("~/Content/paste")

<script type="text/javascript">
<script nonce="@Context.Items[Constants.NONCE_KEY]">
var createVaultURL = '@Url.SubRouteUrl("vault", "Vault.NewVaultFromService", new { type = "Paste" })';
</script>

@@ -42,4 +42,4 @@
</div>
</div>

@Scripts.Render("~/bundles/paste")
@Scripts.Render("~/bundles/paste")

+ 3
- 3
Teknik/Areas/Paste/Views/Paste/Index.cshtml View File

@@ -1,4 +1,4 @@
@model Teknik.Areas.Paste.ViewModels.PasteCreateViewModel
@model Teknik.Areas.Paste.ViewModels.PasteCreateViewModel

@using Teknik.Utilities
@using Teknik.Pygments
@@ -83,7 +83,7 @@
</div>
</div>

<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
$("select[name='ExpireUnit']").change(function () {
if ($(this).val() == "never") {
$('#length-div').addClass("hidden");
@@ -96,4 +96,4 @@
$('#unit-div').addClass("col-sm-2");
}
});
</script>
</script>

+ 5
- 3
Teknik/Areas/Paste/Views/Paste/Simple.cshtml View File

@@ -1,4 +1,6 @@
@model Teknik.Areas.Paste.ViewModels.PasteViewModel
@model Teknik.Areas.Paste.ViewModels.PasteViewModel
@using Teknik.Utilities

@{
Layout = "";
string syntax = string.Empty;
@@ -24,8 +26,8 @@
</head>
<body data-twttr-rendered="true">
@Html.Raw(Model.Content)
<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
function pageloadStopTimer() { }
</script>
</body>
</html>
</html>

+ 3
- 3
Teknik/Areas/Podcast/Views/Podcast/Main.cshtml View File

@@ -1,8 +1,8 @@
@model Teknik.Areas.Podcast.ViewModels.MainViewModel
@model Teknik.Areas.Podcast.ViewModels.MainViewModel

@using Teknik.Utilities

<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
// We need to define the action URLs for the script

var uploadURL = '@Url.SubRouteUrl("upload", "Upload.Upload")';
@@ -146,7 +146,7 @@
@if (!Model.Error)
{
<div class="podcast-main"></div>
<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
var podcasts = @Model.Config.PodcastConfig.PodcastsToLoad;
var startPodcast = 0;
loadMorePodcasts(startPodcast, podcasts);

+ 3
- 3
Teknik/Areas/Podcast/Views/Podcast/ViewPodcast.cshtml View File

@@ -1,8 +1,8 @@
@model Teknik.Areas.Podcast.ViewModels.PodcastViewModel
@model Teknik.Areas.Podcast.ViewModels.PodcastViewModel

@using Teknik.Utilities
<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
// We need to define the action URLs for the script

var uploadURL = '@Url.SubRouteUrl("upload", "Upload.Upload")';
@@ -144,7 +144,7 @@
}
<a name="replies"></a>
<div class="post-comments" id="@Model.PodcastId"></div>
<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
var comments = @Model.Config.PodcastConfig.CommentsToLoad;
var startComment = 0;
loadMoreComments(startComment, comments);

+ 2
- 2
Teknik/Areas/Status/Views/Status/Index.cshtml View File

@@ -1,4 +1,4 @@
@model Teknik.Areas.Status.ViewModels.StatusViewModel
@model Teknik.Areas.Status.ViewModels.StatusViewModel

@using Teknik.Utilities
@using Teknik.Areas.Status.Models
@@ -7,7 +7,7 @@
@Scripts.Render("~/signalr/hubs")
@Scripts.Render("~/bundles/status")

<script type="text/javascript">
<script nonce="@Context.Items[Constants.NONCE_KEY]">
var getVisitorDataURL = '@Url.SubRouteUrl("status", "Status.Action", new { action = "GetVisitorData" })';
var showWebCPU = @Model.Config.StatusConfig.ShowWebStatus.ToString().ToLower();
var showDatabaseCPU = @Model.Config.StatusConfig.ShowDatabaseStatus.ToString().ToLower();

+ 3
- 3
Teknik/Areas/Upload/Scripts/EncryptionWorker.js View File

@@ -1,4 +1,4 @@
self.addEventListener('message', function (e) {
self.addEventListener('message', function (e) {
importScripts(e.data.script);
var bytes = new Uint8Array(e.data.file);

@@ -33,7 +33,7 @@
var curBytes = bytes.subarray(startByte, endByte);

//var b64encoded = btoa(String.fromCharCode.apply(null, curBytes));
var wordArray = CryptoJS.lib.WordArray.create(curBytes)
var wordArray = CryptoJS.lib.WordArray.create(curBytes);

// encrypt the passed in file data
var enc = aesCrypto.process(wordArray);
@@ -112,4 +112,4 @@ function Uint8Concat(first, second) {
result.set(second, firstLength);

return result;
}
}

+ 18
- 2
Teknik/Areas/Upload/Scripts/Upload.js View File

@@ -2,6 +2,15 @@ $(document).ready(function () {
$("#upload-links").css('display', 'none', 'important');
$("#upload-links").html('');

$('[data-toggle="popover"]').popover();

$('[data-toggle="popover"]').on('shown.bs.popover', function () {
var $this = $(this);
setTimeout(function () {
$this.popover('hide');
}, 3000);
});

$("[name='encrypt']").bootstrapSwitch();

linkCopyAll($('#copy-all'));
@@ -14,9 +23,15 @@ $(document).ready(function () {

function linkUploadDelete(element, deleteUrl) {
element.click(function () {
bootbox.dialog({
var dialog = bootbox.dialog({
title: "Direct Deletion URL",
message: '<input type="text" class="form-control" id="deletionLink" onClick="this.select();" value="' + deleteUrl + '">'
message: '<input type="text" class="form-control" id="deletionLink" value="' + deleteUrl + '">'
});

dialog.init(function() {
dialog.find('#deletionLink').click(function() {
$(this).select();
});
});
return false;
});
@@ -76,6 +91,7 @@ function linkCopyAll(element) {
var urlList = allUploads.join();
copyTextToClipboard(urlList);
}
element.popover('show');
});
}


+ 2
- 2
Teknik/Areas/Upload/Views/Upload/Download.cshtml View File

@@ -1,8 +1,8 @@
@model Teknik.Areas.Upload.ViewModels.DownloadViewModel
@model Teknik.Areas.Upload.ViewModels.DownloadViewModel

@using Teknik.Utilities

<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
var encScriptSrc = '@Scripts.Url("~/bundles/cryptoWorker")';
var aesScriptSrc = '@Scripts.Url("~/bundles/crypto")';
var downloadDataUrl = '@Url.SubRouteUrl("upload", "Upload.Action", new { action = "DownloadData" })';

+ 3
- 3
Teknik/Areas/Upload/Views/Upload/Index.cshtml View File

@@ -1,4 +1,4 @@
@model Teknik.Areas.Upload.ViewModels.UploadViewModel
@model Teknik.Areas.Upload.ViewModels.UploadViewModel

@using Teknik.Utilities
@using Teknik.Areas.Vault.Models
@@ -15,7 +15,7 @@
}
}

<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
var encScriptSrc = '@Scripts.Url("~/bundles/cryptoWorker")';
var aesScriptSrc = '@Scripts.Url("~/bundles/crypto")';
var uploadFileURL = '@Url.SubRouteUrl(Model.CurrentSub, "Upload.Action", new { action = "Upload" })';
@@ -64,7 +64,7 @@
<div class="row" id="upload-action-buttons" style="display: none">
<div class="col-sm-12">
<div class="btn-group pull-right" role="group">
<button type="button" class="btn btn-default btn-sm" id="copy-all"><i class="fa fa-clipboard"></i>&nbsp;Copy All Links</button>
<button type="button" class="btn btn-default btn-sm" id="copy-all" data-toggle="popover" data-trigger="manual" data-placement="top" data-content="Copied to Clipboard" data-container="body"><i class="fa fa-clipboard"></i>&nbsp;Copy All Links</button>
<button type="button" class="btn btn-default btn-sm" id="create-vault"><i class="fa fa-folder"></i>&nbsp;Create Vault</button>
@if (User.Identity.IsAuthenticated && Model.Vaults != null && Model.Vaults.Any())
{

+ 19
- 7
Teknik/Areas/User/Scripts/InviteSettings.js View File

@@ -7,12 +7,18 @@ $(document).ready(function () {
$this.popover('hide');
}, 3000);
});
});

function copyCode(inviteCodeId, inviteCode) {
copyTextToClipboard(inviteCode);
$('#copyCode_' + inviteCodeId + '').popover('show');
}
$(".copyCodeBtn").click(function () {
var code = $(this).attr("data-code");
copyTextToClipboard(code);
$(this).popover('show');
});

$(".extCodeBtn").click(function () {
var codeId = $(this).attr("data-codeid");
createExternalLink(codeId);
});
});

function createExternalLink(inviteCodeId) {
$.ajax({
@@ -21,9 +27,15 @@ function createExternalLink(inviteCodeId) {
data: AddAntiForgeryToken({ inviteCodeId: inviteCodeId }),
success: function (response) {
if (response.result) {
bootbox.dialog({
var dialog = bootbox.dialog({
title: "Send this link to someone to claim this invite code.",
message: '<input type="text" class="form-control" id="inviteCodeLink" onClick="this.select();" value="' + response.result + '">'
message: '<input type="text" class="form-control" id="inviteCodeLink" value="' + response.result + '">'
});

dialog.init(function () {
dialog.find('#inviteCodeLink').click(function () {
$(this).select();
});
});
}
else {

+ 4
- 0
Teknik/Areas/User/Scripts/Profile.js View File

@@ -58,4 +58,8 @@ $(document).ready(function () {
}
});
});

$('#pgpKeyBlock').click(function () {
SelectAll('pgpKeyBlock');
});
});

+ 34
- 3
Teknik/Areas/User/Scripts/SecuritySettings.js View File

@@ -79,7 +79,7 @@ $(document).ready(function () {
data: AddAntiForgeryToken({ name: result }),
success: function (response) {
if (response.result) {
bootbox.dialog({
var dialog = bootbox.dialog({
closeButton: false,
buttons: {
close: {
@@ -89,12 +89,33 @@ $(document).ready(function () {
if ($('#noAuthTokens')) {
$('#noAuthTokens').remove();
}
$('#authTokenList').append(response.result.html);
var item = $(response.result.html);

var deleteBtn = item.find('.deleteAuthToken');
var editBtn = item.find('.editAuthToken');

deleteBtn.click(function () {
var authTokenId = $(this).attr("data-authid");
deleteAuthToken(authTokenId);
});

editBtn.click(function () {
var authTokenId = $(this).attr("data-authid");
editAuthToken(authTokenId);
});

$('#authTokenList').append(item);
}
}
},
title: "Authentication Token",
message: '<label for="authToken">Make sure to copy your new personal access token now.<br />You won\'t be able to see it again!</label><input type="text" class="form-control" id="authToken" onClick="this.select();" value="' + response.result.token + '">',
message: '<label for="authToken">Make sure to copy your new personal access token now.<br />You won\'t be able to see it again!</label><input type="text" class="form-control" id="authToken" value="' + response.result.token + '">',
});

dialog.init(function () {
dialog.find('#authToken').click(function () {
$(this).select();
});
});
}
else {
@@ -223,6 +244,16 @@ $(document).ready(function () {
});
return false;
});

$(".deleteAuthToken").click(function() {
var authTokenId = $(this).attr("data-authid");
deleteAuthToken(authTokenId);
});

$(".editAuthToken").click(function () {
var authTokenId = $(this).attr("data-authid");
editAuthToken(authTokenId);
});
});

function editAuthToken(authTokenId) {

+ 3
- 3
Teknik/Areas/User/Views/User/Settings/AuthToken.cshtml View File

@@ -1,9 +1,9 @@
@model Teknik.Areas.Users.ViewModels.AuthTokenViewModel
@model Teknik.Areas.Users.ViewModels.AuthTokenViewModel

<li class="list-group-item" id="authToken_@Model.AuthTokenId">
<div class="btn-group btn-group-sm pull-right" role="group" aria-label="...">
<button type="button" class="btn btn-default" onclick="editAuthToken(@Model.AuthTokenId)">Edit</button>
<button type="button" class="btn btn-danger text-danger" onclick="deleteAuthToken(@Model.AuthTokenId)">Delete</button>
<button type="button" class="btn btn-default editAuthToken" id="editAuthToken_@Model.AuthTokenId" data-authId="@Model.AuthTokenId">Edit</button>
<button type="button" class="btn btn-danger text-danger deleteAuthToken" id="deleteAuthToken_@Model.AuthTokenId" data-authId="@Model.AuthTokenId">Delete</button>
</div>
<h4 class="list-group-item-heading" id="authTokenName_@Model.AuthTokenId">@Model.Name</h4>
@if (Model.LastDateUsed.HasValue)

+ 1
- 1
Teknik/Areas/User/Views/User/Settings/BlogSettings.cshtml View File

@@ -7,7 +7,7 @@
Layout = "~/Areas/User/Views/User/Settings/Settings.cshtml";
}

<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
var editURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "EditBlog" })';
</script>


+ 2
- 2
Teknik/Areas/User/Views/User/Settings/InviteCode.cshtml View File

@@ -9,8 +9,8 @@
@if (!codeClaimed)
{
<div class="btn-group btn-group-sm pull-right" role="group" aria-label="...">
<button type="button" class="btn btn-default" id="copyCode_@Model.InviteCodeId" onclick="copyCode(@(Model.InviteCodeId), '@(Model.Code)');" data-toggle="popover" data-trigger="manual" data-placement="top" data-content="Copied to Clipboard" data-container="body"><i class="fa fa-clipboard"></i></button>
<button type="button" class="btn btn-default" onclick="createExternalLink(@Model.InviteCodeId);"><i class="fa fa-external-link"></i></button>
<button type="button" class="btn btn-default copyCodeBtn" id="copyCodeBtn_@Model.InviteCodeId" data-code="@Model.Code" data-toggle="popover" data-trigger="manual" data-placement="top" data-content="Copied to Clipboard" data-container="body"><i class="fa fa-clipboard"></i></button>
<button type="button" class="btn btn-default extCodeBtn" id="extCodeBtn_@Model.InviteCodeId" data-codeid="@Model.InviteCodeId"><i class="fa fa-external-link"></i></button>
</div>
}
<h4 class="list-group-item-heading" id="inviteCode_Code_@Model.InviteCodeId">@Model.Code</h4>

+ 1
- 1
Teknik/Areas/User/Views/User/Settings/InviteSettings.cshtml View File

@@ -10,7 +10,7 @@
@Styles.Render("~/Content/user/settings/invite")
@Scripts.Render("~/bundles/user/settings/invite")

<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
var createExternalLinkURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "CreateInviteCodeLink" })';
</script>


+ 1
- 1
Teknik/Areas/User/Views/User/Settings/ProfileSettings.cshtml View File

@@ -7,7 +7,7 @@
Layout = "~/Areas/User/Views/User/Settings/Settings.cshtml";
}

<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
var editURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "EditProfile" })';
</script>


+ 1
- 1
Teknik/Areas/User/Views/User/Settings/SecuritySettings.cshtml View File

@@ -7,7 +7,7 @@
Layout = "~/Areas/User/Views/User/Settings/Settings.cshtml";
}

<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
var homeUrl = '@Url.SubRouteUrl("www", "Home.Index")';
var editURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "EditSecurity" })';
var resendVerifyURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "ResendVerifyRecoveryEmail"})';

+ 1
- 1
Teknik/Areas/User/Views/User/Settings/Settings.cshtml View File

@@ -10,7 +10,7 @@
@Styles.Render("~/Content/user/settings")
@Scripts.Render("~/bundles/user/settings")

<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
var homeUrl = '@Url.SubRouteUrl("www", "Home.Index")';
var deleteUserURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "Delete" })';
</script>

+ 1
- 1
Teknik/Areas/User/Views/User/Settings/UploadSettings.cshtml View File

@@ -7,7 +7,7 @@
Layout = "~/Areas/User/Views/User/Settings/Settings.cshtml";
}

<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
var homeUrl = '@Url.SubRouteUrl("www", "Home.Index")';
var editURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "EditUpload" })';
</script>

+ 3
- 3
Teknik/Areas/User/Views/User/TwoFactorCheck.cshtml View File

@@ -1,8 +1,8 @@
@model Teknik.Areas.Users.ViewModels.TwoFactorViewModel
@model Teknik.Areas.Users.ViewModels.TwoFactorViewModel

@using Teknik.Utilities

<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
var confirmAuthCodeURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "ConfirmAuthenticatorCode" })';
</script>

@@ -48,4 +48,4 @@
</div>
</div>
</div>
</div>
</div>

+ 2
- 2
Teknik/Areas/User/Views/User/ViewProfile.cshtml View File

@@ -3,7 +3,7 @@
@using Teknik.Utilities
@using Teknik.Utilities.Cryptography

<script>
<script nonce="@Context.Items[Constants.NONCE_KEY]">
var generateDeleteKeyURL = '@Url.SubRouteUrl("u", "Upload.GenerateDeleteKey")';
var deleteVaultURL = '@Url.SubRouteUrl("v", "Vault.DeleteVault")';
</script>
@@ -73,7 +73,7 @@
<br />
<div class="row">
<div class="col-sm-12">
<textarea class="form-control wmd-input" name="pgpKeyBlock" id="pgpKeyBlock" title="Public Key" rows="10" onClick="SelectAll('pgpKeyBlock');" readonly>@Model.SecuritySettings.PGPSignature</textarea>
<textarea class="form-control wmd-input" name="pgpKeyBlock" id="pgpKeyBlock" title="Public Key" rows="10" readonly>@Model.SecuritySettings.PGPSignature</textarea>
</div>
</div>
</div>

+ 2
- 2
Teknik/Areas/Vault/Views/Vault/ModifyVault.cshtml View File

@@ -1,4 +1,4 @@
@model Teknik.Areas.Vault.ViewModels.ModifyVaultViewModel
@model Teknik.Areas.Vault.ViewModels.ModifyVaultViewModel

@using Teknik.Utilities
@using Teknik.Areas.Vault.ViewModels
@@ -10,7 +10,7 @@
string title = (Model.isEdit) ? "Edit Vault" : "Create a New Vault";
}

<script type="text/javascript">
<script nonce="@Context.Items[Constants.NONCE_KEY]">

var helpURL = '@Url.SubRouteUrl("help", "Help.Markdown")';
var validateItemURL = '@Url.SubRouteUrl(Model.CurrentSub, "Vault.Action", new { action = "ValidateItem" })';

+ 4
- 3
Teknik/Areas/Vault/Views/Vault/ModifyVaultItem.cshtml View File

@@ -1,4 +1,5 @@
@model Teknik.Areas.Vault.ViewModels.ModifyVaultItemViewModel
@model Teknik.Areas.Vault.ViewModels.ModifyVaultItemViewModel
@using Teknik.Utilities
@{
bool isTemplate = (Model.isTemplate);
}
@@ -47,7 +48,7 @@
</div>
@if (!isTemplate)
{
<script type="text/javascript">
<script nonce="@Context.Items[Constants.NONCE_KEY]">
$(document).ready(function () {
var itemDiv = $('#vault-item-@Model.index');

@@ -62,4 +63,4 @@
});
</script>
}
</div>
</div>

+ 3
- 3
Teknik/Areas/Vault/Views/Vault/ViewVault.cshtml View File

@@ -1,4 +1,4 @@
@model Teknik.Areas.Vault.ViewModels.VaultViewModel
@model Teknik.Areas.Vault.ViewModels.VaultViewModel

@using Teknik.Areas.Vault.ViewModels
@using Teknik.Utilities
@@ -6,7 +6,7 @@

@Styles.Render("~/Content/vault")

<script type="text/javascript">
<script nonce="@Context.Items[Constants.NONCE_KEY]">
var helpURL = '@Url.SubRouteUrl("help", "Help.Markdown")';
var validateItemURL = '@Url.SubRouteUrl(Model.CurrentSub, "Vault.Action", new { action = "ValidateItem" })';
var modifyVaultURL = '@Url.SubRouteUrl(Model.CurrentSub, "Vault.Action", new { action = "EditVault" })';
@@ -63,4 +63,4 @@
}
</div>

@Scripts.Render("~/bundles/vault")
@Scripts.Render("~/bundles/vault")

+ 6
- 9
Teknik/Global.asax.cs View File

@@ -43,8 +43,12 @@ namespace Teknik
{
// Start the generation time stopwatcher
var stopwatch = new Stopwatch();
HttpContext.Current.Items["Stopwatch"] = stopwatch;
HttpContext.Current.Items[Constants.PERF_KEY] = stopwatch;
stopwatch.Start();

// Generate the NONCE used for this request
string nonce = Convert.ToBase64String(Encoding.UTF8.GetBytes(StringHelper.RandomString(24)));
HttpContext.Current.Items[Constants.NONCE_KEY] = nonce;
}

protected void Application_PreSendRequestHeaders(object sender, EventArgs e)
@@ -60,20 +64,13 @@ namespace Teknik
HttpContext context = HttpContext.Current;

// Set the generation time in the header
Stopwatch stopwatch = (Stopwatch)context.Items["Stopwatch"];
Stopwatch stopwatch = (Stopwatch)context.Items[Constants.PERF_KEY];
stopwatch.Stop();

TimeSpan ts = stopwatch.Elapsed;
string elapsedTime = String.Format("{0} seconds", ts.TotalSeconds);

context.Response.AppendHeader("GenerationTime", elapsedTime);

// Allow this domain, or everything if local
string origin = (Request.IsLocal) ? "*" : context.Request.Headers.Get("Origin");
if (!string.IsNullOrEmpty(origin))
{
context.Response.AppendHeader("Access-Control-Allow-Origin", origin);
}
}
catch (Exception ex)
{

+ 45
- 0
Teknik/Modules/CORSModule.cs View File

@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Teknik.Configuration;
using Teknik.Utilities;

namespace Teknik.Modules
{
public class CORSModule : IHttpModule
{
public void Dispose()
{
}

public void Init(HttpApplication context)
{
context.PreSendRequestHeaders += delegate(object sender, EventArgs args)
{
HttpContext requestContext = ((HttpApplication)sender).Context;
Config config = Config.Load();

// Allow this domain, or everything if local
string origin = (requestContext.Request.IsLocal) ? "*" : requestContext.Request.Headers.Get("Origin");
string domain = (string.IsNullOrEmpty(origin)) ? string.Empty : origin.GetDomain();

if (string.IsNullOrEmpty(origin))
{
string sub = requestContext.Request.Url.Host.GetSubdomain();
origin = (string.IsNullOrEmpty(sub)) ? config.Host : sub + "." + config.Host;
}
else
{
if (domain != config.Host)
{
string sub = origin.GetSubdomain();
origin = (string.IsNullOrEmpty(sub)) ? config.Host : sub + "." + config.Host;
}
}

requestContext.Response.AppendHeader("Access-Control-Allow-Origin", origin);
};
}
}
}

+ 49
- 0
Teknik/Modules/CSPModule.cs View File

@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Teknik.Configuration;
using Teknik.Utilities;

namespace Teknik.Modules
{
public class CSPModule : IHttpModule
{
public void Dispose()
{
}

public void Init(HttpApplication context)
{
context.PreSendRequestHeaders += delegate (object sender, EventArgs args)
{
HttpContext requestContext = ((HttpApplication)sender).Context;
if (!requestContext.Request.IsLocal)
{
// Default to nothing allowed
string allowedDomain = "'none'";

// Allow this domain
string host = requestContext.Request.Url.Host;

if (!string.IsNullOrEmpty(host))
{
string domain = host.GetDomain();
string sub = host.GetSubdomain();

allowedDomain = string.Format("{0}.{1} {1}", (string.IsNullOrEmpty(sub) ? "*" : sub), domain);
}

// If a CDN is enabled, then add the cdn host
Config config = Config.Load();
if (config.UseCdn)
{
allowedDomain += " " + config.CdnHost;
}

requestContext.Response.AppendHeader("Content-Security-Policy", string.Format("default-src 'none'; script-src blob: 'unsafe-eval' 'nonce-{1}' {0}; style-src 'unsafe-inline' {0}; img-src data: *; font-src data: {0}; connect-src wss: blob: data: {0}; media-src *; worker-src blob: mediastream: {0}; form-action {0}; base-uri {0}; frame-ancestors {0};", allowedDomain, requestContext.Items[Constants.NONCE_KEY]));
}
};
}
}
}

+ 3
- 2
Teknik/Modules/PerformanceMonitorModule.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
@@ -6,6 +6,7 @@ using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using Teknik.Utilities;

namespace Teknik.Modules
{
@@ -35,7 +36,7 @@ namespace Teknik.Modules
string result = string.Format("{0:F0}", ms);

requestContext.Response.Write(
"<script type=\"text/javascript\">" +
"<script nonce=\"" + requestContext.Items[Constants.NONCE_KEY] + "\">" +
"var pageGenerationTime = '" + result + "';" +
"pageloadStopTimer();" +
"</script >");

+ 5
- 1
Teknik/Scripts/common.js View File

@@ -79,6 +79,8 @@ $(document).ready(function () {
});
return false;
});


});

$(function () {
@@ -107,7 +109,9 @@ $(function () {
}

// Auo-select bitcoin address
$('#bitcoin_address_footer').on('click', 'input[type=text]', function () { this.select(); });
$('#bitcoin_address_footer').click(function() {
SelectAll('bitcoin_address_footer');
});

// Setup anti-forgery functions
$.appendAntiForgeryToken = function (data, token) {

+ 2
- 0
Teknik/Teknik.csproj View File

@@ -317,6 +317,8 @@
<Compile Include="Attributes\TeknikAuthorizeAttribute.cs" />
<Compile Include="Hubs\IRCClientHub.cs" />
<Compile Include="Modules\BlacklistModule.cs" />
<Compile Include="Modules\CORSModule.cs" />
<Compile Include="Modules\CSPModule.cs" />
<Compile Include="Modules\UserAuthModule.cs" />
<Compile Include="Security\ITeknikPrincipal.cs" />
<Compile Include="Security\TeknikPrincipal.cs" />

+ 1
- 1
Teknik/Views/Shared/_Footer.cshtml View File

@@ -32,7 +32,7 @@
<div class="form-group">
<div class="input-group">
<span class="input-group-addon" id="basic-addon1"><i class="fa fa-bitcoin"></i></span>
<input type="text" class="form-control input-sm" name="bitcoin_address_footer" id="bitcoin_address_footer" value="@Model.Config.BitcoinAddress" onClick="this.setSelectionRange(0, this.value.length)" readonly>
<input type="text" class="form-control input-sm" name="bitcoin_address_footer" id="bitcoin_address_footer" value="@Model.Config.BitcoinAddress" readonly>
</div>
</div>
</form>

+ 2
- 2
Teknik/Views/Shared/_Layout.cshtml View File

@@ -25,7 +25,7 @@
<meta name="wot-verification" content="e858b91d99b767ad70db" />

<!-- Start of page 'load' -->
<script type="text/javascript">
<script nonce="@Context.Items[Constants.NONCE_KEY]">
var startTime = new Date();
</script>

@@ -71,7 +71,7 @@
</div>
@Html.Partial("_Footer")

<script type="text/javascript">
<script nonce="@Context.Items[Constants.NONCE_KEY]">
$(document).ready(function () {pageloadDoTimer();});
</script>
</body>

+ 17
- 12
Teknik/Web.config View File

@@ -57,6 +57,8 @@
<add name="PerfModule" type="Teknik.Modules.PerformanceMonitorModule, Teknik" />
<add name="UserAuthModule" type="Teknik.Modules.UserAuthModule, Teknik" />
<add name="BlacklistModule" type="Teknik.Modules.BlacklistModule, Teknik" />
<add name="CORSModule" type="Teknik.Modules.CORSModule, Teknik"/>
<add name="CSPModule" type="Teknik.Modules.CSPModule, Teknik"/>
<remove name="UrlRoutingModule-4.0" />
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
</modules>
@@ -135,6 +137,9 @@
<add name="Access-Control-Allow-Headers" value="Authorization, Accept, Origin, Content-Type, X-Requested-With, Connection, Transfer-Encoding" />
<add name="strict-transport-security" value="max-age=31536000; includeSubdomains; preload" />
<add name="X-XSS-Protection" value="1; mode=block" />
<add name="X-Content-Type-Options" value="nosniff"/>
<add name="Referrer-Policy" value="no-referrer, strict-origin-when-cross-origin"/>
<add name="Public-Key-Pins" value="max-age=300; includeSubDomains; pin-sha256=&quot;grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=&quot;; pin-sha256=&quot;C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHFr8M=&quot;;"/>
<add name="Vary" value="Origin" />
</customHeaders>
</httpProtocol>
@@ -190,16 +195,16 @@
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
<system.data>
<DbProviderFactories>
<remove invariant="MySql.Data.MySqlClient" />
<add description=".Net Framework Data Provider for MySQL" invariant="MySql.Data.MySqlClient" name="MySQL Data Provider" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.10.6.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
</DbProviderFactories>
</system.data>
<system.codedom>
<compilers>
<compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.8.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:1659;1699;1701" />
<compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.8.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+" />
</compilers>
</system.codedom>
<system.data>
<DbProviderFactories>
<remove invariant="MySql.Data.MySqlClient" />
<add description=".Net Framework Data Provider for MySQL" invariant="MySql.Data.MySqlClient" name="MySQL Data Provider" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.10.6.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
</DbProviderFactories>
</system.data>
<system.codedom>
<compilers>
<compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.8.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:1659;1699;1701" />
<compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.8.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+" />
</compilers>
</system.codedom>
</configuration>

+ 5
- 12
Utilities/Utilities/BundleExtensions.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
@@ -39,22 +39,15 @@ namespace Teknik.Utilities
}

public virtual void Process(BundleContext context, BundleResponse response)
{
// Don't continue if we aren't using a CDN
if (!context.BundleCollection.UseCdn)
{
{
// If we are using a CDN, then set the host as the CDN host
if (!context.BundleCollection.UseCdn || string.IsNullOrEmpty(CdnHost))
return;
}

// Get the directory and filename for the bundle
var dir = VirtualPathUtility.GetDirectory(context.BundleVirtualPath).TrimStart('/').TrimStart('~').TrimStart('/').TrimEnd('/');
var file = VirtualPathUtility.GetFileName(context.BundleVirtualPath);
var group = string.Format("{0}{1}", file, Ext);

if (string.IsNullOrEmpty(CdnHost))
{
return;
}
var group = $"{file}{Ext}";

using (var hashAlgorithm = Cryptography.SHA256.CreateHashAlgorithm())
{

+ 5
- 1
Utilities/Utilities/Constants.cs View File

@@ -1,4 +1,4 @@
namespace Teknik.Utilities
namespace Teknik.Utilities
{
public static class Constants
{
@@ -9,5 +9,9 @@
public const string ROBOTS_PATH = "~/App_Data/robots.txt";
public const string LOG_FILE_NAME_PREFIX = "Teknik";
public const string LOG_FILE_EXT = ".log";

public const string PERF_KEY = "Stopwatch";

public const string NONCE_KEY = "Nonce";
}
}

Loading…
Cancel
Save