From defb93ba7fbeee5ee0ce5bf978ea75e4c1cd7f4a Mon Sep 17 00:00:00 2001 From: Einhornimmond Date: Mon, 13 Sep 2021 16:33:24 +0200 Subject: [PATCH 01/17] my thoughts to jwt --- .../Snippets/Authorization/concept.md | 28 +++++++++++++++++++ docu/Concepts/Snippets/Authorization/jwt.md | 20 +++++++++++++ .../Snippets/Authorization/session_id.md | 16 +++++++++++ 3 files changed, 64 insertions(+) create mode 100644 docu/Concepts/Snippets/Authorization/concept.md create mode 100644 docu/Concepts/Snippets/Authorization/jwt.md create mode 100644 docu/Concepts/Snippets/Authorization/session_id.md diff --git a/docu/Concepts/Snippets/Authorization/concept.md b/docu/Concepts/Snippets/Authorization/concept.md new file mode 100644 index 000000000..5d189b3be --- /dev/null +++ b/docu/Concepts/Snippets/Authorization/concept.md @@ -0,0 +1,28 @@ +# Authorization and Private Keys +## Keys +For creating transactions ed25519 keys are used for signing. +As long the user is the only controlling the private key he is the only one +how can sign transactions on his behalf. +It is a core concept of all crypto currencies and important for the concept, +that the user has full control over his data. + +Usually crypto currencies like bitcoin or iota save the keys on local system, +maybe additional protected with a password which is used to encrypt the keys. + +## Gradido +Gradido should be easy to use, so we must offer a solution for everyone not that fit +with computer, as easy to use like paypal. +For that role we have the Login-Server. +It stores the private keys of the user encrypted with there email and password. +Additional it stores the passphrase which can be used to generate the private key, +encryted with server admin public key. So only the server admin can access the keys +with his private key. [not done yet] +It is needed for passwort reset if a user has forgetten his password. + +But for the entire concept Login-Server isn't the only way to store the private keys. +For users which has more experience with computer and especially with crypto currencies +it should be a way to keep there private keys by themselfs. + +For example a Desktop- or Handy-App which store the keys locally maybe additional encrypted. +Maybe it is possible to use Stronghold from iota for that. +With that the user don't need to use the Login-Server. \ No newline at end of file diff --git a/docu/Concepts/Snippets/Authorization/jwt.md b/docu/Concepts/Snippets/Authorization/jwt.md new file mode 100644 index 000000000..55355b2a5 --- /dev/null +++ b/docu/Concepts/Snippets/Authorization/jwt.md @@ -0,0 +1,20 @@ +# How JWT could be used for authorization with and without Login-Server +## What we need +The only encrypted data in db are the private key. +Every other data could be accessed without login, depending on frontend and backend code. +So we need only a way to prove the backend that we have access to the private key. + +## JWT +JWT is perfect for that. +We can use JWT to store the public key of the user as UUID for finding his data in db, +signing it with the private key. So even if the backend is running in multiple instances, +on every request is it possible to check the JWT token, that the signature is signed with +the private key, belonging to the public key. +The only thing the backend cannot do with that is signing a transaction. +That can only be done by the Login-Server or a Desktop or Handy-App storing the private key locally. +With that we have universal way for authorization against the backend. +We could additional store if we like to sign transactions local or with Login-Server and the Login-Server url. + + + + diff --git a/docu/Concepts/Snippets/Authorization/session_id.md b/docu/Concepts/Snippets/Authorization/session_id.md new file mode 100644 index 000000000..c8c64a87a --- /dev/null +++ b/docu/Concepts/Snippets/Authorization/session_id.md @@ -0,0 +1,16 @@ +# Session Id Authorization +## Login-Server +With every login, the Login-Server creates a session with a random id, +storing it in memory. For Login email and password are needed. +From email and an additional app-secret (**crypto.app_secret** in Login-Server config) a sha512 hash will be genereted, named **hash512_salt**. +With sodium function *crypto_pwhash* with **hash512_salt** and user password a secret encryption key will be calculated. +*crypto_pwhash* uses argon2 algorithmus to have a CPU hard calculation. Currently it is configured for < 0.5s. +So it is harder to use brute-force attacks to guess the password. Even if someone gets hands on the data saved in db. + +With sodium function *crypto_shorthash* a hash will be calculated from the secret encryption key and server crypto key (**crypto.server_key** in Login-Server config, hex encoded, 16 Bytes, 32 Character hex encoded) +and compared against saved hash in db. If they identical user has successfull logged in. +The secret encryption key will be stored in memory together with the user session and client ip from which login call came. +The session_id will be returned. +The session will be hold in memory for 15 minutes default, can be changed in Login-Server config field **session.timeout** + + From 3dc3b21e8a7c225ded199afa0c4fbdbd4813e21a Mon Sep 17 00:00:00 2001 From: Einhornimmond Date: Mon, 13 Sep 2021 16:33:24 +0200 Subject: [PATCH 02/17] my thoughts to jwt --- .../Snippets/Authorization/concept.md | 28 +++++++++++++++++++ docu/Concepts/Snippets/Authorization/jwt.md | 20 +++++++++++++ .../Snippets/Authorization/session_id.md | 16 +++++++++++ 3 files changed, 64 insertions(+) create mode 100644 docu/Concepts/Snippets/Authorization/concept.md create mode 100644 docu/Concepts/Snippets/Authorization/jwt.md create mode 100644 docu/Concepts/Snippets/Authorization/session_id.md diff --git a/docu/Concepts/Snippets/Authorization/concept.md b/docu/Concepts/Snippets/Authorization/concept.md new file mode 100644 index 000000000..5d189b3be --- /dev/null +++ b/docu/Concepts/Snippets/Authorization/concept.md @@ -0,0 +1,28 @@ +# Authorization and Private Keys +## Keys +For creating transactions ed25519 keys are used for signing. +As long the user is the only controlling the private key he is the only one +how can sign transactions on his behalf. +It is a core concept of all crypto currencies and important for the concept, +that the user has full control over his data. + +Usually crypto currencies like bitcoin or iota save the keys on local system, +maybe additional protected with a password which is used to encrypt the keys. + +## Gradido +Gradido should be easy to use, so we must offer a solution for everyone not that fit +with computer, as easy to use like paypal. +For that role we have the Login-Server. +It stores the private keys of the user encrypted with there email and password. +Additional it stores the passphrase which can be used to generate the private key, +encryted with server admin public key. So only the server admin can access the keys +with his private key. [not done yet] +It is needed for passwort reset if a user has forgetten his password. + +But for the entire concept Login-Server isn't the only way to store the private keys. +For users which has more experience with computer and especially with crypto currencies +it should be a way to keep there private keys by themselfs. + +For example a Desktop- or Handy-App which store the keys locally maybe additional encrypted. +Maybe it is possible to use Stronghold from iota for that. +With that the user don't need to use the Login-Server. \ No newline at end of file diff --git a/docu/Concepts/Snippets/Authorization/jwt.md b/docu/Concepts/Snippets/Authorization/jwt.md new file mode 100644 index 000000000..55355b2a5 --- /dev/null +++ b/docu/Concepts/Snippets/Authorization/jwt.md @@ -0,0 +1,20 @@ +# How JWT could be used for authorization with and without Login-Server +## What we need +The only encrypted data in db are the private key. +Every other data could be accessed without login, depending on frontend and backend code. +So we need only a way to prove the backend that we have access to the private key. + +## JWT +JWT is perfect for that. +We can use JWT to store the public key of the user as UUID for finding his data in db, +signing it with the private key. So even if the backend is running in multiple instances, +on every request is it possible to check the JWT token, that the signature is signed with +the private key, belonging to the public key. +The only thing the backend cannot do with that is signing a transaction. +That can only be done by the Login-Server or a Desktop or Handy-App storing the private key locally. +With that we have universal way for authorization against the backend. +We could additional store if we like to sign transactions local or with Login-Server and the Login-Server url. + + + + diff --git a/docu/Concepts/Snippets/Authorization/session_id.md b/docu/Concepts/Snippets/Authorization/session_id.md new file mode 100644 index 000000000..c8c64a87a --- /dev/null +++ b/docu/Concepts/Snippets/Authorization/session_id.md @@ -0,0 +1,16 @@ +# Session Id Authorization +## Login-Server +With every login, the Login-Server creates a session with a random id, +storing it in memory. For Login email and password are needed. +From email and an additional app-secret (**crypto.app_secret** in Login-Server config) a sha512 hash will be genereted, named **hash512_salt**. +With sodium function *crypto_pwhash* with **hash512_salt** and user password a secret encryption key will be calculated. +*crypto_pwhash* uses argon2 algorithmus to have a CPU hard calculation. Currently it is configured for < 0.5s. +So it is harder to use brute-force attacks to guess the password. Even if someone gets hands on the data saved in db. + +With sodium function *crypto_shorthash* a hash will be calculated from the secret encryption key and server crypto key (**crypto.server_key** in Login-Server config, hex encoded, 16 Bytes, 32 Character hex encoded) +and compared against saved hash in db. If they identical user has successfull logged in. +The secret encryption key will be stored in memory together with the user session and client ip from which login call came. +The session_id will be returned. +The session will be hold in memory for 15 minutes default, can be changed in Login-Server config field **session.timeout** + + From 2ca00810306cc1df93cc113424986f7be6d5c8bf Mon Sep 17 00:00:00 2001 From: Einhornimmond Date: Tue, 14 Sep 2021 11:41:53 +0200 Subject: [PATCH 03/17] append additional infos --- docu/Concepts/Snippets/Authorization/jwt.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docu/Concepts/Snippets/Authorization/jwt.md b/docu/Concepts/Snippets/Authorization/jwt.md index 55355b2a5..158613e36 100644 --- a/docu/Concepts/Snippets/Authorization/jwt.md +++ b/docu/Concepts/Snippets/Authorization/jwt.md @@ -15,6 +15,15 @@ That can only be done by the Login-Server or a Desktop or Handy-App storing the With that we have universal way for authorization against the backend. We could additional store if we like to sign transactions local or with Login-Server and the Login-Server url. +## JWT and Login-Server +Login-Server uses Poco version 1.9.4 but unfortunately Poco only introduces jwt from version 1.10. +And Updating to 1.10 needs some work because some things have changed in Poco 1.10. + +## JWT signature algorithms +In JWT standard ed25519 don't seemd to play a role. +We must find out if we can use the ed25519 keys together with one of the signature algorithms +in JWT standard or we must use **crypto_sign_verify_detached** from libsodium even it is nonstandard +to verify signature created with ed25519 keys and libsodiums **crypto_sign_detached** function. From 7ede572f4b62928cffe3cf54b1bf675c49fd265d Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 14 Sep 2021 16:25:14 +0200 Subject: [PATCH 04/17] refactor: Pagination Buttons --- frontend/src/components/PaginationButtons.vue | 42 ++++++++++++++----- .../AccountOverview/GdtTransactionList.vue | 18 ++------ 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/frontend/src/components/PaginationButtons.vue b/frontend/src/components/PaginationButtons.vue index 252301388..bf2c19488 100644 --- a/frontend/src/components/PaginationButtons.vue +++ b/frontend/src/components/PaginationButtons.vue @@ -7,7 +7,7 @@ -

