mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-12 23:35:58 +00:00
Merge branch 'master' of github.com:Human-Connection/Human-Connection into 236-list-social-media-accounts
This commit is contained in:
commit
e409d6508f
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
.env
|
||||
.idea
|
||||
*.iml
|
||||
.vscode
|
||||
.DS_Store
|
||||
npm-debug.log*
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
"lint": "eslint src --config .eslintrc.js",
|
||||
"test": "nyc --reporter=text-lcov yarn test:jest",
|
||||
"test:cypress": "run-p --race test:before:*",
|
||||
"test:before:server": "cross-env GRAPHQL_URI=http://localhost:4123 GRAPHQL_PORT=4123 babel-node src/ 2> /dev/null",
|
||||
"test:before:server": "cross-env CLIENT_URI=http://localhost:4123 GRAPHQL_URI=http://localhost:4123 GRAPHQL_PORT=4123 babel-node src/ 2> /dev/null",
|
||||
"test:before:seeder": "cross-env GRAPHQL_URI=http://localhost:4001 GRAPHQL_PORT=4001 PERMISSIONS=disabled babel-node src/ 2> /dev/null",
|
||||
"test:jest:cmd": "wait-on tcp:4001 tcp:4123 && jest --forceExit --detectOpenHandles --runInBand",
|
||||
"test:cucumber:cmd": "wait-on tcp:4001 tcp:4123 && cucumber-js --require-module @babel/register --exit test/",
|
||||
@ -58,7 +58,7 @@
|
||||
"graphql-shield": "~5.3.1",
|
||||
"graphql-tag": "~2.10.1",
|
||||
"graphql-yoga": "~1.17.4",
|
||||
"helmet": "~3.15.1",
|
||||
"helmet": "~3.16.0",
|
||||
"jsonwebtoken": "~8.5.1",
|
||||
"linkifyjs": "~2.1.8",
|
||||
"lodash": "~4.17.11",
|
||||
@ -76,7 +76,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "~7.2.3",
|
||||
"@babel/core": "~7.3.4",
|
||||
"@babel/core": "~7.4.0",
|
||||
"@babel/node": "~7.2.2",
|
||||
"@babel/plugin-proposal-throw-expressions": "^7.2.0",
|
||||
"@babel/preset-env": "~7.4.2",
|
||||
|
||||
@ -22,9 +22,8 @@ let activityPub = null
|
||||
export { activityPub }
|
||||
|
||||
export default class ActivityPub {
|
||||
constructor (domain, port, uri) {
|
||||
if (domain === 'localhost') { this.domain = `${domain}:${port}` } else { this.domain = domain }
|
||||
this.port = port
|
||||
constructor (host, uri) {
|
||||
this.host = host
|
||||
this.dataSource = new NitroDataSource(uri)
|
||||
this.collections = new Collections(this.dataSource)
|
||||
}
|
||||
@ -32,8 +31,8 @@ export default class ActivityPub {
|
||||
static init (server) {
|
||||
if (!activityPub) {
|
||||
dotenv.config()
|
||||
const url = new URL(process.env.GRAPHQL_URI)
|
||||
activityPub = new ActivityPub(url.hostname || 'localhost', url.port || 4000, url.origin)
|
||||
const url = new URL(process.env.CLIENT_URI)
|
||||
activityPub = new ActivityPub(url.host || 'localhost:4000', url.origin)
|
||||
|
||||
// integrate into running graphql express server
|
||||
server.express.set('ap', activityPub)
|
||||
@ -59,7 +58,7 @@ export default class ActivityPub {
|
||||
}
|
||||
}, async (err, response, toActorObject) => {
|
||||
if (err) return reject(err)
|
||||
debug(`name = ${toActorName}@${this.domain}`)
|
||||
debug(`name = ${toActorName}@${this.host}`)
|
||||
// save shared inbox
|
||||
toActorObject = JSON.parse(toActorObject)
|
||||
await this.dataSource.addSharedInboxEndpoint(toActorObject.endpoints.sharedInbox)
|
||||
@ -184,7 +183,7 @@ export default class ActivityPub {
|
||||
}
|
||||
|
||||
generateStatusId (slug) {
|
||||
return `http://${this.domain}/activitypub/users/${slug}/status/${uuid()}`
|
||||
return `https://${this.host}/activitypub/users/${slug}/status/${uuid()}`
|
||||
}
|
||||
|
||||
async sendActivity (activity) {
|
||||
|
||||
@ -11,14 +11,14 @@ export function createNoteObject (text, name, id, published) {
|
||||
|
||||
return {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'id': `https://${activityPub.domain}/activitypub/users/${name}/status/${createUuid}`,
|
||||
'id': `https://${activityPub.host}/activitypub/users/${name}/status/${createUuid}`,
|
||||
'type': 'Create',
|
||||
'actor': `https://${activityPub.domain}/activitypub/users/${name}`,
|
||||
'actor': `https://${activityPub.host}/activitypub/users/${name}`,
|
||||
'object': {
|
||||
'id': `https://${activityPub.domain}/activitypub/users/${name}/status/${id}`,
|
||||
'id': `https://${activityPub.host}/activitypub/users/${name}/status/${id}`,
|
||||
'type': 'Note',
|
||||
'published': published,
|
||||
'attributedTo': `https://${activityPub.domain}/activitypub/users/${name}`,
|
||||
'attributedTo': `https://${activityPub.host}/activitypub/users/${name}`,
|
||||
'content': text,
|
||||
'to': 'https://www.w3.org/ns/activitystreams#Public'
|
||||
}
|
||||
@ -64,8 +64,8 @@ export async function getActorId (name) {
|
||||
|
||||
export function sendAcceptActivity (theBody, name, targetDomain, url) {
|
||||
as.accept()
|
||||
.id(`https://${activityPub.domain}/activitypub/users/${name}/status/` + crypto.randomBytes(16).toString('hex'))
|
||||
.actor(`https://${activityPub.domain}/activitypub/users/${name}`)
|
||||
.id(`https://${activityPub.host}/activitypub/users/${name}/status/` + crypto.randomBytes(16).toString('hex'))
|
||||
.actor(`https://${activityPub.host}/activitypub/users/${name}`)
|
||||
.object(theBody)
|
||||
.prettyWrite((err, doc) => {
|
||||
if (!err) {
|
||||
@ -79,8 +79,8 @@ export function sendAcceptActivity (theBody, name, targetDomain, url) {
|
||||
|
||||
export function sendRejectActivity (theBody, name, targetDomain, url) {
|
||||
as.reject()
|
||||
.id(`https://${activityPub.domain}/activitypub/users/${name}/status/` + crypto.randomBytes(16).toString('hex'))
|
||||
.actor(`https://${activityPub.domain}/activitypub/users/${name}`)
|
||||
.id(`https://${activityPub.host}/activitypub/users/${name}/status/` + crypto.randomBytes(16).toString('hex'))
|
||||
.actor(`https://${activityPub.host}/activitypub/users/${name}`)
|
||||
.object(theBody)
|
||||
.prettyWrite((err, doc) => {
|
||||
if (!err) {
|
||||
|
||||
@ -6,21 +6,21 @@ export function createActor (name, pubkey) {
|
||||
'https://www.w3.org/ns/activitystreams',
|
||||
'https://w3id.org/security/v1'
|
||||
],
|
||||
'id': `https://${activityPub.domain}/activitypub/users/${name}`,
|
||||
'id': `https://${activityPub.host}/activitypub/users/${name}`,
|
||||
'type': 'Person',
|
||||
'preferredUsername': `${name}`,
|
||||
'name': `${name}`,
|
||||
'following': `https://${activityPub.domain}/activitypub/users/${name}/following`,
|
||||
'followers': `https://${activityPub.domain}/activitypub/users/${name}/followers`,
|
||||
'inbox': `https://${activityPub.domain}/activitypub/users/${name}/inbox`,
|
||||
'outbox': `https://${activityPub.domain}/activitypub/users/${name}/outbox`,
|
||||
'url': `https://${activityPub.domain}/activitypub/@${name}`,
|
||||
'following': `https://${activityPub.host}/activitypub/users/${name}/following`,
|
||||
'followers': `https://${activityPub.host}/activitypub/users/${name}/followers`,
|
||||
'inbox': `https://${activityPub.host}/activitypub/users/${name}/inbox`,
|
||||
'outbox': `https://${activityPub.host}/activitypub/users/${name}/outbox`,
|
||||
'url': `https://${activityPub.host}/activitypub/@${name}`,
|
||||
'endpoints': {
|
||||
'sharedInbox': `https://${activityPub.domain}/activitypub/inbox`
|
||||
'sharedInbox': `https://${activityPub.host}/activitypub/inbox`
|
||||
},
|
||||
'publicKey': {
|
||||
'id': `https://${activityPub.domain}/activitypub/users/${name}#main-key`,
|
||||
'owner': `https://${activityPub.domain}/activitypub/users/${name}`,
|
||||
'id': `https://${activityPub.host}/activitypub/users/${name}#main-key`,
|
||||
'owner': `https://${activityPub.host}/activitypub/users/${name}`,
|
||||
'publicKeyPem': pubkey
|
||||
}
|
||||
}
|
||||
@ -28,12 +28,12 @@ export function createActor (name, pubkey) {
|
||||
|
||||
export function createWebFinger (name) {
|
||||
return {
|
||||
'subject': `acct:${name}@${activityPub.domain}`,
|
||||
'subject': `acct:${name}@${activityPub.host}`,
|
||||
'links': [
|
||||
{
|
||||
'rel': 'self',
|
||||
'type': 'application/activity+json',
|
||||
'href': `https://${activityPub.domain}/users/${name}`
|
||||
'href': `https://${activityPub.host}/activitypub/users/${name}`
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -5,10 +5,10 @@ const debug = require('debug')('ea:utils:collections')
|
||||
export function createOrderedCollection (name, collectionName) {
|
||||
return {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'id': `https://${activityPub.domain}/activitypub/users/${name}/${collectionName}`,
|
||||
'id': `https://${activityPub.host}/activitypub/users/${name}/${collectionName}`,
|
||||
'summary': `${name}s ${collectionName} collection`,
|
||||
'type': 'OrderedCollection',
|
||||
'first': `https://${activityPub.domain}/activitypub/users/${name}/${collectionName}?page=true`,
|
||||
'first': `https://${activityPub.host}/activitypub/users/${name}/${collectionName}?page=true`,
|
||||
'totalItems': 0
|
||||
}
|
||||
}
|
||||
@ -16,11 +16,11 @@ export function createOrderedCollection (name, collectionName) {
|
||||
export function createOrderedCollectionPage (name, collectionName) {
|
||||
return {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'id': `https://${activityPub.domain}/activitypub/users/${name}/${collectionName}?page=true`,
|
||||
'id': `https://${activityPub.host}/activitypub/users/${name}/${collectionName}?page=true`,
|
||||
'summary': `${name}s ${collectionName} collection`,
|
||||
'type': 'OrderedCollectionPage',
|
||||
'totalItems': 0,
|
||||
'partOf': `https://${activityPub.domain}/activitypub/users/${name}/${collectionName}`,
|
||||
'partOf': `https://${activityPub.host}/activitypub/users/${name}/${collectionName}`,
|
||||
'orderedItems': []
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,12 +20,12 @@ export function extractIdFromActivityId (uri) {
|
||||
return splitted[splitted.indexOf('status') + 1]
|
||||
}
|
||||
|
||||
export function constructIdFromName (name, fromDomain = activityPub.domain) {
|
||||
export function constructIdFromName (name, fromDomain = activityPub.host) {
|
||||
return `http://${fromDomain}/activitypub/users/${name}`
|
||||
}
|
||||
|
||||
export function extractDomainFromUrl (url) {
|
||||
return new URL(url).hostname
|
||||
return new URL(url).host
|
||||
}
|
||||
|
||||
export function throwErrorIfApolloErrorOccurred (result) {
|
||||
@ -76,7 +76,7 @@ export function signAndSend (activity, fromName, targetDomain, url) {
|
||||
'Host': targetDomain,
|
||||
'Date': date,
|
||||
'Signature': createSignature({ privateKey,
|
||||
keyId: `http://${activityPub.domain}/activitypub/users/${fromName}#main-key`,
|
||||
keyId: `http://${activityPub.host}/activitypub/users/${fromName}#main-key`,
|
||||
url,
|
||||
headers: {
|
||||
'Host': targetDomain,
|
||||
|
||||
@ -12,6 +12,6 @@ const serverConfig = {
|
||||
const server = createServer()
|
||||
server.start(serverConfig, options => {
|
||||
/* eslint-disable-next-line no-console */
|
||||
console.log(`Server ready at ${process.env.GRAPHQL_URI} 🚀`)
|
||||
console.log(`Server ready at ${process.env.CLIENT_URI} 🚀`)
|
||||
ActivityPub.init(server)
|
||||
})
|
||||
|
||||
@ -49,7 +49,7 @@ export default {
|
||||
CreateUser: async (resolve, root, args, context, info) => {
|
||||
const keys = generateRsaKeyPair()
|
||||
Object.assign(args, keys)
|
||||
args.actorId = `${process.env.GRAPHQL_URI}/activitypub/users/${args.slug}`
|
||||
args.actorId = `${activityPub.host}/activitypub/users/${args.slug}`
|
||||
return resolve(root, args, context, info)
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ Feature: Webfinger discovery
|
||||
{
|
||||
"rel": "self",
|
||||
"type": "application/activity+json",
|
||||
"href": "https://localhost:4123/users/peter-lustiger"
|
||||
"href": "https://localhost:4123/activitypub/users/peter-lustiger"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -38,18 +38,18 @@
|
||||
dependencies:
|
||||
"@babel/highlight" "^7.0.0"
|
||||
|
||||
"@babel/core@^7.1.0":
|
||||
version "7.3.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.3.3.tgz#d090d157b7c5060d05a05acaebc048bd2b037947"
|
||||
integrity sha512-w445QGI2qd0E0GlSnq6huRZWPMmQGCp5gd5ZWS4hagn0EiwzxD5QMFkpchyusAyVC1n27OKXzQ0/88aVU9n4xQ==
|
||||
"@babel/core@^7.1.0", "@babel/core@~7.4.0":
|
||||
version "7.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.4.0.tgz#248fd6874b7d755010bfe61f557461d4f446d9e9"
|
||||
integrity sha512-Dzl7U0/T69DFOTwqz/FJdnOSWS57NpjNfCwMKHABr589Lg8uX1RrlBIJ7L5Dubt/xkLsx0xH5EBFzlBVes1ayA==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.0.0"
|
||||
"@babel/generator" "^7.3.3"
|
||||
"@babel/helpers" "^7.2.0"
|
||||
"@babel/parser" "^7.3.3"
|
||||
"@babel/template" "^7.2.2"
|
||||
"@babel/traverse" "^7.2.2"
|
||||
"@babel/types" "^7.3.3"
|
||||
"@babel/generator" "^7.4.0"
|
||||
"@babel/helpers" "^7.4.0"
|
||||
"@babel/parser" "^7.4.0"
|
||||
"@babel/template" "^7.4.0"
|
||||
"@babel/traverse" "^7.4.0"
|
||||
"@babel/types" "^7.4.0"
|
||||
convert-source-map "^1.1.0"
|
||||
debug "^4.1.0"
|
||||
json5 "^2.1.0"
|
||||
@ -58,49 +58,7 @@
|
||||
semver "^5.4.1"
|
||||
source-map "^0.5.0"
|
||||
|
||||
"@babel/core@~7.3.4":
|
||||
version "7.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.3.4.tgz#921a5a13746c21e32445bf0798680e9d11a6530b"
|
||||
integrity sha512-jRsuseXBo9pN197KnDwhhaaBzyZr2oIcLHHTt2oDdQrej5Qp57dCCJafWx5ivU8/alEYDpssYqv1MUqcxwQlrA==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.0.0"
|
||||
"@babel/generator" "^7.3.4"
|
||||
"@babel/helpers" "^7.2.0"
|
||||
"@babel/parser" "^7.3.4"
|
||||
"@babel/template" "^7.2.2"
|
||||
"@babel/traverse" "^7.3.4"
|
||||
"@babel/types" "^7.3.4"
|
||||
convert-source-map "^1.1.0"
|
||||
debug "^4.1.0"
|
||||
json5 "^2.1.0"
|
||||
lodash "^4.17.11"
|
||||
resolve "^1.3.2"
|
||||
semver "^5.4.1"
|
||||
source-map "^0.5.0"
|
||||
|
||||
"@babel/generator@^7.0.0", "@babel/generator@^7.2.2", "@babel/generator@^7.3.3":
|
||||
version "7.3.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.3.tgz#185962ade59a52e00ca2bdfcfd1d58e528d4e39e"
|
||||
integrity sha512-aEADYwRRZjJyMnKN7llGIlircxTCofm3dtV5pmY6ob18MSIuipHpA2yZWkPlycwu5HJcx/pADS3zssd8eY7/6A==
|
||||
dependencies:
|
||||
"@babel/types" "^7.3.3"
|
||||
jsesc "^2.5.1"
|
||||
lodash "^4.17.11"
|
||||
source-map "^0.5.0"
|
||||
trim-right "^1.0.1"
|
||||
|
||||
"@babel/generator@^7.3.4":
|
||||
version "7.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.4.tgz#9aa48c1989257877a9d971296e5b73bfe72e446e"
|
||||
integrity sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==
|
||||
dependencies:
|
||||
"@babel/types" "^7.3.4"
|
||||
jsesc "^2.5.1"
|
||||
lodash "^4.17.11"
|
||||
source-map "^0.5.0"
|
||||
trim-right "^1.0.1"
|
||||
|
||||
"@babel/generator@^7.4.0":
|
||||
"@babel/generator@^7.0.0", "@babel/generator@^7.4.0":
|
||||
version "7.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.4.0.tgz#c230e79589ae7a729fd4631b9ded4dc220418196"
|
||||
integrity sha512-/v5I+a1jhGSKLgZDcmAUZ4K/VePi43eRkUs3yePW1HB1iANOD5tqJXwGSG4BZhSksP8J9ejSlwGeTiiOFZOrXQ==
|
||||
@ -283,14 +241,14 @@
|
||||
"@babel/traverse" "^7.1.0"
|
||||
"@babel/types" "^7.2.0"
|
||||
|
||||
"@babel/helpers@^7.2.0":
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.2.0.tgz#8335f3140f3144270dc63c4732a4f8b0a50b7a21"
|
||||
integrity sha512-Fr07N+ea0dMcMN8nFpuK6dUIT7/ivt9yKQdEEnjVS83tG2pHwPi03gYmk/tyuwONnZ+sY+GFFPlWGgCtW1hF9A==
|
||||
"@babel/helpers@^7.4.0":
|
||||
version "7.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.4.2.tgz#3bdfa46a552ca77ef5a0f8551be5f0845ae989be"
|
||||
integrity sha512-gQR1eQeroDzFBikhrCccm5Gs2xBjZ57DNjGbqTaHo911IpmSxflOQWMAHPw/TXk8L3isv7s9lYzUkexOeTQUYg==
|
||||
dependencies:
|
||||
"@babel/template" "^7.1.2"
|
||||
"@babel/traverse" "^7.1.5"
|
||||
"@babel/types" "^7.2.0"
|
||||
"@babel/template" "^7.4.0"
|
||||
"@babel/traverse" "^7.4.0"
|
||||
"@babel/types" "^7.4.0"
|
||||
|
||||
"@babel/highlight@^7.0.0":
|
||||
version "7.0.0"
|
||||
@ -312,17 +270,7 @@
|
||||
lodash "^4.17.10"
|
||||
v8flags "^3.1.1"
|
||||
|
||||
"@babel/parser@^7.0.0", "@babel/parser@^7.2.2", "@babel/parser@^7.2.3", "@babel/parser@^7.3.3":
|
||||
version "7.3.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.3.tgz#092d450db02bdb6ccb1ca8ffd47d8774a91aef87"
|
||||
integrity sha512-xsH1CJoln2r74hR+y7cg2B5JCPaTh+Hd+EbBRk9nWGSNspuo6krjhX0Om6RnRQuIvFq8wVXCLKH3kwKDYhanSg==
|
||||
|
||||
"@babel/parser@^7.1.0", "@babel/parser@^7.3.4":
|
||||
version "7.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.4.tgz#a43357e4bbf4b92a437fb9e465c192848287f27c"
|
||||
integrity sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==
|
||||
|
||||
"@babel/parser@^7.4.0":
|
||||
"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.4.0":
|
||||
version "7.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.2.tgz#b4521a400cb5a871eab3890787b4bc1326d38d91"
|
||||
integrity sha512-9fJTDipQFvlfSVdD/JBtkiY0br9BtfvW2R8wo6CX/Ej2eMuV0gWPk1M67Mt3eggQvBqYW1FCEk8BN7WvGm/g5g==
|
||||
@ -720,46 +668,16 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.2"
|
||||
|
||||
"@babel/template@^7.0.0", "@babel/template@^7.1.0", "@babel/template@^7.1.2", "@babel/template@^7.2.2":
|
||||
version "7.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.2.2.tgz#005b3fdf0ed96e88041330379e0da9a708eb2907"
|
||||
integrity sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==
|
||||
"@babel/template@^7.0.0", "@babel/template@^7.1.0", "@babel/template@^7.4.0":
|
||||
version "7.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.0.tgz#12474e9c077bae585c5d835a95c0b0b790c25c8b"
|
||||
integrity sha512-SOWwxxClTTh5NdbbYZ0BmaBVzxzTh2tO/TeLTbF6MO6EzVhHTnff8CdBXx3mEtazFBoysmEM6GU/wF+SuSx4Fw==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.0.0"
|
||||
"@babel/parser" "^7.2.2"
|
||||
"@babel/types" "^7.2.2"
|
||||
"@babel/parser" "^7.4.0"
|
||||
"@babel/types" "^7.4.0"
|
||||
|
||||
"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.1.5", "@babel/traverse@^7.2.2":
|
||||
version "7.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.2.3.tgz#7ff50cefa9c7c0bd2d81231fdac122f3957748d8"
|
||||
integrity sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.0.0"
|
||||
"@babel/generator" "^7.2.2"
|
||||
"@babel/helper-function-name" "^7.1.0"
|
||||
"@babel/helper-split-export-declaration" "^7.0.0"
|
||||
"@babel/parser" "^7.2.3"
|
||||
"@babel/types" "^7.2.2"
|
||||
debug "^4.1.0"
|
||||
globals "^11.1.0"
|
||||
lodash "^4.17.10"
|
||||
|
||||
"@babel/traverse@^7.3.4":
|
||||
version "7.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.3.4.tgz#1330aab72234f8dea091b08c4f8b9d05c7119e06"
|
||||
integrity sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.0.0"
|
||||
"@babel/generator" "^7.3.4"
|
||||
"@babel/helper-function-name" "^7.1.0"
|
||||
"@babel/helper-split-export-declaration" "^7.0.0"
|
||||
"@babel/parser" "^7.3.4"
|
||||
"@babel/types" "^7.3.4"
|
||||
debug "^4.1.0"
|
||||
globals "^11.1.0"
|
||||
lodash "^4.17.11"
|
||||
|
||||
"@babel/traverse@^7.4.0":
|
||||
"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.0":
|
||||
version "7.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.4.0.tgz#14006967dd1d2b3494cdd650c686db9daf0ddada"
|
||||
integrity sha512-/DtIHKfyg2bBKnIN+BItaIlEg5pjAnzHOIQe5w+rHAw/rg9g0V7T4rqPX8BJPfW11kt3koyjAnTNwCzb28Y1PA==
|
||||
@ -774,7 +692,7 @@
|
||||
globals "^11.1.0"
|
||||
lodash "^4.17.11"
|
||||
|
||||
"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.3.4", "@babel/types@^7.4.0":
|
||||
"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.3.0", "@babel/types@^7.4.0":
|
||||
version "7.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.4.0.tgz#670724f77d24cce6cc7d8cf64599d511d164894c"
|
||||
integrity sha512-aPvkXyU2SPOnztlgo8n9cEiXW755mgyvueUPcpStqdzoSPm0fjO0vQBjLkt3JKJW7ufikfcnMTTPsN1xaTsBPA==
|
||||
@ -4011,10 +3929,10 @@ helmet-csp@2.7.1:
|
||||
dasherize "2.0.0"
|
||||
platform "1.3.5"
|
||||
|
||||
helmet@~3.15.1:
|
||||
version "3.15.1"
|
||||
resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.15.1.tgz#2c80d1a59138b6f23929605afca4b1c88b3298ec"
|
||||
integrity sha512-hgoNe/sjKlKNvJ3g9Gz149H14BjMMWOCmW/DTXl7IfyKGtIK37GePwZrHNfr4aPXdKVyXcTj26RgRFbPKDy9lw==
|
||||
helmet@~3.16.0:
|
||||
version "3.16.0"
|
||||
resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.16.0.tgz#7df41a4bfe4c83d90147c1e30d70893f92a9d97c"
|
||||
integrity sha512-rsTKRogc5OYGlvSHuq5QsmOsOzF6uDoMqpfh+Np8r23+QxDq+SUx90Rf8HyIKQVl7H6NswZEwfcykinbAeZ6UQ==
|
||||
dependencies:
|
||||
depd "2.0.0"
|
||||
dns-prefetch-control "0.1.0"
|
||||
@ -4026,8 +3944,8 @@ helmet@~3.15.1:
|
||||
helmet-csp "2.7.1"
|
||||
hide-powered-by "1.0.0"
|
||||
hpkp "2.0.0"
|
||||
hsts "2.1.0"
|
||||
ienoopen "1.0.0"
|
||||
hsts "2.2.0"
|
||||
ienoopen "1.1.0"
|
||||
nocache "2.0.0"
|
||||
referrer-policy "1.1.0"
|
||||
x-xss-protection "1.1.0"
|
||||
@ -4064,10 +3982,12 @@ hpkp@2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/hpkp/-/hpkp-2.0.0.tgz#10e142264e76215a5d30c44ec43de64dee6d1672"
|
||||
integrity sha1-EOFCJk52IVpdMMROxD3mTe5tFnI=
|
||||
|
||||
hsts@2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/hsts/-/hsts-2.1.0.tgz#cbd6c918a2385fee1dd5680bfb2b3a194c0121cc"
|
||||
integrity sha512-zXhh/DqgrTXJ7erTN6Fh5k/xjMhDGXCqdYN3wvxUvGUQvnxcFfUd8E+6vLg/nk3ss1TYMb+DhRl25fYABioTvA==
|
||||
hsts@2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/hsts/-/hsts-2.2.0.tgz#09119d42f7a8587035d027dda4522366fe75d964"
|
||||
integrity sha512-ToaTnQ2TbJkochoVcdXYm4HOCliNozlviNsg+X2XQLQvZNI/kCHR9rZxVYpJB3UPcHz80PgxRyWQ7PdU1r+VBQ==
|
||||
dependencies:
|
||||
depd "2.0.0"
|
||||
|
||||
html-encoding-sniffer@^1.0.2:
|
||||
version "1.0.2"
|
||||
@ -4142,10 +4062,10 @@ ieee754@^1.1.4:
|
||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b"
|
||||
integrity sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==
|
||||
|
||||
ienoopen@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ienoopen/-/ienoopen-1.0.0.tgz#346a428f474aac8f50cf3784ea2d0f16f62bda6b"
|
||||
integrity sha1-NGpCj0dKrI9QzzeE6i0PFvYr2ms=
|
||||
ienoopen@1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ienoopen/-/ienoopen-1.1.0.tgz#411e5d530c982287dbdc3bb31e7a9c9e32630974"
|
||||
integrity sha512-MFs36e/ca6ohEKtinTJ5VvAJ6oDRAYFdYXweUnGY9L9vcoqFOU4n2ZhmJ0C4z/cwGZ3YIQRSB3XZ1+ghZkY5NQ==
|
||||
|
||||
ignore-by-default@^1.0.1:
|
||||
version "1.0.1"
|
||||
|
||||
@ -5,7 +5,7 @@ import { getLangByName } from '../../support/helpers'
|
||||
|
||||
let lastPost = {}
|
||||
|
||||
const loginCredentials = {
|
||||
let loginCredentials = {
|
||||
email: 'peterpan@example.org',
|
||||
password: '1234'
|
||||
}
|
||||
@ -244,3 +244,48 @@ Then(
|
||||
cy.get('.error').should('contain', message)
|
||||
}
|
||||
)
|
||||
|
||||
Given('my user account has the following login credentials:', table => {
|
||||
loginCredentials = table.hashes()[0]
|
||||
cy.debug()
|
||||
cy.factory().create('User', loginCredentials)
|
||||
})
|
||||
|
||||
When('I fill the password form with:', table => {
|
||||
table = table.rowsHash()
|
||||
cy.get('input[id=oldPassword]')
|
||||
.type(table['Your old password'])
|
||||
.get('input[id=newPassword]')
|
||||
.type(table['Your new passsword'])
|
||||
.get('input[id=confirmPassword]')
|
||||
.type(table['Confirm new password'])
|
||||
})
|
||||
|
||||
When('submit the form', () => {
|
||||
cy.get('form').submit()
|
||||
})
|
||||
|
||||
Then('I cannot login anymore with password {string}', password => {
|
||||
cy.reload()
|
||||
const { email } = loginCredentials
|
||||
cy.visit(`/login`)
|
||||
cy.get('input[name=email]')
|
||||
.trigger('focus')
|
||||
.type(email)
|
||||
cy.get('input[name=password]')
|
||||
.trigger('focus')
|
||||
.type(password)
|
||||
cy.get('button[name=submit]')
|
||||
.as('submitButton')
|
||||
.click()
|
||||
cy.get('.iziToast-wrapper').should('contain', 'Incorrect email address or password.')
|
||||
})
|
||||
|
||||
Then('I can login successfully with password {string}', password => {
|
||||
cy.reload()
|
||||
cy.login({
|
||||
...loginCredentials,
|
||||
...{password}
|
||||
})
|
||||
cy.get('.iziToast-wrapper').should('contain', "You are logged in!")
|
||||
})
|
||||
|
||||
31
cypress/integration/settings/ChangePassword.feature
Normal file
31
cypress/integration/settings/ChangePassword.feature
Normal file
@ -0,0 +1,31 @@
|
||||
Feature: Change password
|
||||
As a user
|
||||
I want to change my password in my settings
|
||||
For security, e.g. if I exposed my password by accident
|
||||
|
||||
Login via email and password is a well-known authentication procedure and you
|
||||
can assure to the server that you are who you claim to be. Either if you
|
||||
exposed your password by acccident and you want to invalidate the exposed
|
||||
password or just out of an good habit, you want to change your password.
|
||||
|
||||
Background:
|
||||
Given my user account has the following login credentials:
|
||||
| email | password |
|
||||
| user@example.org | exposed |
|
||||
And I am logged in
|
||||
|
||||
Scenario: Change my password
|
||||
Given I am on the "settings" page
|
||||
And I click on "Security"
|
||||
When I fill the password form with:
|
||||
| Your old password | exposed |
|
||||
| Your new passsword | secure |
|
||||
| Confirm new password | secure |
|
||||
And submit the form
|
||||
And I see a success message:
|
||||
"""
|
||||
Password successfully changed!
|
||||
"""
|
||||
And I log out through the menu in the top right corner
|
||||
Then I cannot login anymore with password "exposed"
|
||||
But I can login successfully with password "secure"
|
||||
@ -4,8 +4,6 @@
|
||||
metadata:
|
||||
name: nitro-backend
|
||||
namespace: human-connection
|
||||
labels:
|
||||
commit: "COMMIT"
|
||||
spec:
|
||||
replicas: 1
|
||||
minReadySeconds: 15
|
||||
@ -20,6 +18,7 @@
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
human-connection.org/commit: COMMIT
|
||||
human-connection.org/selector: deployment-human-connection-backend
|
||||
name: "nitro-backend"
|
||||
spec:
|
||||
|
||||
@ -3,8 +3,6 @@ kind: Deployment
|
||||
metadata:
|
||||
name: nitro-web
|
||||
namespace: human-connection
|
||||
labels:
|
||||
commit: "COMMIT"
|
||||
spec:
|
||||
replicas: 2
|
||||
minReadySeconds: 15
|
||||
@ -15,6 +13,7 @@ spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
human-connection.org/commit: COMMIT
|
||||
human-connection.org/selector: deployment-human-connection-web
|
||||
name: nitro-web
|
||||
spec:
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
metadata:
|
||||
labels:
|
||||
commit: <COMMIT>
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
human-connection.org/commit: <COMMIT>
|
||||
|
||||
154
webapp/components/ChangePassword.spec.js
Normal file
154
webapp/components/ChangePassword.spec.js
Normal file
@ -0,0 +1,154 @@
|
||||
import { mount, createLocalVue } from '@vue/test-utils'
|
||||
import ChangePassword from './ChangePassword.vue'
|
||||
import Vue from 'vue'
|
||||
import Styleguide from '@human-connection/styleguide'
|
||||
|
||||
const localVue = createLocalVue()
|
||||
|
||||
localVue.use(Styleguide)
|
||||
|
||||
describe('ChangePassword.vue', () => {
|
||||
let mocks
|
||||
let wrapper
|
||||
|
||||
beforeEach(() => {
|
||||
mocks = {
|
||||
validate: jest.fn(),
|
||||
$toast: {
|
||||
error: jest.fn(),
|
||||
success: jest.fn()
|
||||
},
|
||||
$t: jest.fn(),
|
||||
$store: {
|
||||
commit: jest.fn()
|
||||
},
|
||||
$apollo: {
|
||||
mutate: jest
|
||||
.fn()
|
||||
.mockRejectedValue({ message: 'Ouch!' })
|
||||
.mockResolvedValueOnce({ data: { changePassword: 'NEWTOKEN' } })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
describe('mount', () => {
|
||||
let wrapper
|
||||
const Wrapper = () => {
|
||||
return mount(ChangePassword, { mocks, localVue })
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
it('renders three input fields', () => {
|
||||
expect(wrapper.findAll('input')).toHaveLength(3)
|
||||
})
|
||||
|
||||
describe('validations', () => {
|
||||
it('invalid', () => {
|
||||
expect(wrapper.vm.disabled).toBe(true)
|
||||
})
|
||||
|
||||
describe('old password and new password', () => {
|
||||
describe('match', () => {
|
||||
beforeEach(() => {
|
||||
wrapper.find('input#oldPassword').setValue('some secret')
|
||||
wrapper.find('input#newPassword').setValue('some secret')
|
||||
})
|
||||
|
||||
it('invalid', () => {
|
||||
expect(wrapper.vm.disabled).toBe(true)
|
||||
})
|
||||
|
||||
it.skip('displays a warning', () => {
|
||||
const calls = mocks.validate.mock.calls
|
||||
const expected = [
|
||||
['change-password.validations.old-and-new-password-match']
|
||||
]
|
||||
expect(calls).toEqual(expect.arrayContaining(expected))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('new password and confirmation', () => {
|
||||
describe('mismatch', () => {
|
||||
it.todo('invalid')
|
||||
it.todo('displays a warning')
|
||||
})
|
||||
|
||||
describe('match', () => {
|
||||
describe('and old password mismatch', () => {
|
||||
it.todo('valid')
|
||||
})
|
||||
|
||||
describe('clicked', () => {
|
||||
it.todo('sets loading')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('given valid input', () => {
|
||||
beforeEach(() => {
|
||||
wrapper.find('input#oldPassword').setValue('supersecret')
|
||||
wrapper.find('input#newPassword').setValue('superdupersecret')
|
||||
wrapper.find('input#confirmPassword').setValue('superdupersecret')
|
||||
})
|
||||
|
||||
describe('submit form', () => {
|
||||
beforeEach(() => {
|
||||
wrapper.find('form').trigger('submit')
|
||||
})
|
||||
|
||||
it('calls changePassword mutation', () => {
|
||||
expect(mocks.$apollo.mutate).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('passes form data as variables', () => {
|
||||
expect(mocks.$apollo.mutate.mock.calls[0][0]).toEqual(
|
||||
expect.objectContaining({
|
||||
variables: {
|
||||
oldPassword: 'supersecret',
|
||||
newPassword: 'superdupersecret',
|
||||
confirmPassword: 'superdupersecret'
|
||||
}
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
describe('mutation resolves', () => {
|
||||
beforeEach(() => {
|
||||
mocks.$apollo.mutate = jest.fn().mockResolvedValue()
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
it('calls auth/SET_TOKEN with response', () => {
|
||||
expect(mocks.$store.commit).toHaveBeenCalledWith(
|
||||
'auth/SET_TOKEN',
|
||||
'NEWTOKEN'
|
||||
)
|
||||
})
|
||||
|
||||
it('displays success message', () => {
|
||||
expect(mocks.$t).toHaveBeenCalledWith(
|
||||
'settings.security.change-password.success'
|
||||
)
|
||||
expect(mocks.$toast.success).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('mutation rejects', () => {
|
||||
beforeEach(() => {
|
||||
// second call will reject
|
||||
wrapper.find('form').trigger('submit')
|
||||
})
|
||||
|
||||
it('displays error message', () => {
|
||||
expect(mocks.$toast.error).toHaveBeenCalledWith('Ouch!')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
83
webapp/components/ChangePassword.vue
Normal file
83
webapp/components/ChangePassword.vue
Normal file
@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<ds-form
|
||||
v-model="formData"
|
||||
:schema="formSchema"
|
||||
@submit="handleSubmit"
|
||||
>
|
||||
<template>
|
||||
<ds-input
|
||||
id="oldPassword"
|
||||
model="oldPassword"
|
||||
type="password"
|
||||
label="Your old password"
|
||||
/>
|
||||
<ds-input
|
||||
id="newPassword"
|
||||
model="newPassword"
|
||||
type="password"
|
||||
label="Your new password"
|
||||
/>
|
||||
<ds-input
|
||||
id="confirmPassword"
|
||||
model="confirmPassword"
|
||||
type="password"
|
||||
label="Confirm new password"
|
||||
/>
|
||||
<ds-space margin-top="base">
|
||||
<ds-button
|
||||
:loading="loading"
|
||||
primary
|
||||
>
|
||||
{{ $t('settings.security.change-password.button') }}
|
||||
</ds-button>
|
||||
</ds-space>
|
||||
</template>
|
||||
</ds-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export default {
|
||||
name: 'ChangePassword',
|
||||
data() {
|
||||
return {
|
||||
formData: {
|
||||
oldPassword: '',
|
||||
newPassword: '',
|
||||
confirmPassword: ''
|
||||
},
|
||||
formSchema: {
|
||||
oldPassword: { required: true },
|
||||
newPassword: { required: true },
|
||||
confirmPassword: { required: true }
|
||||
},
|
||||
loading: false,
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async handleSubmit(data) {
|
||||
this.loading = true
|
||||
const mutation = gql`
|
||||
mutation($oldPassword: String!, $newPassword: String!) {
|
||||
changePassword(oldPassword: $oldPassword, newPassword: $newPassword)
|
||||
}
|
||||
`
|
||||
const variables = this.formData
|
||||
|
||||
try {
|
||||
const { data } = await this.$apollo.mutate({ mutation, variables })
|
||||
this.$store.commit('auth/SET_TOKEN', data.changePassword)
|
||||
this.$toast.success(
|
||||
this.$t('settings.security.change-password.success')
|
||||
)
|
||||
} catch (err) {
|
||||
this.$toast.error(err.message)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -31,7 +31,11 @@
|
||||
"labelBio": "Über dich"
|
||||
},
|
||||
"security": {
|
||||
"name": "Sicherheit"
|
||||
"name": "Sicherheit",
|
||||
"change-password": {
|
||||
"button": "Passwort ändern",
|
||||
"success": "Passwort erfolgreich geändert!"
|
||||
}
|
||||
},
|
||||
"invites": {
|
||||
"name": "Einladungen"
|
||||
|
||||
@ -31,7 +31,11 @@
|
||||
"labelBio": "About You"
|
||||
},
|
||||
"security": {
|
||||
"name": "Security"
|
||||
"name": "Security",
|
||||
"change-password": {
|
||||
"button": "Change password",
|
||||
"success": "Password successfully changed!"
|
||||
}
|
||||
},
|
||||
"invites": {
|
||||
"name": "Invites"
|
||||
|
||||
@ -121,12 +121,21 @@ module.exports = {
|
||||
proxy: true
|
||||
},
|
||||
proxy: {
|
||||
'/.well-known/webfinger': {
|
||||
target: process.env.GRAPHQL_URI || 'http://localhost:4000',
|
||||
toProxy: true // cloudflare needs that
|
||||
},
|
||||
'/activityPub': {
|
||||
// make this configurable (nuxt-dotenv)
|
||||
target: process.env.GRAPHQL_URI || 'http://localhost:4000',
|
||||
pathRewrite: { '^/activityPub': '' },
|
||||
toProxy: true // cloudflare needs that
|
||||
},
|
||||
'/api': {
|
||||
// make this configurable (nuxt-dotenv)
|
||||
target: process.env.GRAPHQL_URI || 'http://localhost:4000',
|
||||
pathRewrite: { '^/api': '' },
|
||||
toProxy: true, // cloudflare needs that
|
||||
changeOrigin: true,
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'X-UI-Request': true,
|
||||
|
||||
@ -1,18 +1,16 @@
|
||||
<template>
|
||||
<ds-card :header="$t('settings.security.name')">
|
||||
<hc-empty
|
||||
icon="tasks"
|
||||
message="Coming Soon…"
|
||||
/>
|
||||
<change-password />
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HcEmpty from '~/components/Empty.vue'
|
||||
import ChangePassword from '~/components/ChangePassword.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HcEmpty
|
||||
ChangePassword
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user