
7 changed files with 83 additions and 43537 deletions
@ -0,0 +1,37 @@
|
||||
--- |
||||
layout: page |
||||
title: Affiliates |
||||
subtitle: Support NixNet by making purchases and using these links |
||||
description: Support NixNet by making purchases with affiliate links and vouchers |
||||
--- |
||||
One of the easiest ways to support NixNet is to purchase products on these websites using the provided affiliate links. |
||||
|
||||
# netcup |
||||
[netcup](https://netcup.eu) is currently where the most services are running. They have fantastic offerings at most price points and incredible deals. I've been very happy with their service and *highly* recommend them. |
||||
|
||||
## Voucher codes |
||||
These are single-use vouchers for various products. When you use one, please [send me a message](/contact) so I can generate a new one. |
||||
|
||||
### 5€ for anything except domains |
||||
* [36nc15758387844](https://www.netcup.eu/bestellen/gutschein_einloesen.php?gutschein=36nc15758387844) |
||||
* [36nc15758387843](https://www.netcup.eu/bestellen/gutschein_einloesen.php?gutschein=36nc15758387843) |
||||
* [36nc15758387842](https://www.netcup.eu/bestellen/gutschein_einloesen.php?gutschein=36nc15758387842) |
||||
* [36nc15758387841](https://www.netcup.eu/bestellen/gutschein_einloesen.php?gutschein=36nc15758387841) |
||||
* [36nc15758387840](https://www.netcup.eu/bestellen/gutschein_einloesen.php?gutschein=36nc15758387840) |
||||
|
||||
### 10% off the 200 G8 |
||||
* [2052nc15758390090](https://www.netcup.eu/bestellen/gutschein_einloesen.php?gutschein=2052nc15758390090) |
||||
* [2052nc15758390091](https://www.netcup.eu/bestellen/gutschein_einloesen.php?gutschein=2052nc15758390091) |
||||
|
||||
### 10% off the 500 G8 |
||||
* [2053nc15758393980](https://www.netcup.eu/bestellen/gutschein_einloesen.php?gutschein=2053nc15758393980) |
||||
* [2053nc15758393981](https://www.netcup.eu/bestellen/gutschein_einloesen.php?gutschein=2053nc15758393981) |
||||
|
||||
### 10% off the 1000 G8 |
||||
* [2054nc15758394201](https://www.netcup.eu/bestellen/gutschein_einloesen.php?gutschein=2054nc15758394201) |
||||
* [2054nc15758394200](https://www.netcup.eu/bestellen/gutschein_einloesen.php?gutschein=2054nc15758394200) |
||||
|
||||
### 10% off the 2000 G8 |
||||
* [2056nc15758394800](https://www.netcup.eu/bestellen/gutschein_einloesen.php?gutschein=2056nc15758394800) |
||||
* [2056nc15758394801](https://www.netcup.eu/bestellen/gutschein_einloesen.php?gutschein=2056nc15758394801) |
||||
|
@ -1,108 +0,0 @@
|
||||
|
||||
$(function(){ |
||||
|
||||
var model = { |
||||
// renomear
|
||||
dat: [ |
||||
], |
||||
read_json: function() { |
||||
$.ajax({ |
||||
url: "/cards.json", |
||||
dataType: 'json', |
||||
async: false, |
||||
success: function(data) { |
||||
$(data["cards"]).each(function(){ |
||||
var card_info = $(this)[0]; |
||||
model.set_data(card_info); |
||||
}); |
||||
} |
||||
}); |
||||
}, |
||||
set_data: function(d) { |
||||
model.dat.push(d); |
||||
}, |
||||
get_data: function() { |
||||
return model.dat; |
||||
}, |
||||
filter_data: function(conteudo) { |
||||
var $d = model.dat; |
||||
var $filter = []; |
||||
var $c = conteudo.toLowerCase(); |
||||
$($d).each(function(i){ |
||||
if( |
||||
$d[i].name.toLowerCase().indexOf($c) >= 0 || |
||||
$d[i].description.toLowerCase().indexOf($c) >= 0 || |
||||
$d[i].button_text.toLowerCase().indexOf($c) >= 0 |
||||
) { |
||||
$filter.push($d[i]); |
||||
} |
||||
}); |
||||
return $filter; |
||||
}, |
||||
init: function() { |
||||
model.read_json(); |
||||
} |
||||
}; |
||||
var octopus = { |
||||
init: function() { |
||||
model.init(); |
||||
view.init(); |
||||
octopus.create_card(model.get_data()); |
||||
}, |
||||
create_card: function(d) { |
||||
$.each(d, function(i){ |
||||
view.create_card(d[i].name, d[i].description, d[i].button_text, d[i].link, d[i].tor); |
||||
}); |
||||
}, |
||||
filter_data: function(c) { |
||||
var d = model.filter_data(c); |
||||
$.each(d, function(i){ |
||||
view.create_card(d[i].name, d[i].description, d[i].button_text, d[i].link, d[i].tor); |
||||
}); |
||||
}, |
||||
recreate_cards: function() { |
||||
octopus.create_card(model.get_data()); |
||||
} |
||||
}; |
||||
|
||||
// Renomear
|
||||
var view = { |
||||
init: function() { |
||||
this.container = $(".flex-cards"); |
||||
this.search_field = $("#search_field"); |
||||
view.events(); |
||||
}, |
||||
events: function(){ |
||||
this.search_field.on('input',function(){ |
||||
var $conteudo = $(this).val(); |
||||
view.clean_cards(); |
||||
if($conteudo.length == 0){ |
||||
octopus.recreate_cards(); |
||||
}else { |
||||
octopus.filter_data($conteudo); |
||||
} |
||||
}); |
||||
}, |
||||
create_card: function(name, desc, bt_txt, link, tor){ |
||||
var $card = $("<div>").addClass("card"); |
||||
var $h1 = $("<h1>").text(name); |
||||
var $desc = $("<p>").text(desc); |
||||
var $button = $("<button>").addClass("button").text(bt_txt); |
||||
var $icon = $("<button>").addClass("tor").text("Tor"); |
||||
var $a = $("<a>").attr("href", link); |
||||
var $tor = $("<a>").attr("href", tor); |
||||
$a.append($button); |
||||
$tor.append($icon); |
||||
if (tor == "#") { |
||||
$card.append($h1).append($desc).append($a); |
||||
} else { |
||||
$card.append($h1).append($desc).append($a).append($tor);
|
||||
} |
||||
this.container.append($card); |
||||
}, |
||||
clean_cards: function() { |
||||
this.container.empty(); |
||||
} |
||||
}; |
||||
octopus.init(); |
||||
}); |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 6.2 KiB |
@ -1,4 +0,0 @@
|
||||
{ |
||||
"title": "NixNet", |
||||
"description": "NixNet.xyz is a network of websites and services hosted by the pseudonymous Amolith (me). It's also a blog!" |
||||
} |
After Width: | Height: | Size: 44 KiB |
File diff suppressed because one or more lines are too long
@ -1,537 +0,0 @@
|
||||
System.register("local", [], function (exports_1, context_1) { |
||||
"use strict"; |
||||
var __moduleName = context_1 && context_1.id; |
||||
function createElement(name, attributes, ...children) { |
||||
return { |
||||
name, |
||||
attributes: attributes || {}, |
||||
children: Array.prototype.concat(...(children || [])) |
||||
}; |
||||
} |
||||
exports_1("createElement", createElement); |
||||
return { |
||||
setters: [], |
||||
execute: function () { |
||||
} |
||||
}; |
||||
}); |
||||
System.register("renderer", [], function (exports_2, context_2) { |
||||
"use strict"; |
||||
var __moduleName = context_2 && context_2.id; |
||||
function render(element) { |
||||
if (element == null) |
||||
return ''; |
||||
if (typeof element !== "object") |
||||
element = String(element); |
||||
if (typeof element === "string") |
||||
return element.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); |
||||
//if (element instanceof Raw) return element.html;
|
||||
console.assert(!!element.attributes, 'Element attributes must be defined:\n' + JSON.stringify(element)); |
||||
const elementAttributes = element.attributes; |
||||
let attributes = Object.keys(elementAttributes).filter(key => { |
||||
const value = elementAttributes[key]; |
||||
return value != null; |
||||
}).map(key => { |
||||
const value = elementAttributes[key]; |
||||
if (value === true) { |
||||
return key; |
||||
} |
||||
return `${key}="${String(value).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"')}"`; |
||||
}).join(' '); |
||||
if (attributes.length > 0) { |
||||
attributes = ' ' + attributes; |
||||
} |
||||
const children = element.children.length > 0 ? `>${element.children.map(child => render(child)).join('')}` : '>'; |
||||
return `<${element.name}${attributes}${children}</${element.name}>`; |
||||
} |
||||
exports_2("render", render); |
||||
return { |
||||
setters: [], |
||||
execute: function () { |
||||
} |
||||
}; |
||||
}); |
||||
/* |
||||
Copyright 2019 Wiktor Kwapisiewicz |
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); |
||||
you may not use this file except in compliance with the License. |
||||
You may obtain a copy of the License at |
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software |
||||
distributed under the License is distributed on an "AS IS" BASIS, |
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
See the License for the specific language governing permissions and |
||||
limitations under the License. |
||||
*/ |
||||
System.register("openpgp-key", ["local", "renderer"], function (exports_3, context_3) { |
||||
"use strict"; |
||||
var local, renderer, proofs, dateFormat; |
||||
var __moduleName = context_3 && context_3.id; |
||||
function getLatestSignature(signatures, date = new Date()) { |
||||
let signature = signatures[0]; |
||||
for (let i = 1; i < signatures.length; i++) { |
||||
if (signatures[i].created >= signature.created && |
||||
(signatures[i].created <= date || date === null)) { |
||||
signature = signatures[i]; |
||||
} |
||||
} |
||||
return signature; |
||||
} |
||||
function getVerifier(proofUrl, fingerprint) { |
||||
for (const proof of proofs) { |
||||
const matches = proofUrl.match(proof.matcher); |
||||
if (!matches) |
||||
continue; |
||||
const bound = Object.entries(proof.variables).map(([key, value]) => [key, matches[value || 0]]).reduce((previous, current) => { previous[current[0]] = current[1]; return previous; }, { FINGERPRINT: fingerprint }); |
||||
const profile = proof.profile.replace(/\{([A-Z]+)\}/g, (_, name) => bound[name]); |
||||
const proofJson = proof.proof.replace(/\{([A-Z]+)\}/g, (_, name) => bound[name]); |
||||
const username = proof.username.replace(/\{([A-Z]+)\}/g, (_, name) => bound[name]); |
||||
return { |
||||
profile, |
||||
proofUrl, |
||||
proofJson, |
||||
username, |
||||
service: proof.service, |
||||
checks: (proof.checks || []).map((check) => ({ |
||||
relation: check.relation, |
||||
proof: check.proof, |
||||
claim: check.claim.replace(/\{([A-Z]+)\}/g, (_, name) => bound[name]) |
||||
})) |
||||
}; |
||||
} |
||||
return null; |
||||
} |
||||
async function verify(proofJson, checks) { |
||||
const response = await fetch(proofJson, { |
||||
headers: { |
||||
Accept: 'application/json' |
||||
}, |
||||
credentials: 'omit' |
||||
}); |
||||
if (!response.ok) { |
||||
throw new Error('Response failed: ' + response.status); |
||||
} |
||||
const json = await response.json(); |
||||
for (const check of checks) { |
||||
const proofValue = check.proof.reduce((previous, current) => { |
||||
if (current == null || previous == null) |
||||
return null; |
||||
if (Array.isArray(previous) && typeof current === 'string') { |
||||
return previous.map(value => value[current]); |
||||
} |
||||
return previous[current]; |
||||
}, json); |
||||
const claimValue = check.claim; |
||||
if (check.relation === 'eq') { |
||||
if (proofValue !== claimValue) { |
||||
throw new Error(`Proof value ${proofValue} !== claim value ${claimValue}`); |
||||
} |
||||
} |
||||
else if (check.relation === 'contains') { |
||||
if (!proofValue || proofValue.indexOf(claimValue) === -1) { |
||||
throw new Error(`Proof value ${proofValue} does not contain claim value ${claimValue}`); |
||||
} |
||||
} |
||||
else if (check.relation === 'oneOf') { |
||||
if (!proofValue || proofValue.indexOf(claimValue) === -1) { |
||||
throw new Error(`Proof value ${proofValue} does not contain claim value ${claimValue}`); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
function serviceToClassName(service) { |
||||
if (service === 'github') { |
||||
return 'fab fa-github'; |
||||
} |
||||
else if (service === 'reddit') { |
||||
return 'fab fa-reddit'; |
||||
} |
||||
else if (service === 'hackernews') { |
||||
return 'fab fa-hacker-news'; |
||||
} |
||||
else if (service === 'mastodon') { |
||||
return 'fab fa-mastodon'; |
||||
} |
||||
else if (service === 'dns') { |
||||
return 'fas fa-globe'; |
||||
} |
||||
else { |
||||
return ''; |
||||
} |
||||
} |
||||
async function lookupKey(query) { |
||||
const result = document.getElementById('result'); |
||||
result.innerHTML = renderer.render(local.createElement("span", null, |
||||
"Looking up ", |
||||
query, |
||||
"...")); |
||||
let keys, keyUrl; |
||||
const keyLink = document.querySelector('[rel="pgpkey"]'); |
||||
if (!keyLink) { |
||||
const keyserver = document.querySelector('meta[name="keyserver"]').content; |
||||
keyUrl = `https://${keyserver}/pks/lookup?op=get&options=mr&search=${query}`; |
||||
const response = await fetch(keyUrl); |
||||
const key = await response.text(); |
||||
keys = (await openpgp.key.readArmored(key)).keys; |
||||
} |
||||
else { |
||||
keyUrl = keyLink.href; |
||||
const response = await fetch(keyUrl); |
||||
const key = await response.arrayBuffer(); |
||||
keys = (await openpgp.key.read(new Uint8Array(key))).keys; |
||||
} |
||||
if (keys.length > 0) { |
||||
loadKeys(keyUrl, keys).catch(e => { |
||||
result.innerHTML = renderer.render(local.createElement("span", null, |
||||
"Could not display this key: ", |
||||
String(e))); |
||||
}); |
||||
} |
||||
else { |
||||
result.innerHTML = renderer.render(local.createElement("span", null, |
||||
query, |
||||
": not found")); |
||||
} |
||||
} |
||||
async function loadKeys(keyUrl, _keys) { |
||||
const key = _keys[0]; |
||||
window.key = key; |
||||
const primaryUser = await key.getPrimaryUser(); |
||||
for (var i = key.users.length - 1; i >= 0; i--) { |
||||
try { |
||||
if (await key.users[i].verify(key.primaryKey) === openpgp.enums.keyStatus.valid) { |
||||
continue; |
||||
} |
||||
} |
||||
catch (e) { |
||||
console.error('User verification error:', e); |
||||
} |
||||
//key.users.splice(i, 1);
|
||||
} |
||||
for (const user of key.users) { |
||||
user.revoked = await user.isRevoked(); |
||||
} |
||||
const lastPrimarySig = primaryUser.selfCertification; |
||||
const keys = [{ |
||||
fingerprint: key.primaryKey.getFingerprint(), |
||||
status: await key.verifyPrimaryKey(), |
||||
keyFlags: lastPrimarySig.keyFlags, |
||||
created: key.primaryKey.created, |
||||
algorithmInfo: key.primaryKey.getAlgorithmInfo(), |
||||
expirationTime: lastPrimarySig.getExpirationTime() |
||||
}]; |
||||
//console.log(lastPrimarySig);
|
||||
const proofs = (lastPrimarySig.notations || []) |
||||
.filter((notation) => notation[0] === 'proof@metacode.biz' && typeof notation[1] === 'string') |
||||
.map((notation) => notation[1]) |
||||
.map((proofUrl) => getVerifier(proofUrl, key.primaryKey.getFingerprint())) |
||||
.filter((verifier) => !!verifier); |
||||
/* |
||||
proofs.push(getVerifier('https://www.reddit.com/user/wiktor-k/comments/bo5oih/test/', key.primaryKey.getFingerprint())); |
||||
proofs.push(getVerifier('https://news.ycombinator.com/user?id=wiktor-k', key.primaryKey.getFingerprint())); |
||||
proofs.push(getVerifier('https://gist.github.com/wiktor-k/389d589dd19250e1f9a42bc3d5d40c16', key.primaryKey.getFingerprint())); |
||||
proofs.push(getVerifier('https://metacode.biz/@wiktor', key.primaryKey.getFingerprint())); |
||||
proofs.push(getVerifier('dns:metacode.biz?type=TXT', key.primaryKey.getFingerprint())); |
||||
*/ |
||||
for (const subKey of key.subKeys) { |
||||
const lastSig = getLatestSignature(subKey.bindingSignatures); |
||||
let reasonForRevocation; |
||||
if (subKey.revocationSignatures.length > 0) { |
||||
reasonForRevocation = subKey.revocationSignatures[subKey.revocationSignatures.length - 1].reasonForRevocationString; |
||||
} |
||||
keys.push({ |
||||
fingerprint: subKey.keyPacket.getFingerprint(), |
||||
status: await subKey.verify(key.primaryKey), |
||||
reasonForRevocation, |
||||
keyFlags: lastSig.keyFlags, |
||||
created: lastSig.created, |
||||
algorithmInfo: subKey.keyPacket.getAlgorithmInfo(), |
||||
expirationTime: await subKey.getExpirationTime() |
||||
}); |
||||
} |
||||
//key.users.splice(primaryUser.index, 1);
|
||||
const profileHash = await openpgp.crypto.hash.md5(openpgp.util.str_to_Uint8Array(primaryUser.user.userId.email)).then((u) => openpgp.util.str_to_hex(openpgp.util.Uint8Array_to_str(u))); |
||||
const now = new Date(); |
||||
// there is index property on primaryUser
|
||||
document.title = primaryUser.user.userId.name + ' - OpenPGP key'; |
||||
const info = local.createElement("div", null, |
||||
local.createElement("div", { class: "wrapper" }, |
||||
local.createElement("div", { class: "bio" }, |
||||
local.createElement("img", { class: "avatar", src: "https://seccdn.libravatar.org/avatar/" + profileHash + "?s=148&d=" + encodeURIComponent("https://www.gravatar.com/avatar/" + profileHash + "?s=148&d=mm") }), |
||||
local.createElement("h2", null, primaryUser.user.userId.name)), |
||||
local.createElement("div", null, |
||||
local.createElement("ul", { class: "props" }, |
||||
local.createElement("li", { title: key.primaryKey.getFingerprint() }, |
||||
local.createElement("a", { href: keyUrl, target: "_blank", rel: "nofollow noopener" }, |
||||
"\uD83D\uDD11\u00A0", |
||||
local.createElement("code", null, key.primaryKey.getFingerprint()))), |
||||
key.users.filter((user) => !user.revoked && user.userId).map((user) => user.userId.email).filter((email) => !!email).map((email) => local.createElement("li", null, |
||||
local.createElement("a", { href: "mailto:" + email }, |
||||
"\uD83D\uDCE7 ", |
||||
email |
||||
//formatAttribute(user.userAttribute)
|
||||
))), |
||||
proofs.filter((proof) => !!proof).map((proof) => local.createElement("li", null, |
||||
local.createElement("a", { rel: "me noopener nofollow", target: "_blank", href: proof.profile }, |
||||
local.createElement("i", { class: serviceToClassName(proof.service) }), |
||||
proof.username), |
||||
local.createElement("a", { rel: "noopener nofollow", target: "_blank", href: proof.proofUrl, class: "proof", "data-proof-json": proof.proofJson, "data-checks": JSON.stringify(proof.checks) }, |
||||
local.createElement("i", { class: "fas fa-certificate" }), |
||||
"proof")))))), |
||||
local.createElement("details", null, |
||||
local.createElement("summary", null, "\uD83D\uDD12 Encrypt"), |
||||
local.createElement("textarea", { placeholder: "Message to encrypt...", id: "message" }), |
||||
local.createElement("input", { type: "button", value: "Encrypt", id: "encrypt" }), |
||||
' ', |
||||
local.createElement("input", { type: "button", id: "send", "data-recipient": primaryUser.user.userId.email, value: "Send to " + primaryUser.user.userId.email })), |
||||
local.createElement("details", null, |
||||
local.createElement("summary", null, "\uD83D\uDD8B Verify"), |
||||
local.createElement("textarea", { placeholder: "Clearsigned message to verify...", id: "signed" }), |
||||
local.createElement("input", { type: "button", value: "Verify", id: "verify" })), |
||||
local.createElement("details", null, |
||||
local.createElement("summary", null, "\uD83D\uDD11 Key details"), |
||||
local.createElement("p", null, "Subkeys:"), |
||||
local.createElement("ul", null, keys.map((subKey) => local.createElement("li", null, |
||||
local.createElement("div", null, |
||||
getStatus(subKey.status, subKey.reasonForRevocation), |
||||
" ", |
||||
getIcon(subKey.keyFlags), |
||||
" ", |
||||
local.createElement("code", null, subKey.fingerprint.substring(24).match(/.{4}/g).join(" ")), |
||||
" ", |
||||
formatAlgorithm(subKey.algorithmInfo.algorithm), |
||||
" (", |
||||
subKey.algorithmInfo.bits, |
||||
")"), |
||||
local.createElement("div", null, |
||||
"created: ", |
||||
formatDate(subKey.created), |
||||
", expire", |
||||
now > subKey.expirationTime ? "d" : "s", |
||||
": ", |
||||
formatDate(subKey.expirationTime))))))); |
||||
document.getElementById('result').innerHTML = renderer.render(info); |
||||
checkProofs(); |
||||
} |
||||
async function checkProofs() { |
||||
const proofs = document.querySelectorAll('[data-checks]'); |
||||
for (const proofLink of proofs) { |
||||
const checks = JSON.parse(proofLink.dataset.checks || ''); |
||||
const url = proofLink.dataset.proofJson || ''; |
||||
try { |
||||
await verify(url, checks); |
||||
proofLink.textContent = 'verified proof'; |
||||
proofLink.classList.add('verified'); |
||||
} |
||||
catch (e) { |
||||
console.error('Could not verify proof: ' + e); |
||||
} |
||||
} |
||||
} |
||||
async function verifyProof(e) { |
||||
const target = e.target; |
||||
if (target.id === 'encrypt') { |
||||
const text = document.getElementById('message'); |
||||
openpgp.encrypt({ |
||||
message: openpgp.message.fromText(text.value), |
||||
publicKeys: [window.key], |
||||
armor: true |
||||
}).then((cipherText) => { |
||||
text.value = cipherText.data; |
||||
}, (e) => alert(e)); |
||||
} |
||||
else if (target.id === 'send') { |
||||
location.href = "mailto:" + target.dataset.recipient + "?subject=Encrypted%20message&body=" + encodeURIComponent(document.getElementById('message').value); |
||||
} |
||||
else if (target.id === 'verify') { |
||||
const text = document.getElementById('signed'); |
||||
const message = await openpgp.cleartext.readArmored(text.value); |
||||
const verified = await openpgp.verify({ |
||||
message, |
||||
publicKeys: [window.key] |
||||
}); |
||||
console.log(verified); |
||||
alert('The signature is ' + (verified.signatures[0].valid ? '✅ correct.' : '❌ incorrect.')); |
||||
} |
||||
} |
||||
function formatAttribute(userAttribute) { |
||||
if (userAttribute.attributes[0][0] === String.fromCharCode(1)) { |
||||
return local.createElement("img", { src: "data:image/jpeg;base64," + btoa(userAttribute.attributes[0].substring(17)) }); |
||||
} |
||||
if (userAttribute.attributes[0][0] === 'e') { |
||||
const url = userAttribute.attributes[0].substring(userAttribute.attributes[0].indexOf('@') + 1); |
||||
return local.createElement("a", { href: url, rel: "noopener nofollow" }, url); |
||||
} |
||||
return 'unknown attribute'; |
||||
} |
||||
function formatAlgorithm(name) { |
||||
if (name === 'rsa_encrypt_sign') |
||||
return "RSA"; |
||||
return name; |
||||
} |
||||
function formatDate(date) { |
||||
if (date === Infinity) |
||||
return "never"; |
||||
if (typeof date === 'number') |
||||
return 'x'; |
||||
return dateFormat.format(date); |
||||
} |
||||
function getStatus(status, details) { |
||||
if (status === openpgp.enums.keyStatus.invalid) { |
||||
return local.createElement("span", { title: "Invalid key" }, "\u274C"); |
||||
} |
||||
if (status === openpgp.enums.keyStatus.expired) { |
||||
return local.createElement("span", { title: "Key expired" }, "\u23F0"); |
||||
} |
||||
if (status === openpgp.enums.keyStatus.revoked) { |
||||
return local.createElement("span", { title: "Key revoked: " + details }, "\u274C"); |
||||
} |
||||
if (status === openpgp.enums.keyStatus.valid) { |
||||
return local.createElement("span", { title: "Valid key" }, "\u2705"); |
||||
} |
||||
if (status === openpgp.enums.keyStatus.no_self_cert) { |
||||
return local.createElement("span", { title: "Key not certified" }, "\u274C"); |
||||
} |
||||
return "unknown:" + status; |
||||
} |
||||
function getIcon(keyFlags) { |
||||
if (!keyFlags || !keyFlags[0]) { |
||||
return ""; |
||||
} |
||||
let flags = []; |
||||
if ((keyFlags[0] & openpgp.enums.keyFlags.certify_keys) !== 0) { |
||||
flags.push(local.createElement("span", { title: "Certyfing key" }, "\uD83C\uDFF5\uFE0F")); |
||||
} |
||||
if ((keyFlags[0] & openpgp.enums.keyFlags.sign_data) !== 0) { |
||||
flags.push(local.createElement("span", { title: 'Signing key' }, "\uD83D\uDD8B")); |
||||
} |
||||
if (((keyFlags[0] & openpgp.enums.keyFlags.encrypt_communication) !== 0) || |
||||
((keyFlags[0] & openpgp.enums.keyFlags.encrypt_storage) !== 0)) { |
||||
flags.push(local.createElement("span", { title: 'Encryption key' }, "\uD83D\uDD12")); |
||||
} |
||||
if ((keyFlags[0] & openpgp.enums.keyFlags.authentication) !== 0) { |
||||
flags.push(local.createElement("span", { title: 'Authentication key' }, "\uD83D\uDCB3")); |
||||
} |
||||
return flags; |
||||
} |
||||
return { |
||||
setters: [ |
||||
function (local_1) { |
||||
local = local_1; |
||||
}, |
||||
function (renderer_1) { |
||||
renderer = renderer_1; |
||||
} |
||||
], |
||||
execute: function () { |
||||
openpgp.config.show_version = false; |
||||
openpgp.config.show_comment = false; |
||||
proofs = [ |
||||
{ |
||||
matcher: /^https:\/\/gist\.github\.com\/([A-Za-z0-9_-]+)\/([0-9a-f]+)$/, |
||||
variables: { |
||||
USERNAME: 1, |
||||
PROOFID: 2 |
||||
}, |
||||
profile: 'https://github.com/{USERNAME}', |
||||
proof: 'https://api.github.com/gists/{PROOFID}', |
||||
username: '{USERNAME}', |
||||
service: 'github', |
||||
checks: [{ |
||||
relation: 'eq', |
||||
proof: ['owner', 'login'], |
||||
claim: '{USERNAME}' |
||||
}, { |
||||
relation: 'eq', |
||||
proof: ['owner', 'html_url'], |
||||
claim: 'https://github.com/{USERNAME}' |
||||
}, { |
||||
relation: 'contains', |
||||
proof: ['files', 'openpgp.md', 'content'], |
||||
claim: '[Verifying my OpenPGP key: openpgp4fpr:{FINGERPRINT}]' |
||||
}] |
||||
}, |
||||
{ |
||||
matcher: /^https:\/\/news\.ycombinator\.com\/user\?id=([A-Za-z0-9-]+)$/, |
||||
variables: { |
||||
USERNAME: 1, |
||||
PROFILE: 0 |
||||
}, |
||||
profile: '{PROFILE}', |
||||
proof: 'https://hacker-news.firebaseio.com/v0/user/{USERNAME}.json', |
||||
username: '{USERNAME}', |
||||
service: 'hackernews', |
||||
checks: [{ |
||||
relation: 'contains', |
||||
proof: ['about'], |
||||
claim: '[Verifying my OpenPGP key: openpgp4fpr:{FINGERPRINT}]' |
||||
}] |
||||
}, |
||||
{ |
||||
matcher: /^https:\/\/www\.reddit\.com\/user\/([^/]+)\/comments\/([^/]+)\/([^/]+\/)?$/, |
||||
variables: { |
||||
USERNAME: 1, |
||||
PROOF: 2 |
||||
}, |
||||
profile: 'https://www.reddit.com/user/{USERNAME}', |
||||
proof: 'https://www.reddit.com/user/{USERNAME}/comments/{PROOF}.json', |
||||
username: '{USERNAME}', |
||||
service: 'reddit', |
||||
checks: [{ |
||||
relation: 'contains', |
||||
proof: [0, 'data', 'children', 0, 'data', 'selftext'], |
||||
claim: 'Verifying my OpenPGP key: openpgp4fpr:{FINGERPRINT}' |
||||
}, { |
||||
relation: 'eq', |
||||
proof: [0, 'data', 'children', 0, 'data', 'author'], |
||||
claim: '{USERNAME}' |
||||
}] |
||||
}, |
||||
{ |
||||
matcher: /^https:\/\/([^/]+)\/@([A-Za-z0-9_-]+)$/, |
||||
variables: { |
||||
INSTANCE: 1, |
||||
USERNAME: 2, |
||||
PROFILE: 0 |
||||
}, |
||||
profile: '{PROFILE}', |
||||
proof: '{PROFILE}', |
||||
username: '@{USERNAME}@{INSTANCE}', |
||||
service: 'mastodon', |
||||
checks: [{ |
||||
relation: 'oneOf', |
||||
proof: ['attachment', 'value'], |
||||
claim: '{FINGERPRINT}' |
||||
}] |
||||
}, |
||||
{ |
||||
matcher: /^dns:([^?]+)\?type=TXT$/, |
||||
variables: { |
||||
DOMAIN: 1 |
||||
}, |
||||
profile: 'https://{DOMAIN}', |
||||
proof: 'https://dns.google.com/resolve?name={DOMAIN}&type=TXT', |
||||
username: '{DOMAIN}', |
||||
service: 'dns', |
||||
checks: [{ |
||||
relation: 'oneOf', |
||||
proof: ['Answer', 'data'], |
||||
claim: '\"openpgp4fpr:{FINGERPRINT}\"' |
||||
}] |
||||
} |
||||
]; |
||||
window.onload = window.onhashchange = function () { |
||||
lookupKey(location.hash.substring(1)); |
||||
}; |
||||
; |
||||
document.addEventListener('click', verifyProof); |
||||
dateFormat = new Intl.DateTimeFormat(undefined, { |
||||
year: 'numeric', month: 'numeric', day: 'numeric', |
||||
hour: 'numeric', minute: 'numeric', second: 'numeric', |
||||
}); |
||||
} |
||||
}; |
||||
}); |
Loading…
Reference in new issue