{{ currentPage }} / {{ totalPages }}

+

{{ value }} / {{ totalPages }}

@@ -18,13 +18,35 @@ diff --git a/frontend/src/views/Pages/AccountOverview/GdtTransactionList.vue b/frontend/src/views/Pages/AccountOverview/GdtTransactionList.vue index 1ad4ba13e..8f1fd2839 100644 --- a/frontend/src/views/Pages/AccountOverview/GdtTransactionList.vue +++ b/frontend/src/views/Pages/AccountOverview/GdtTransactionList.vue @@ -29,10 +29,9 @@ @@ -58,17 +57,6 @@ export default { pageSize: 25, } }, - computed: { - hasNext() { - return this.currentPage * this.pageSize < this.transactionGdtCount - }, - hasPrevious() { - return this.currentPage > 1 - }, - totalPages() { - return Math.ceil(this.transactionGdtCount / this.pageSize) - }, - }, methods: { async updateGdt() { this.$apollo From 4f5ca22363a3852c13d9bb3ef74fee941ea17b83 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 14 Sep 2021 17:28:40 +0200 Subject: [PATCH 05/17] refactoring is working --- frontend/src/components/PaginationButtons.vue | 69 ++++++++++--------- .../AccountOverview/GddTransactionList.vue | 40 +++-------- .../AccountOverview/GdtTransactionList.vue | 19 ++--- 3 files changed, 50 insertions(+), 78 deletions(-) diff --git a/frontend/src/components/PaginationButtons.vue b/frontend/src/components/PaginationButtons.vue index bf2c19488..708a92f40 100644 --- a/frontend/src/components/PaginationButtons.vue +++ b/frontend/src/components/PaginationButtons.vue @@ -1,8 +1,8 @@ diff --git a/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue b/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue index 77aa78879..908b08fcc 100644 --- a/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue +++ b/frontend/src/views/Pages/AccountOverview/GddTransactionList.vue @@ -84,13 +84,9 @@
{{ $t('transaction.nullTransactions') }} @@ -128,23 +124,6 @@ export default { transactionCount: { type: Number, default: 0 }, showPagination: { type: Boolean, default: false }, }, - watch: { - timestamp: { - immediate: true, - handler: 'updateTransactions', - }, - }, - computed: { - hasNext() { - return this.currentPage * this.pageSize < this.transactionCount - }, - hasPrevious() { - return this.currentPage > 1 - }, - totalPages() { - return Math.ceil(this.transactionCount / this.pageSize) - }, - }, methods: { updateTransactions() { this.$emit('update-transactions', { @@ -165,15 +144,14 @@ export default { throwError(msg) { throw new Error(msg) }, - showNext() { - this.currentPage++ + }, + watch: { + currentPage() { this.updateTransactions() - window.scrollTo(0, 0) }, - showPrevious() { - this.currentPage-- - this.updateTransactions() - window.scrollTo(0, 0) + timestamp: { + immediate: true, + handler: 'updateTransactions', }, }, } diff --git a/frontend/src/views/Pages/AccountOverview/GdtTransactionList.vue b/frontend/src/views/Pages/AccountOverview/GdtTransactionList.vue index 8f1fd2839..7d1bcfd7e 100644 --- a/frontend/src/views/Pages/AccountOverview/GdtTransactionList.vue +++ b/frontend/src/views/Pages/AccountOverview/GdtTransactionList.vue @@ -28,12 +28,9 @@
@@ -73,25 +70,21 @@ export default { } = result this.transactionsGdt = listGDTEntries.gdtEntries this.transactionGdtCount = listGDTEntries.count + window.scrollTo(0, 0) }) .catch((error) => { this.$toasted.error(error.message) }) }, - showNext() { - this.currentPage++ - this.updateGdt() - window.scrollTo(0, 0) - }, - showPrevious() { - this.currentPage-- - this.updateGdt() - window.scrollTo(0, 0) - }, }, mounted() { this.updateGdt() }, + watch: { + currentPage() { + this.updateGdt() + }, + }, } diff --git a/frontend/src/components/Collapse/CollapseItem.vue b/frontend/src/components/Collapse/CollapseItem.vue deleted file mode 100644 index 7d6b8ded1..000000000 --- a/frontend/src/components/Collapse/CollapseItem.vue +++ /dev/null @@ -1,91 +0,0 @@ - - - diff --git a/frontend/src/components/index.js b/frontend/src/components/index.js index 155b060de..656f05d91 100755 --- a/frontend/src/components/index.js +++ b/frontend/src/components/index.js @@ -1,8 +1,5 @@ import NavbarToggleButton from './Navbar/NavbarToggleButton' -import Collapse from './Collapse/Collapse.vue' -import CollapseItem from './Collapse/CollapseItem.vue' - import SidebarPlugin from './SidebarPlugin' -export { SidebarPlugin, NavbarToggleButton, Collapse, CollapseItem } +export { SidebarPlugin, NavbarToggleButton } diff --git a/frontend/src/views/Pages/AccountOverview.spec.js b/frontend/src/views/Pages/AccountOverview.spec.js index df964ed2c..32db6a19a 100644 --- a/frontend/src/views/Pages/AccountOverview.spec.js +++ b/frontend/src/views/Pages/AccountOverview.spec.js @@ -6,6 +6,8 @@ sendMock.mockResolvedValue('success') const localVue = global.localVue +window.scrollTo = jest.fn() + describe('AccountOverview', () => { let wrapper diff --git a/frontend/src/views/Pages/AccountOverview/GddAddWork2.vue b/frontend/src/views/Pages/AccountOverview/GddAddWork2.vue deleted file mode 100644 index 70f56f0e6..000000000 --- a/frontend/src/views/Pages/AccountOverview/GddAddWork2.vue +++ /dev/null @@ -1,183 +0,0 @@ - - - diff --git a/frontend/src/views/Pages/AccountOverview/GddWorkTable.vue b/frontend/src/views/Pages/AccountOverview/GddWorkTable.vue deleted file mode 100644 index 247175a63..000000000 --- a/frontend/src/views/Pages/AccountOverview/GddWorkTable.vue +++ /dev/null @@ -1,83 +0,0 @@ - - - - diff --git a/frontend/src/views/Pages/UserProfileTransactionList.spec.js b/frontend/src/views/Pages/UserProfileTransactionList.spec.js index 8e4235fbe..057e1dfd5 100644 --- a/frontend/src/views/Pages/UserProfileTransactionList.spec.js +++ b/frontend/src/views/Pages/UserProfileTransactionList.spec.js @@ -3,6 +3,8 @@ import UserProfileTransactionList from './UserProfileTransactionList' const localVue = global.localVue +window.scrollTo = jest.fn() + describe('UserProfileTransactionList', () => { let wrapper From b94ec0b616ae1f5ef41a9d3b2052a8954ec23991 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 15 Sep 2021 15:34:57 +0200 Subject: [PATCH 16/17] frontend test coverage to 66% --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d65430a3f..dc26ce26c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -316,7 +316,7 @@ jobs: report_name: Coverage Frontend type: lcov result_path: ./coverage/lcov.info - min_coverage: 61 + min_coverage: 66 token: ${{ github.token }} ############################################################################## From e9c30a65c2ef37100ec3495e93301b99e1e03acc Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Thu, 16 Sep 2021 11:54:53 +0200 Subject: [PATCH 17/17] install bash & jq since they are not present on the alpine image. Install it only for test so we do not bloat our production image --- frontend/Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 5ec90fe81..879fdf4e0 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -72,6 +72,9 @@ RUN yarn run build ################################################################################## FROM build as test +# Install Additional Software +RUN apk add --no-cache bash jq + # Run command CMD /bin/sh -c "yarn run dev"