1
0
mirror of https://git.teknik.io/Teknikode/Teknik.git synced 2023-08-02 14:16:22 +02:00

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

This commit is contained in:
Uncled1023 2018-01-29 23:18:47 -08:00
parent c78ea99e79
commit 37424956db
49 changed files with 296 additions and 128 deletions

View File

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

View File

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

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>

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>

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" })';

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>

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>

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>

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>

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>

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>

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>

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")

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>

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>

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);

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);

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();

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;
}
}

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');
});
}

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" })';

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())
{

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 {

View File

@ -58,4 +58,8 @@ $(document).ready(function () {
}
});
});
$('#pgpKeyBlock').click(function () {
SelectAll('pgpKeyBlock');
});
});

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) {

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)

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>

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>

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>

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>

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"})';

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>

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>

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>

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>

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" })';

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>

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")

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)
{

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);
};
}
}
}

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]));
}
};
}
}
}

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 >");

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) {

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" />

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>

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>

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>

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())
{

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";
}
}