mirror of
https://github.com/IT4Change/gradido.git
synced 2026-01-20 20:01:31 +00:00
Merge branch 'master' into community_decay_inside
This commit is contained in:
commit
6756419855
18
.github/workflows/test.yml
vendored
18
.github/workflows/test.yml
vendored
@ -50,13 +50,7 @@ jobs:
|
||||
##########################################################################
|
||||
- name: login server | Build `release` image
|
||||
run: |
|
||||
docker build --target release -t "gradido/login_server:release" -f ./login_server/Dockerfile login_server/
|
||||
#docker save "gradido/login_server:test" > /tmp/login_server.tar
|
||||
#- name: Upload Artifact
|
||||
# uses: actions/upload-artifact@v2
|
||||
#with:
|
||||
# name: docker-login-server-test
|
||||
#path: /tmp/login_server.tar
|
||||
docker build -t "gradido/login_server:release" -f ./login_server/Dockerfile login_server/
|
||||
|
||||
##############################################################################
|
||||
# JOB: DOCKER BUILD TEST COMMUNITY SERVER ####################################
|
||||
@ -212,7 +206,7 @@ jobs:
|
||||
report_name: Coverage Frontend
|
||||
type: lcov
|
||||
result_path: ./coverage/lcov.info
|
||||
min_coverage: 28
|
||||
min_coverage: 32
|
||||
token: ${{ github.token }}
|
||||
|
||||
##############################################################################
|
||||
@ -251,7 +245,7 @@ jobs:
|
||||
##########################################################################
|
||||
- name: login server | Build `test` image
|
||||
run: |
|
||||
docker build --target test -t "gradido/login_server:test" -f ./login_server/Dockerfile login_server/
|
||||
docker build -t "gradido/login_server:test" -f ./login_server/Dockerfiles/ubuntu/Dockerfile.test login_server/
|
||||
##########################################################################
|
||||
# UNIT TESTS BACKEND LOGIN-SERVER #######################################
|
||||
##########################################################################
|
||||
@ -268,7 +262,7 @@ jobs:
|
||||
report_name: Coverage Backend Login
|
||||
type: lcov
|
||||
result_path: ./coverage/coverage.info
|
||||
min_coverage: 13
|
||||
min_coverage: 25
|
||||
token: ${{ github.token }}
|
||||
|
||||
##############################################################################
|
||||
@ -300,7 +294,7 @@ jobs:
|
||||
run: echo "::set-output name=id::$(docker network ls | grep github_network | awk '{ print $1 }')"
|
||||
id: network
|
||||
- name: Start Login-Server
|
||||
run: docker run --network ${{ steps.network.outputs.id }} --name=login-server -d gradido/login_server:default
|
||||
run: docker run --network ${{ steps.network.outputs.id }} --name=login-server -d gradido/login_server:with-config
|
||||
- name: get login-server container id
|
||||
run: echo "::set-output name=id::$(docker container ls | grep login_server | awk '{ print $1 }')"
|
||||
id: login_server_container
|
||||
@ -341,7 +335,7 @@ jobs:
|
||||
report_name: Coverage Backend Community
|
||||
type: phpunit
|
||||
result_path: ./coverage/coverage.info
|
||||
min_coverage: 10
|
||||
min_coverage: 14
|
||||
token: ${{ github.token }}
|
||||
|
||||
#test:
|
||||
|
||||
44
CHANGELOG.md
44
CHANGELOG.md
@ -4,8 +4,52 @@ All notable changes to this project will be documented in this file. Dates are d
|
||||
|
||||
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
||||
|
||||
#### [1.1.0](https://github.com/gradido/gradido/compare/1.0.2...1.1.0)
|
||||
|
||||
- fix: API Call for Reset Password [`#571`](https://github.com/gradido/gradido/pull/571)
|
||||
- Login reset password [`#570`](https://github.com/gradido/gradido/pull/570)
|
||||
- Hide unuse components in profil [`#566`](https://github.com/gradido/gradido/pull/566)
|
||||
- fix: Thousend Dividers on GDD Send Amount Field [`#567`](https://github.com/gradido/gradido/pull/567)
|
||||
- reorganisiere Dockerfiles [`#550`](https://github.com/gradido/gradido/pull/550)
|
||||
- hot fixes shown by test [`#551`](https://github.com/gradido/gradido/pull/551)
|
||||
- fix to big text ths [`#565`](https://github.com/gradido/gradido/pull/565)
|
||||
- feat: Trim Email on Blur [`#556`](https://github.com/gradido/gradido/pull/556)
|
||||
- Mobile UI send gdd form [`#562`](https://github.com/gradido/gradido/pull/562)
|
||||
- fix: Change Password Form [`#561`](https://github.com/gradido/gradido/pull/561)
|
||||
- change userdata button disable rules [`#548`](https://github.com/gradido/gradido/pull/548)
|
||||
- Change password require old password [`#519`](https://github.com/gradido/gradido/pull/519)
|
||||
- feat: Test Forget Password [`#546`](https://github.com/gradido/gradido/pull/546)
|
||||
- feat: Validate Change Username [`#545`](https://github.com/gradido/gradido/pull/545)
|
||||
- Remove base input example login vue [`#524`](https://github.com/gradido/gradido/pull/524)
|
||||
- Feature: Change Username [`#490`](https://github.com/gradido/gradido/pull/490)
|
||||
- feat: Toaster to Display Messages [`#512`](https://github.com/gradido/gradido/pull/512)
|
||||
- fix: Validation of GDD Send Amount Field [`#525`](https://github.com/gradido/gradido/pull/525)
|
||||
- Community coverage [`#496`](https://github.com/gradido/gradido/pull/496)
|
||||
- compare with last transaction sended [`#523`](https://github.com/gradido/gradido/pull/523)
|
||||
- remove check decays for being at least 100 GDD cent [`#526`](https://github.com/gradido/gradido/pull/526)
|
||||
- fix: Remove Target Date in Send Coins Request [`#518`](https://github.com/gradido/gradido/pull/518)
|
||||
- Feature profile page bugs [`#511`](https://github.com/gradido/gradido/pull/511)
|
||||
- fix: GDD Send Amount Input Field [`#491`](https://github.com/gradido/gradido/pull/491)
|
||||
- change transfer confirmation email [`#485`](https://github.com/gradido/gradido/pull/485)
|
||||
- Login wait on passwords with missing chars [`#487`](https://github.com/gradido/gradido/pull/487)
|
||||
- fix problem with create User [`#486`](https://github.com/gradido/gradido/pull/486)
|
||||
- Feature: Profile Page + Update API [`#474`](https://github.com/gradido/gradido/pull/474)
|
||||
- add new API Call checkUsername [`#482`](https://github.com/gradido/gradido/pull/482)
|
||||
- feat: Pagination Buttons for Transaction List [`#473`](https://github.com/gradido/gradido/pull/473)
|
||||
- Login-Server & Community-Server Coverage [`#472`](https://github.com/gradido/gradido/pull/472)
|
||||
- login without hedera [`#478`](https://github.com/gradido/gradido/pull/478)
|
||||
- fix: Show Correct Version Number in Footer [`#475`](https://github.com/gradido/gradido/pull/475)
|
||||
- refactor: Remove Element-UI [`#476`](https://github.com/gradido/gradido/pull/476)
|
||||
- remove components Charts, Notification, SearchUser, ButtonCheckbox, Button RadioGroup, Breadcrumb [`159bff7`](https://github.com/gradido/gradido/commit/159bff71df20a5c48f93389b2f990f7fe54e53b9)
|
||||
- fix bug, update dockerfiles to use dependencies without grpc [`dedcebd`](https://github.com/gradido/gradido/commit/dedcebdb95ee0f3dfd2ad62074d4181af38476a2)
|
||||
- add warning to able to forward warnings from community server to client [`2fc3fe9`](https://github.com/gradido/gradido/commit/2fc3fe94a09bae199bf2f34f9df90e8fc3879c2b)
|
||||
|
||||
#### [1.0.2](https://github.com/gradido/gradido/compare/1.0.1...1.0.2)
|
||||
|
||||
> 27 May 2021
|
||||
|
||||
- feat: Test Transaction List [`#470`](https://github.com/gradido/gradido/pull/470)
|
||||
- fixed problem with finding cpsp parse binary under windows with conan [`#471`](https://github.com/gradido/gradido/pull/471)
|
||||
- fix: GDD Amount is Always Displayed with Two Digits [`#468`](https://github.com/gradido/gradido/pull/468)
|
||||
- fix: Date Time Formats [`#469`](https://github.com/gradido/gradido/pull/469)
|
||||
- Community ipv6 localhost [`#466`](https://github.com/gradido/gradido/pull/466)
|
||||
|
||||
@ -289,7 +289,7 @@ class AppController extends Controller
|
||||
}
|
||||
} else {
|
||||
if(!$redirect) {
|
||||
return ['state' => 'not found', 'msg' => 'invalid session'];
|
||||
return ['state' => 'not found', 'msg' => 'invalid session', 'details' => $json];
|
||||
}
|
||||
if ($json['state'] === 'not found') {
|
||||
$this->Flash->error(__('invalid session'));
|
||||
|
||||
@ -192,7 +192,7 @@ class TransactionsTable extends Table
|
||||
$calculated_decay = $stateBalancesTable->calculateDecay($prev->balance, $prev->balance_date, $current->balance_date, true);
|
||||
$balance = floatval($prev->balance - $calculated_decay['balance']);
|
||||
|
||||
if($balance)
|
||||
if($balance > 100)
|
||||
{
|
||||
$final_transactions['decay'] = [
|
||||
'balance' => $balance,
|
||||
|
||||
@ -109,9 +109,11 @@ class AppRequestControllerTest extends TestCase
|
||||
'public_hex' => '8190bda585ee5f1d9fbf7d06e81e69ec18e13376104cff54b7457eb7d3ef710d'
|
||||
]
|
||||
]);
|
||||
|
||||
|
||||
$this->getAndParse('/api/get-balance/' . 1211,
|
||||
['state' => 'not found', 'msg' => 'invalid session']
|
||||
['state' => 'not found', 'msg' => 'invalid session',
|
||||
'details' => ['msg' => 'session not found', 'state' => 'not found']
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@ -128,7 +130,9 @@ class AppRequestControllerTest extends TestCase
|
||||
]);
|
||||
|
||||
$this->getAndParse('/api/get-balance/' ,
|
||||
['state' => 'not found', 'msg' => 'invalid session']
|
||||
['state' => 'not found', 'msg' => 'invalid session',
|
||||
'details' => ['msg' => 'session not found', 'state' => 'not found']
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -26,8 +26,7 @@ services:
|
||||
#########################################################
|
||||
login-server:
|
||||
build:
|
||||
target: login_server_alpine_debug
|
||||
dockerfile: Dockerfile.alpine-debug
|
||||
dockerfile: Dockerfiles/alpine/Dockerfile.debug
|
||||
security_opt:
|
||||
- seccomp:unconfined
|
||||
cap_add:
|
||||
|
||||
@ -26,7 +26,7 @@ services:
|
||||
login-server:
|
||||
build:
|
||||
context: ./login_server/
|
||||
target: test
|
||||
dockerfile: Dockerfiles/ubuntu/Dockerfile.test
|
||||
security_opt:
|
||||
- seccomp:unconfined
|
||||
cap_add:
|
||||
|
||||
@ -55,7 +55,6 @@ services:
|
||||
login-server:
|
||||
build:
|
||||
context: ./login_server/
|
||||
target: login_server
|
||||
depends_on:
|
||||
- mariadb
|
||||
networks:
|
||||
|
||||
@ -230,7 +230,8 @@ with:
|
||||
"User.description" : "Tischler",
|
||||
"User.disabled": 0,
|
||||
"User.language": "de",
|
||||
"User.password": "1234"
|
||||
"User.password": "1234",
|
||||
"User.password_old": "4321"
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -240,6 +241,7 @@ Notes:
|
||||
- User will be disabled if he wants his account deleted, but has transactions. Until transactions are saved in real blockchain, we need this data because the public key is in db only saved in state_users so if we delete this entry, validating all transactions is no longer possible.
|
||||
- Disabled Users can neither login nor receive transactions.
|
||||
- It is not required to provide all fields of `update`, it can be a subset depending on what you intend to change.
|
||||
- `User.password`: to change user password, needed current passwort in `User.password_old` (only if user was logged in with his password, not by reset password email code)
|
||||
|
||||
### Response
|
||||
In case of success:
|
||||
@ -252,7 +254,7 @@ In case of success:
|
||||
}
|
||||
```
|
||||
|
||||
- `valid_values`: should contain count of entries in update if no error occurred (User.password will not be counted)
|
||||
- `valid_values`: should contain count of entries in update if no error occurred (User.password will now be counted also)
|
||||
- `errors`: contain on error string for every entry in update, which type isn't like expected
|
||||
- `password`:
|
||||
- "new password is the same as old password": no change taking place
|
||||
@ -503,6 +505,29 @@ The link can be modified in the Login-Server config:
|
||||
|
||||
For the docker build, you can find the config here: `configs/login_server/grd_login.properties`
|
||||
|
||||
### Request
|
||||
`POST http://localhost/login_api/resetPassword`
|
||||
|
||||
with:
|
||||
|
||||
```json
|
||||
{
|
||||
"session_id": 12452361,
|
||||
"password":"hasu/282?sjS"
|
||||
}
|
||||
```
|
||||
|
||||
### Response
|
||||
In case of success returns:
|
||||
|
||||
```json
|
||||
{
|
||||
"state":"success"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Check Running Transactions / password encryption
|
||||
Check if transactions on login-server for user are processed
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bootstrap-vue-gradido-wallet",
|
||||
"version": "1.0.2",
|
||||
"version": "1.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "node run/server.js",
|
||||
|
||||
@ -15,7 +15,7 @@ const apiGet = async (url) => {
|
||||
if (result.status !== 200) {
|
||||
throw new Error('HTTP Status Error ' + result.status)
|
||||
}
|
||||
if (result.data.state !== 'success') {
|
||||
if (!['success', 'warning'].includes(result.data.state)) {
|
||||
throw new Error(result.data.msg)
|
||||
}
|
||||
return { success: true, result }
|
||||
@ -102,19 +102,17 @@ const loginAPI = {
|
||||
const payload = {
|
||||
session_id: sessionId,
|
||||
email,
|
||||
update: {
|
||||
'User.password': password,
|
||||
},
|
||||
password,
|
||||
}
|
||||
return apiPost(CONFIG.LOGIN_API_URL + 'updateUserInfos', payload)
|
||||
return apiPost(CONFIG.LOGIN_API_URL + 'resetPassword', payload)
|
||||
},
|
||||
changePasswordProfile: async (sessionId, email, password, passwordNew) => {
|
||||
const payload = {
|
||||
session_id: sessionId,
|
||||
email,
|
||||
update: {
|
||||
'User.password': password,
|
||||
'User.passwordNew': passwordNew,
|
||||
'User.password_old': password,
|
||||
'User.password': passwordNew,
|
||||
},
|
||||
}
|
||||
return apiPost(CONFIG.LOGIN_API_URL + 'updateUserInfos', payload)
|
||||
@ -139,6 +137,9 @@ const loginAPI = {
|
||||
}
|
||||
return apiPost(CONFIG.LOGIN_API_URL + 'updateUserInfos', payload)
|
||||
},
|
||||
checkUsername: async (username, groupId = 1) => {
|
||||
return apiGet(CONFIG.LOGIN_API_URL + `checkUsername?username=${username}&group_id=${groupId}`)
|
||||
},
|
||||
}
|
||||
|
||||
export default loginAPI
|
||||
|
||||
@ -85,7 +85,7 @@ export default {
|
||||
default: 'img/brand/green.png',
|
||||
description: 'Gradido Sidebar app logo',
|
||||
},
|
||||
value: { type: Array },
|
||||
value: { type: String },
|
||||
autoClose: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
|
||||
@ -38,6 +38,12 @@ const numberFormats = {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
},
|
||||
ungroupedDecimal: {
|
||||
style: 'decimal',
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
useGrouping: false,
|
||||
},
|
||||
},
|
||||
de: {
|
||||
decimal: {
|
||||
@ -45,6 +51,12 @@ const numberFormats = {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
},
|
||||
ungroupedDecimal: {
|
||||
style: 'decimal',
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
useGrouping: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -39,6 +39,7 @@
|
||||
"password_new":"neues Passwort",
|
||||
"password_new_repeat":"neues Passwort wiederholen",
|
||||
"change": "ändern",
|
||||
"change-password": "Passwort ändern",
|
||||
"amount":"Betrag",
|
||||
"memo":"Nachricht für den Empfänger",
|
||||
"message":"Nachricht",
|
||||
@ -57,12 +58,15 @@
|
||||
"send_transaction_error":"Leider konnte die Transaktion nicht ausgeführt werden!",
|
||||
"validation": {
|
||||
"gddSendAmount": "Das Feld {_field_} muss eine Zahl zwischen {min} und {max} mit höchstens zwei Nachkommastellen sein",
|
||||
"is-not": "Du kannst dir selbst keine Gradidos überweisen"
|
||||
"is-not": "Du kannst dir selbst keine Gradidos überweisen",
|
||||
"usernmae-unique": "Der Username ist bereits vergeben.",
|
||||
"usernmae-regex": "Der Username muss mit einem Buchstaben beginnen auf den mindestens zwei alfanumerische Zeichen folgen müssen."
|
||||
},
|
||||
"change_username_info": "Das ändern des Usernamens bedarf mehrerer Schritte."
|
||||
"change_username_info": "Einmal gespeichert, kann der Username ncht mehr geändert werden!"
|
||||
},
|
||||
"error": {
|
||||
"error":"Fehler"
|
||||
"error":"Fehler",
|
||||
"change-password": "Fehler beim Ändern des Passworts"
|
||||
},
|
||||
"transaction":{
|
||||
"show_all":"Alle <strong>{count}</strong> Transaktionen ansehen",
|
||||
|
||||
@ -39,6 +39,7 @@
|
||||
"password_new":"New password",
|
||||
"password_new_repeat":"Repeat new password",
|
||||
"change": "change",
|
||||
"change-password": "Change password",
|
||||
"amount":"Amount",
|
||||
"memo":"Message for the recipient",
|
||||
"message":"Message",
|
||||
@ -57,12 +58,15 @@
|
||||
"send_transaction_error":"Unfortunately, the transaction could not be executed!",
|
||||
"validation": {
|
||||
"gddSendAmount": "The {_field_} field must be a number between {min} and {max} with at most two digits",
|
||||
"is-not": "You cannot send Gradidos to yourself"
|
||||
"is-not": "You cannot send Gradidos to yourself",
|
||||
"usernmae-unique": "The username is already taken.",
|
||||
"usernmae-regex": "The username must start with a letter, followed by at least two alphanumeric characters."
|
||||
},
|
||||
"change_username_info": "Changing the username requires several steps."
|
||||
"change_username_info": "Once saved, the username cannot be changed again!"
|
||||
},
|
||||
"error": {
|
||||
"error":"Error"
|
||||
"error":"Error",
|
||||
"change-password": "Error while changing password"
|
||||
},
|
||||
"transaction":{
|
||||
"show_all":"View all <strong>{count}</strong> transactions.",
|
||||
|
||||
@ -9,6 +9,8 @@ import { required, email, min, max, is_not } from 'vee-validate/dist/rules'
|
||||
// store
|
||||
import { store } from './store/store'
|
||||
|
||||
import loginAPI from './apis/loginAPI'
|
||||
|
||||
// router setup
|
||||
import router from './routes/router'
|
||||
|
||||
@ -58,12 +60,27 @@ extend('gddSendAmount', {
|
||||
},
|
||||
params: ['min', 'max'],
|
||||
message: (_, values) => {
|
||||
values.min = i18n.n(values.min)
|
||||
values.max = i18n.n(values.max)
|
||||
values.min = i18n.n(values.min, 'ungroupedDecimal')
|
||||
values.max = i18n.n(values.max, 'ungroupedDecimal')
|
||||
return i18n.t('form.validation.gddSendAmount', values)
|
||||
},
|
||||
})
|
||||
|
||||
extend('gddUsernameUnique', {
|
||||
async validate(value) {
|
||||
const result = await loginAPI.checkUsername(value)
|
||||
return result.result.data.state === 'success'
|
||||
},
|
||||
message: (_, values) => i18n.t('form.validation.usernmae-unique', values),
|
||||
})
|
||||
|
||||
extend('gddUsernameRgex', {
|
||||
validate(value) {
|
||||
return !!value.match(/^[a-zA-Z][-_a-zA-Z0-9]{2,}$/)
|
||||
},
|
||||
message: (_, values) => i18n.t('form.validation.usernmae-regex', values),
|
||||
})
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
extend('is_not', {
|
||||
// eslint-disable-next-line camelcase
|
||||
|
||||
@ -1,16 +1,12 @@
|
||||
import { mount, RouterLinkStub } from '@vue/test-utils'
|
||||
import VueRouter from 'vue-router'
|
||||
import Vuex from 'vuex'
|
||||
import flushPromises from 'flush-promises'
|
||||
import routes from '../../routes/routes'
|
||||
import DashboardLayoutGdd from './DashboardLayout_gdd'
|
||||
|
||||
jest.useFakeTimers()
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
const router = new VueRouter({ routes })
|
||||
|
||||
const transitionStub = () => ({
|
||||
render(h) {
|
||||
return this.$options._renderChildren
|
||||
@ -26,6 +22,14 @@ describe('DashboardLayoutGdd', () => {
|
||||
},
|
||||
$t: jest.fn((t) => t),
|
||||
$n: jest.fn(),
|
||||
$route: {
|
||||
meta: {
|
||||
hideFooter: false,
|
||||
},
|
||||
},
|
||||
$router: {
|
||||
push: jest.fn(),
|
||||
},
|
||||
}
|
||||
|
||||
const state = {
|
||||
@ -40,6 +44,7 @@ describe('DashboardLayoutGdd', () => {
|
||||
const stubs = {
|
||||
RouterLink: RouterLinkStub,
|
||||
FadeTransition: transitionStub(),
|
||||
RouterView: transitionStub(),
|
||||
}
|
||||
|
||||
const store = new Vuex.Store({
|
||||
@ -50,7 +55,7 @@ describe('DashboardLayoutGdd', () => {
|
||||
})
|
||||
|
||||
const Wrapper = () => {
|
||||
return mount(DashboardLayoutGdd, { localVue, mocks, router, store, stubs })
|
||||
return mount(DashboardLayoutGdd, { localVue, mocks, store, stubs })
|
||||
}
|
||||
|
||||
describe('mount', () => {
|
||||
|
||||
@ -144,9 +144,6 @@ export default {
|
||||
mounted() {
|
||||
this.initScrollbar()
|
||||
},
|
||||
created() {
|
||||
this.updateTransactions({ firstPage: 1, items: 5 })
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
|
||||
@ -45,7 +45,7 @@ describe('GddSend', () => {
|
||||
})
|
||||
|
||||
it('has a label form.receiver', () => {
|
||||
expect(wrapper.findAll('div.text-left').at(0).text()).toBe('form.receiver')
|
||||
expect(wrapper.find('label.input-1').text()).toBe('form.receiver')
|
||||
})
|
||||
|
||||
it('has a placeholder "E-Mail"', () => {
|
||||
@ -61,11 +61,11 @@ describe('GddSend', () => {
|
||||
})
|
||||
|
||||
it('has an GDD text icon', () => {
|
||||
expect(wrapper.find('#input-group-2').find('div.h3').text()).toBe('GDD')
|
||||
expect(wrapper.find('#input-group-2').find('div.m-1').text()).toBe('GDD')
|
||||
})
|
||||
|
||||
it('has a label form.amount', () => {
|
||||
expect(wrapper.findAll('div.text-left').at(1).text()).toBe('form.amount')
|
||||
expect(wrapper.find('label.input-2').text()).toBe('form.amount')
|
||||
})
|
||||
|
||||
it('has a placeholder "0.01"', () => {
|
||||
@ -87,7 +87,7 @@ describe('GddSend', () => {
|
||||
})
|
||||
|
||||
it('has a label form.memo', () => {
|
||||
expect(wrapper.findAll('div.text-left').at(2).text()).toBe('form.memo')
|
||||
expect(wrapper.find('label.input-3').text()).toBe('form.memo')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<b-row class="transaction-form">
|
||||
<b-col xl="12" md="12">
|
||||
<b-card class="p-0 p-md-3" style="background-color: #ebebeba3 !important">
|
||||
<b-col xl="12" md="12" class="p-0">
|
||||
<b-card class="p-0 m-0" style="background-color: #ebebeba3 !important">
|
||||
<!-- -<QrCode @set-transaction="setTransaction"></QrCode> -->
|
||||
<validation-observer v-slot="{ handleSubmit }" ref="formValidator">
|
||||
<b-form role="form" @submit.prevent="handleSubmit(onSubmit)" @reset="onReset">
|
||||
@ -10,6 +10,7 @@
|
||||
</div>
|
||||
<br />
|
||||
-->
|
||||
|
||||
<div>
|
||||
<validation-provider
|
||||
name="Email"
|
||||
@ -21,33 +22,37 @@
|
||||
v-slot="{ errors }"
|
||||
>
|
||||
<b-row>
|
||||
<b-col class="text-left p-3 p-sm-1">{{ $t('form.receiver') }}</b-col>
|
||||
<b-col v-if="errors" class="text-right p-3 p-sm-1">
|
||||
<span v-for="error in errors" :key="error" class="errors">{{ error }}</span>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<label class="input-1" for="input-1">{{ $t('form.receiver') }}</label>
|
||||
<b-input-group
|
||||
id="input-group-1"
|
||||
label="Empfänger:"
|
||||
label-for="input-1"
|
||||
class="border border-default"
|
||||
description="We'll never share your email with anyone else."
|
||||
size="lg"
|
||||
class="mb-3"
|
||||
>
|
||||
<b-input-group-prepend class="p-3 d-none d-md-block">
|
||||
<b-icon icon="envelope" class="display-3"></b-icon>
|
||||
<b-input-group-prepend class="d-none d-md-block">
|
||||
<b-icon icon="envelope" class="display-4 m-3"></b-icon>
|
||||
</b-input-group-prepend>
|
||||
<b-form-input
|
||||
id="input-1"
|
||||
v-model="form.email"
|
||||
v-focus="emailFocused"
|
||||
@focus="emailFocused = true"
|
||||
@blur="normalizeEmail()"
|
||||
type="email"
|
||||
placeholder="E-Mail"
|
||||
style="font-size: xx-large; padding-left: 20px"
|
||||
style="font-size: large"
|
||||
class="pl-3"
|
||||
></b-form-input>
|
||||
</b-input-group>
|
||||
</validation-provider>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<div>
|
||||
<validation-provider
|
||||
:name="$t('form.amount')"
|
||||
@ -58,33 +63,32 @@
|
||||
v-slot="{ errors, valid }"
|
||||
>
|
||||
<b-row>
|
||||
<b-col class="text-left p-3 p-sm-1">{{ $t('form.amount') }}</b-col>
|
||||
<b-col v-if="errors" class="text-right p-3 p-sm-1">
|
||||
<b-col v-if="errors" class="col-12 text-right p-3 p-sm-1">
|
||||
<span v-for="error in errors" class="errors" :key="error">{{ error }}</span>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<b-input-group
|
||||
id="input-group-2"
|
||||
label="Betrag:"
|
||||
label-for="input-2"
|
||||
size="lg"
|
||||
class="mb-3"
|
||||
>
|
||||
<label class="input-2" for="input-2">{{ $t('form.amount') }}</label>
|
||||
<b-input-group id="input-group-2" class="border border-default" size="lg">
|
||||
<b-input-group-prepend class="p-2 d-none d-md-block">
|
||||
<div class="h3 pt-3 pr-3">GDD</div>
|
||||
<div class="m-1 mt-2">GDD</div>
|
||||
</b-input-group-prepend>
|
||||
|
||||
<b-form-input
|
||||
id="input-2"
|
||||
v-model="form.amount"
|
||||
type="text"
|
||||
v-focus="amountFocused"
|
||||
@focus="amountFocused = !amountFocused"
|
||||
@focus="amountFocused = true"
|
||||
@blur="normalizeAmount(valid)"
|
||||
:placeholder="$n(0.01)"
|
||||
style="font-size: xx-large; padding-left: 20px"
|
||||
style="font-size: large"
|
||||
class="pl-3"
|
||||
></b-form-input>
|
||||
</b-input-group>
|
||||
</validation-provider>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<validation-provider
|
||||
:rules="{
|
||||
required: true,
|
||||
@ -95,20 +99,20 @@
|
||||
v-slot="{ errors }"
|
||||
>
|
||||
<b-row>
|
||||
<b-col class="text-left p-3 p-sm-1">{{ $t('form.memo') }}</b-col>
|
||||
<b-col v-if="errors" class="text-right p-3 p-sm-1">
|
||||
<span v-for="error in errors" class="errors" :key="error">{{ error }}</span>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<b-input-group id="input-group-3">
|
||||
<b-input-group-prepend class="p-3 d-none d-md-block">
|
||||
<b-icon icon="chat-right-text" class="display-3"></b-icon>
|
||||
<label class="input-3" for="input-3">{{ $t('form.memo') }}</label>
|
||||
<b-input-group id="input-group-3" class="border border-default">
|
||||
<b-input-group-prepend class="d-none d-md-block">
|
||||
<b-icon icon="chat-right-text" class="display-4 m-3 mt-4"></b-icon>
|
||||
</b-input-group-prepend>
|
||||
<b-form-textarea
|
||||
id="input-3"
|
||||
rows="3"
|
||||
v-model="form.memo"
|
||||
class="pl-3"
|
||||
style="font-size: x-large"
|
||||
></b-form-textarea>
|
||||
</b-input-group>
|
||||
</validation-provider>
|
||||
@ -153,6 +157,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
amountFocused: false,
|
||||
emailFocused: false,
|
||||
form: {
|
||||
email: '',
|
||||
amount: '',
|
||||
@ -181,10 +186,14 @@ export default {
|
||||
this.form.amount = data.amount
|
||||
},
|
||||
normalizeAmount(isValid) {
|
||||
this.amountFocused = !this.amountFocused
|
||||
this.amountFocused = false
|
||||
if (!isValid) return
|
||||
this.form.amountValue = Number(this.form.amount.replace(',', '.'))
|
||||
this.form.amount = this.$n(this.form.amountValue, 'decimal')
|
||||
this.form.amount = this.$n(this.form.amountValue, 'ungroupedDecimal')
|
||||
},
|
||||
normalizeEmail() {
|
||||
this.emailFocused = false
|
||||
this.form.email = this.form.email.trim()
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<b-row v-if="!error">
|
||||
<b-col>
|
||||
<b-card class="p-0 p-md-3" style="background-color: #ebebeba3 !important">
|
||||
<div class="display-2 p-4">
|
||||
<b-card class="p-0" style="background-color: #ebebeba3 !important">
|
||||
<div class="p-4">
|
||||
{{ $t('form.thx') }}
|
||||
<hr />
|
||||
{{ $t('form.send_transaction_success') }}
|
||||
</div>
|
||||
<p class="text-center">
|
||||
<p class="text-center mt-3">
|
||||
<b-button variant="success" @click="$emit('on-reset')">{{ $t('form.close') }}</b-button>
|
||||
</p>
|
||||
</b-card>
|
||||
@ -15,13 +15,13 @@
|
||||
</b-row>
|
||||
<b-row v-else>
|
||||
<b-col>
|
||||
<b-card class="p-0 p-md-3" style="background-color: #ebebeba3 !important">
|
||||
<div class="display-2 p-4">
|
||||
<b-card class="p-0" style="background-color: #ebebeba3 !important">
|
||||
<div class="p-4" style="font-size: 1.5rem">
|
||||
{{ $t('form.sorry') }}
|
||||
<hr />
|
||||
{{ $t('form.send_transaction_error') }}
|
||||
</div>
|
||||
<p class="text-center">
|
||||
<p class="text-center mt-3">
|
||||
<b-button variant="success" @click="$emit('on-reset')">{{ $t('form.close') }}</b-button>
|
||||
</p>
|
||||
</b-card>
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-row>
|
||||
<b-col>
|
||||
<b-card style="background-color: #ebebeba3 !important">
|
||||
<b-col class="p-0">
|
||||
<b-card class="p-0" style="background-color: #ebebeba3 !important">
|
||||
{{ pending ? '—' : $n(balance, 'decimal') }} GDD
|
||||
</b-card>
|
||||
</b-col>
|
||||
<b-col>
|
||||
<b-card class="lg-h2 text-right" style="background-color: #ebebeba3 !important">
|
||||
<b-col class="pr-0">
|
||||
<b-card class="p-0 text-right" style="background-color: #ebebeba3 !important">
|
||||
{{ pending ? '—' : $n(GdtBalance, 'decimal') }} GDT
|
||||
</b-card>
|
||||
</b-col>
|
||||
|
||||
114
frontend/src/views/Pages/ForgotPassword.spec.js
Normal file
114
frontend/src/views/Pages/ForgotPassword.spec.js
Normal file
@ -0,0 +1,114 @@
|
||||
import { mount, RouterLinkStub } from '@vue/test-utils'
|
||||
import flushPromises from 'flush-promises'
|
||||
import loginAPI from '../../apis/loginAPI.js'
|
||||
import ForgotPassword from './ForgotPassword'
|
||||
|
||||
jest.mock('../../apis/loginAPI.js')
|
||||
|
||||
const mockAPIcall = jest.fn()
|
||||
loginAPI.sendEmail = mockAPIcall
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
const mockRouterPush = jest.fn()
|
||||
|
||||
describe('ForgotPassword', () => {
|
||||
let wrapper
|
||||
|
||||
const mocks = {
|
||||
$t: jest.fn((t) => t),
|
||||
$router: {
|
||||
push: mockRouterPush,
|
||||
},
|
||||
}
|
||||
|
||||
const stubs = {
|
||||
RouterLink: RouterLinkStub,
|
||||
}
|
||||
|
||||
const Wrapper = () => {
|
||||
return mount(ForgotPassword, { localVue, mocks, stubs })
|
||||
}
|
||||
|
||||
describe('mount', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
it('renders the component', () => {
|
||||
expect(wrapper.find('div.forgot-password').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
it('has a title', () => {
|
||||
expect(wrapper.find('h1').text()).toEqual('site.password.title')
|
||||
})
|
||||
|
||||
it('has a subtitle', () => {
|
||||
expect(wrapper.find('p.text-lead').text()).toEqual('site.password.subtitle')
|
||||
})
|
||||
|
||||
describe('back button', () => {
|
||||
it('has a "back" button', () => {
|
||||
expect(wrapper.findComponent(RouterLinkStub).text()).toEqual('back')
|
||||
})
|
||||
|
||||
it('links to login', () => {
|
||||
expect(wrapper.findComponent(RouterLinkStub).props().to).toEqual('/Login')
|
||||
})
|
||||
})
|
||||
|
||||
describe('input form', () => {
|
||||
let form
|
||||
|
||||
beforeEach(() => {
|
||||
form = wrapper.find('form')
|
||||
})
|
||||
|
||||
it('has the label "Email"', () => {
|
||||
expect(form.find('label').text()).toEqual('Email')
|
||||
})
|
||||
|
||||
it('has the placeholder "Email"', () => {
|
||||
expect(form.find('input').attributes('placeholder')).toEqual('Email')
|
||||
})
|
||||
|
||||
it('has a submit button', () => {
|
||||
expect(form.find('button[type="submit"]').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
describe('invalid Email', () => {
|
||||
beforeEach(async () => {
|
||||
await form.find('input').setValue('no-email')
|
||||
await flushPromises()
|
||||
})
|
||||
|
||||
it('displays an error', () => {
|
||||
expect(form.find('#reset-pwd--live-feedback').text()).toEqual(
|
||||
'The Email field must be a valid email',
|
||||
)
|
||||
})
|
||||
|
||||
it('does not call the API', () => {
|
||||
expect(mockAPIcall).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('valid Email', () => {
|
||||
beforeEach(async () => {
|
||||
await form.find('input').setValue('user@example.org')
|
||||
form.trigger('submit')
|
||||
await wrapper.vm.$nextTick()
|
||||
await flushPromises()
|
||||
})
|
||||
|
||||
it('calls the API', () => {
|
||||
expect(mockAPIcall).toHaveBeenCalledWith('user@example.org')
|
||||
})
|
||||
|
||||
it('pushes "/thx/password" to the route', () => {
|
||||
expect(mockRouterPush).toHaveBeenCalledWith('/thx/password')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="forgot-password">
|
||||
<div class="header p-4">
|
||||
<b-container class="container">
|
||||
<div class="header-body text-center mb-7">
|
||||
@ -70,7 +70,6 @@ export default {
|
||||
},
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
methods: {
|
||||
getValidationState({ dirty, validated, valid = null }) {
|
||||
return dirty || validated ? valid : null
|
||||
|
||||
@ -1,30 +1,74 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import VueRouter from 'vue-router'
|
||||
import routes from '../../routes/routes'
|
||||
|
||||
import { mount, RouterLinkStub } from '@vue/test-utils'
|
||||
import loginAPI from '../../apis/loginAPI'
|
||||
import ResetPassword from './ResetPassword'
|
||||
import flushPromises from 'flush-promises'
|
||||
|
||||
jest.mock('../../apis/loginAPI')
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
const router = new VueRouter({ routes })
|
||||
const successResponseObject = {
|
||||
success: true,
|
||||
result: {
|
||||
data: {
|
||||
session_id: 1,
|
||||
user: {
|
||||
email: 'user@example.org',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const emailVerificationMock = jest.fn()
|
||||
const changePasswordMock = jest.fn()
|
||||
const toasterMock = jest.fn()
|
||||
const routerPushMock = jest.fn()
|
||||
|
||||
emailVerificationMock
|
||||
.mockReturnValueOnce({ success: false, result: { message: 'error' } })
|
||||
.mockReturnValueOnce({ success: false, result: { message: 'error' } })
|
||||
.mockReturnValueOnce({ success: false, result: { message: 'error' } })
|
||||
.mockReturnValue(successResponseObject)
|
||||
|
||||
changePasswordMock
|
||||
.mockReturnValueOnce({ success: false, result: { message: 'error' } })
|
||||
.mockReturnValue({ success: true })
|
||||
|
||||
loginAPI.loginViaEmailVerificationCode = emailVerificationMock
|
||||
loginAPI.changePassword = changePasswordMock
|
||||
|
||||
describe('ResetPassword', () => {
|
||||
let wrapper
|
||||
|
||||
const emailVerification = jest.fn()
|
||||
|
||||
const mocks = {
|
||||
$i18n: {
|
||||
locale: 'en',
|
||||
},
|
||||
$t: jest.fn((t) => t),
|
||||
loginAPI: {
|
||||
loginViaEmailVerificationCode: emailVerification,
|
||||
$route: {
|
||||
params: {
|
||||
optin: '123',
|
||||
},
|
||||
},
|
||||
$toast: {
|
||||
error: toasterMock,
|
||||
},
|
||||
$router: {
|
||||
push: routerPushMock,
|
||||
},
|
||||
$loading: {
|
||||
show: jest.fn(() => {
|
||||
return { hide: jest.fn() }
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
const stubs = {
|
||||
RouterLink: RouterLinkStub,
|
||||
}
|
||||
|
||||
const Wrapper = () => {
|
||||
return mount(ResetPassword, { localVue, mocks, router })
|
||||
return mount(ResetPassword, { localVue, mocks, stubs })
|
||||
}
|
||||
|
||||
describe('mount', () => {
|
||||
@ -32,84 +76,94 @@ describe('ResetPassword', () => {
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
/*
|
||||
it('calls the email verification when created', () => {
|
||||
const spy = jest.spyOn(wrapper.vm, 'authenticate')
|
||||
expect(spy).toBeCalled()
|
||||
expect(emailVerificationMock).toHaveBeenCalledWith('123')
|
||||
})
|
||||
*/
|
||||
|
||||
it('does not render the Reset Password form when not authenticated', async () => {
|
||||
it('does not render the Reset Password form when not authenticated', () => {
|
||||
expect(wrapper.find('div.resetpwd-form').exists()).toBeFalsy()
|
||||
})
|
||||
|
||||
it('renders the Reset Password form', async () => {
|
||||
it('toasts an error when no valid optin is given', () => {
|
||||
expect(toasterMock).toHaveBeenCalledWith('error')
|
||||
})
|
||||
|
||||
it('renders the Reset Password form when authenticated', async () => {
|
||||
wrapper.setData({ authenticated: true })
|
||||
await wrapper.vm.$nextTick()
|
||||
expect(wrapper.find('div.resetpwd-form').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
// describe('Register header', () => {
|
||||
// it('has a welcome message', () => {
|
||||
// expect(wrapper.find('div.header').text()).toBe('site.signup.title site.signup.subtitle')
|
||||
// })
|
||||
// })
|
||||
describe('Register header', () => {
|
||||
it('has a welcome message', () => {
|
||||
expect(wrapper.find('div.header').text()).toBe('reset-password.title reset-password.text')
|
||||
})
|
||||
})
|
||||
|
||||
// describe('links', () => {
|
||||
// it('has a link "Back"', () => {
|
||||
// expect(wrapper.findAllComponents(RouterLinkStub).at(0).text()).toEqual('back')
|
||||
// })
|
||||
/* there is no back button, why?
|
||||
describe('links', () => {
|
||||
it('has a link "Back"', () => {
|
||||
expect(wrapper.findAllComponents(RouterLinkStub).at(0).text()).toEqual('back')
|
||||
})
|
||||
|
||||
// it('links to /login when clicking "Back"', () => {
|
||||
// expect(wrapper.findAllComponents(RouterLinkStub).at(0).props().to).toBe('/login')
|
||||
// })
|
||||
// })
|
||||
it('links to /login when clicking "Back"', () => {
|
||||
expect(wrapper.findAllComponents(RouterLinkStub).at(0).props().to).toBe('/login')
|
||||
})
|
||||
})
|
||||
*/
|
||||
|
||||
// describe('Register form', () => {
|
||||
// it('has a register form', () => {
|
||||
// expect(wrapper.find('form').exists()).toBeTruthy()
|
||||
// })
|
||||
describe('reset password form', () => {
|
||||
it('has a register form', () => {
|
||||
expect(wrapper.find('form').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
// it('has 3 text input fields', () => {
|
||||
// expect(wrapper.findAll('input[type="text"]').length).toBe(3)
|
||||
// })
|
||||
it('has 2 password input fields', () => {
|
||||
expect(wrapper.findAll('input[type="password"]').length).toBe(2)
|
||||
})
|
||||
|
||||
// it('has 2 password input fields', () => {
|
||||
// expect(wrapper.findAll('input[type="password"]').length).toBe(2)
|
||||
// })
|
||||
it('has no submit button when not completely filled', () => {
|
||||
expect(wrapper.find('button[type="submit"]').exists()).toBe(false)
|
||||
})
|
||||
|
||||
// it('has 1 checkbox input fields', () => {
|
||||
// expect(wrapper.findAll('input[type="checkbox"]').length).toBe(1)
|
||||
// })
|
||||
it('toggles the first input field to text when eye icon is clicked', async () => {
|
||||
wrapper.findAll('button').at(0).trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
expect(wrapper.findAll('input').at(0).attributes('type')).toBe('text')
|
||||
})
|
||||
|
||||
// it('has no submit button when not completely filled', () => {
|
||||
// expect(wrapper.find('button[type="submit"]').exists()).toBe(false)
|
||||
// })
|
||||
it('toggles the second input field to text when eye icon is clicked', async () => {
|
||||
wrapper.findAll('button').at(1).trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
expect(wrapper.findAll('input').at(1).attributes('type')).toBe('text')
|
||||
})
|
||||
})
|
||||
|
||||
// it('shows a warning when no valid Email is entered', async () => {
|
||||
// wrapper.findAll('input[type="text"]').at(2).setValue('no_valid@Email')
|
||||
// await flushPromises()
|
||||
// await expect(wrapper.find('.invalid-feedback').text()).toEqual(
|
||||
// 'The Email field must be a valid email',
|
||||
// )
|
||||
// })
|
||||
describe('submit form', () => {
|
||||
beforeEach(async () => {
|
||||
wrapper.findAll('input').at(0).setValue('Aa123456')
|
||||
wrapper.findAll('input').at(1).setValue('Aa123456')
|
||||
await wrapper.vm.$nextTick()
|
||||
await flushPromises()
|
||||
wrapper.find('form').trigger('submit')
|
||||
})
|
||||
|
||||
// it('shows 4 warnings when no password is set', async () => {
|
||||
// const passwords = wrapper.findAll('input[type="password"]')
|
||||
// passwords.at(0).setValue('')
|
||||
// passwords.at(1).setValue('')
|
||||
// await flushPromises()
|
||||
// await expect(wrapper.find('div.hints').text()).toContain(
|
||||
// 'site.signup.lowercase',
|
||||
// 'site.signup.uppercase',
|
||||
// 'site.signup.minimum',
|
||||
// 'site.signup.one_number',
|
||||
// )
|
||||
// })
|
||||
describe('server response with error', () => {
|
||||
it('toasts an error message', async () => {
|
||||
expect(toasterMock).toHaveBeenCalledWith('error')
|
||||
})
|
||||
})
|
||||
|
||||
// //TODO test different invalid password combinations
|
||||
// })
|
||||
describe('server response with success', () => {
|
||||
it('calls the API', async () => {
|
||||
await wrapper.vm.$nextTick()
|
||||
await flushPromises()
|
||||
expect(changePasswordMock).toHaveBeenCalledWith(1, 'user@example.org', 'Aa123456')
|
||||
})
|
||||
|
||||
// TODO test submit button
|
||||
it('redirects to "/thx/reset"', () => {
|
||||
expect(routerPushMock).toHaveBeenCalledWith('/thx/reset')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -121,6 +121,7 @@ export default {
|
||||
},
|
||||
password: '',
|
||||
passwordVisible: false,
|
||||
passwordVisibleRepeat: false,
|
||||
submitted: false,
|
||||
authenticated: false,
|
||||
sessionId: null,
|
||||
@ -134,6 +135,9 @@ export default {
|
||||
togglePasswordVisibility() {
|
||||
this.passwordVisible = !this.passwordVisible
|
||||
},
|
||||
togglePasswordRepeatVisibility() {
|
||||
this.passwordVisibleRepeat = !this.passwordVisibleRepeat
|
||||
},
|
||||
async onSubmit() {
|
||||
const result = await loginAPI.changePassword(this.sessionId, this.email, this.form.password)
|
||||
if (result.success) {
|
||||
@ -150,6 +154,9 @@ export default {
|
||||
}
|
||||
},
|
||||
async authenticate() {
|
||||
const loader = this.$loading.show({
|
||||
container: this.$refs.submitButton,
|
||||
})
|
||||
const optin = this.$route.params.optin
|
||||
const result = await loginAPI.loginViaEmailVerificationCode(optin)
|
||||
if (result.success) {
|
||||
@ -159,6 +166,7 @@ export default {
|
||||
} else {
|
||||
this.$toast.error(result.result.message)
|
||||
}
|
||||
loader.hide()
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
<div class="card-profile-stats d-flex justify-content-center mt-md-5">
|
||||
<div>
|
||||
<span class="heading">
|
||||
{{ $n(balance) }}
|
||||
{{ $n(balance, 'decimal') }}
|
||||
</span>
|
||||
<span class="description">GDD</span>
|
||||
</div>
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
<b-container>
|
||||
<b-form @keyup.prevent="loadSubmitButton">
|
||||
<b-row class="mb-3">
|
||||
<b-col class="col-lg-3 col-md-12 col-sm-12 text-md-left text-lg-right">
|
||||
<b-col class="col-12 col-lg-3 col-md-12 col-sm-12 text-md-left text-lg-right">
|
||||
<small>{{ $t('form.firstname') }}</small>
|
||||
</b-col>
|
||||
<b-col v-if="showUserData" class="col-sm-10 col-md-9">
|
||||
@ -42,7 +42,7 @@
|
||||
</b-col>
|
||||
</b-row>
|
||||
<b-row class="mb-3">
|
||||
<b-col class="col-lg-3 col-md-12 col-sm-12 text-md-left text-lg-right">
|
||||
<b-col class="col-12 col-lg-3 col-md-12 col-sm-12 text-md-left text-lg-right">
|
||||
<small>{{ $t('form.lastname') }}</small>
|
||||
</b-col>
|
||||
<b-col v-if="showUserData" class="col-sm-10 col-md-9">
|
||||
@ -52,8 +52,8 @@
|
||||
<b-input type="text" v-model="form.lastName"></b-input>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<b-row class="mb-3">
|
||||
<b-col class="col-lg-3 col-md-10 col-sm-10 text-md-left text-lg-right">
|
||||
<b-row class="mb-3" v-show="false">
|
||||
<b-col class="col-12 col-lg-3 col-md-10 col-sm-10 text-md-left text-lg-right">
|
||||
<small>{{ $t('form.description') }}</small>
|
||||
</b-col>
|
||||
<b-col v-if="showUserData" class="col-sm-10 col-md-9">
|
||||
@ -68,7 +68,7 @@
|
||||
<b-col>
|
||||
<div class="text-right" ref="submitButton">
|
||||
<b-button
|
||||
variant="info"
|
||||
:variant="loading ? 'default' : 'success'"
|
||||
@click="onSubmit"
|
||||
type="submit"
|
||||
class="mt-4"
|
||||
|
||||
@ -0,0 +1,127 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import UserCardFormPasswort from './UserCard_FormUserPasswort'
|
||||
import loginAPI from '../../../apis/loginAPI'
|
||||
// import flushPromises from 'flush-promises'
|
||||
|
||||
jest.mock('../../../apis/loginAPI')
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
const changePasswordProfileMock = jest.fn()
|
||||
loginAPI.changePasswordProfile = changePasswordProfileMock
|
||||
|
||||
const toastSuccessMock = jest.fn()
|
||||
const toastErrorMock = jest.fn()
|
||||
|
||||
describe('UserCardFormUserPasswort', () => {
|
||||
let wrapper
|
||||
|
||||
const mocks = {
|
||||
$t: jest.fn((t) => t),
|
||||
$store: {
|
||||
state: {
|
||||
sessionId: 1,
|
||||
email: 'user@example.org',
|
||||
},
|
||||
},
|
||||
$toast: {
|
||||
success: toastSuccessMock,
|
||||
error: toastErrorMock,
|
||||
},
|
||||
}
|
||||
|
||||
const Wrapper = () => {
|
||||
return mount(UserCardFormPasswort, { localVue, mocks })
|
||||
}
|
||||
|
||||
describe('mount', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
it('renders the component', () => {
|
||||
expect(wrapper.find('div#change_pwd').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
it('has a change password button', () => {
|
||||
expect(wrapper.find('a').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
it('has a change password button with text "form.change-password"', () => {
|
||||
expect(wrapper.find('a').text()).toEqual('form.change-password')
|
||||
})
|
||||
|
||||
it('has a change password button with a pencil icon', () => {
|
||||
expect(wrapper.find('svg.bi-pencil').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
describe('change password from', () => {
|
||||
let form
|
||||
|
||||
beforeEach(async () => {
|
||||
wrapper.find('a').trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
form = wrapper.find('form')
|
||||
})
|
||||
|
||||
it('has a change password form', () => {
|
||||
expect(form.exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
it('has a cancel button', () => {
|
||||
expect(form.find('svg.bi-x-circle').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
it('closes the form when cancel button is clicked', async () => {
|
||||
form.find('svg.bi-x-circle').trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
expect(wrapper.find('input').exists()).toBeFalsy()
|
||||
})
|
||||
|
||||
it('has three input fields', () => {
|
||||
expect(form.findAll('input')).toHaveLength(3)
|
||||
})
|
||||
|
||||
it('switches the first input type to text when show password is clicked', async () => {
|
||||
form.findAll('button').at(0).trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
expect(form.findAll('input').at(0).attributes('type')).toEqual('text')
|
||||
})
|
||||
|
||||
it('switches the second input type to text when show password is clicked', async () => {
|
||||
form.findAll('button').at(1).trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
expect(form.findAll('input').at(1).attributes('type')).toEqual('text')
|
||||
})
|
||||
|
||||
it('switches the third input type to text when show password is clicked', async () => {
|
||||
form.findAll('button').at(2).trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
expect(form.findAll('input').at(2).attributes('type')).toEqual('text')
|
||||
})
|
||||
|
||||
it('has a submit button', () => {
|
||||
expect(form.find('button[type="submit"]').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
/*
|
||||
describe('submit', () => {
|
||||
beforeEach(async () => {
|
||||
await form.findAll('input').at(0).setValue('1234')
|
||||
await form.findAll('input').at(1).setValue('Aa123456')
|
||||
await form.findAll('input').at(2).setValue('Aa123456')
|
||||
form.trigger('submit')
|
||||
await wrapper.vm.$nextTick()
|
||||
await flushPromises()
|
||||
})
|
||||
|
||||
it('calls the API', async () => {
|
||||
await wrapper.vm.$nextTick()
|
||||
await flushPromises()
|
||||
expect(changePasswordProfileMock).toHaveBeenCalledWith(1, 'user@example.org', '1234', 'Aa123456')
|
||||
})
|
||||
})
|
||||
*/
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -4,14 +4,14 @@
|
||||
<b-form @keyup.prevent="loadSubmitButton">
|
||||
<b-row class="mb-4 text-right">
|
||||
<b-col class="text-right">
|
||||
<a href="#change_pwd" v-if="edit_pwd" @click="edit_pwd = !edit_pwd">
|
||||
<span>{{ $t('form.password') }} {{ $t('form.change') }}</span>
|
||||
<a href="#change_pwd" v-if="!editPassword" @click="editPassword = !editPassword">
|
||||
<span>{{ $t('form.change-password') }}</span>
|
||||
<b-icon class="pointer ml-3" icon="pencil" />
|
||||
</a>
|
||||
|
||||
<b-icon
|
||||
v-else
|
||||
@click="edit_pwd = !edit_pwd"
|
||||
@click="cancelEdit()"
|
||||
class="pointer"
|
||||
icon="x-circle"
|
||||
variant="danger"
|
||||
@ -19,9 +19,9 @@
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<div v-if="!edit_pwd">
|
||||
<b-row class="mb-3">
|
||||
<b-col class="col-lg-3 col-md-10 col-sm-10 text-md-left text-lg-right">
|
||||
<div v-if="editPassword">
|
||||
<b-row class="mb-5">
|
||||
<b-col class="col-12 col-lg-3 col-md-10 col-sm-10 text-md-left text-lg-right">
|
||||
<small>{{ $t('form.password_old') }}</small>
|
||||
</b-col>
|
||||
<b-col class="col-md-9 col-sm-10">
|
||||
@ -43,8 +43,9 @@
|
||||
</b-input-group>
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<b-row class="mb-3">
|
||||
<b-col class="col-lg-3 col-md-10 col-sm-10 text-md-left text-lg-right">
|
||||
<b-col class="col-12 col-lg-3 col-md-10 col-sm-10 text-md-left text-lg-right">
|
||||
<small>{{ $t('form.password_new') }}</small>
|
||||
</b-col>
|
||||
<b-col class="col-md-9 col-sm-10">
|
||||
@ -67,7 +68,7 @@
|
||||
</b-col>
|
||||
</b-row>
|
||||
<b-row class="mb-3">
|
||||
<b-col class="col-lg-3 col-md-10 col-sm-10 text-md-left text-lg-right">
|
||||
<b-col class="col-12 col-lg-3 col-md-10 col-sm-10 text-md-left text-lg-right">
|
||||
<small>{{ $t('form.password_new_repeat') }}</small>
|
||||
</b-col>
|
||||
<b-col class="col-md-9 col-sm-10">
|
||||
@ -89,10 +90,31 @@
|
||||
</b-input-group>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<b-row class="text-right" v-if="!edit_pwd">
|
||||
<b-row>
|
||||
<b-col></b-col>
|
||||
<b-col class="col-12">
|
||||
<transition name="hint" appear>
|
||||
<div v-if="passwordValidation.errors.length > 0" class="hints">
|
||||
<ul>
|
||||
<li v-for="error in passwordValidation.errors" :key="error">
|
||||
<small>{{ error }}</small>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</transition>
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<b-row class="text-right" v-if="editPassword">
|
||||
<b-col>
|
||||
<div class="text-right" ref="submitButton">
|
||||
<b-button variant="info" @click="onSubmit" class="mt-4">
|
||||
<b-button
|
||||
:variant="loading ? 'default' : 'success'"
|
||||
@click="onSubmit"
|
||||
type="submit"
|
||||
class="mt-4"
|
||||
:disabled="loading"
|
||||
>
|
||||
{{ $t('form.save') }}
|
||||
</b-button>
|
||||
</div>
|
||||
@ -110,7 +132,7 @@ export default {
|
||||
name: 'FormUserPasswort',
|
||||
data() {
|
||||
return {
|
||||
edit_pwd: true,
|
||||
editPassword: false,
|
||||
email: null,
|
||||
password: '',
|
||||
passwordNew: '',
|
||||
@ -122,6 +144,12 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
cancelEdit() {
|
||||
this.editPassword = false
|
||||
this.password = ''
|
||||
this.passwordNew = ''
|
||||
this.passwordNewRepeat = ''
|
||||
},
|
||||
togglePasswordVisibilityNewPwd() {
|
||||
this.passwordVisibleNewPwd = !this.passwordVisibleNewPwd
|
||||
},
|
||||
@ -132,27 +160,58 @@ export default {
|
||||
this.passwordVisibleOldPwd = !this.passwordVisibleOldPwd
|
||||
},
|
||||
loadSubmitButton() {
|
||||
if (this.passwordVisibleNewPwd === this.passwordVisibleNewPwdRepeat) {
|
||||
if (
|
||||
this.password !== '' &&
|
||||
this.passwordNew !== '' &&
|
||||
this.passwordNewRepeat !== '' &&
|
||||
this.passwordNew === this.passwordNewRepeat
|
||||
) {
|
||||
this.loading = false
|
||||
} else {
|
||||
this.loading = true
|
||||
}
|
||||
},
|
||||
async onSubmit() {
|
||||
// console.log(this.data)
|
||||
async onSubmit(event) {
|
||||
event.preventDefault()
|
||||
const result = await loginAPI.changePasswordProfile(
|
||||
this.$store.state.sessionId,
|
||||
this.email,
|
||||
this.$store.state.email,
|
||||
this.password,
|
||||
this.passwordNew,
|
||||
)
|
||||
if (result.success) {
|
||||
alert('changePassword success')
|
||||
this.$toast.success(this.$t('site.thx.reset'))
|
||||
this.cancelEdit()
|
||||
} else {
|
||||
alert(result.result.message)
|
||||
this.$toast.error(result.result.message)
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
samePasswords() {
|
||||
return this.password === this.passwordNew
|
||||
},
|
||||
rules() {
|
||||
return [
|
||||
{ message: this.$t('site.signup.lowercase'), regex: /[a-z]+/ },
|
||||
{ message: this.$t('site.signup.uppercase'), regex: /[A-Z]+/ },
|
||||
{ message: this.$t('site.signup.minimum'), regex: /.{8,}/ },
|
||||
{ message: this.$t('site.signup.one_number'), regex: /[0-9]+/ },
|
||||
]
|
||||
},
|
||||
passwordValidation() {
|
||||
const errors = []
|
||||
for (const condition of this.rules) {
|
||||
if (!condition.regex.test(this.passwordNew)) {
|
||||
errors.push(condition.message)
|
||||
}
|
||||
}
|
||||
if (errors.length === 0) {
|
||||
return { valid: true, errors }
|
||||
}
|
||||
return { valid: false, errors }
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style></style>
|
||||
|
||||
@ -0,0 +1,121 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { extend } from 'vee-validate'
|
||||
import UserCardFormUsername from './UserCard_FormUsername'
|
||||
import loginAPI from '../../../apis/loginAPI'
|
||||
import flushPromises from 'flush-promises'
|
||||
|
||||
jest.mock('../../../apis/loginAPI')
|
||||
|
||||
extend('gddUsernameRgex', {
|
||||
validate(value) {
|
||||
return true
|
||||
},
|
||||
})
|
||||
|
||||
extend('gddUsernameUnique', {
|
||||
validate(value) {
|
||||
return true
|
||||
},
|
||||
})
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
const mockAPIcall = jest.fn((args) => {
|
||||
return { success: true }
|
||||
})
|
||||
|
||||
loginAPI.changeUsernameProfile = mockAPIcall
|
||||
|
||||
describe('UserCard_FormUsername', () => {
|
||||
let wrapper
|
||||
|
||||
const mocks = {
|
||||
$t: jest.fn((t) => t),
|
||||
$store: {
|
||||
state: {
|
||||
sessionId: 1,
|
||||
email: 'user@example.org',
|
||||
username: '',
|
||||
},
|
||||
commit: jest.fn(),
|
||||
},
|
||||
$toast: {
|
||||
success: jest.fn(),
|
||||
},
|
||||
}
|
||||
|
||||
const Wrapper = () => {
|
||||
return mount(UserCardFormUsername, { localVue, mocks })
|
||||
}
|
||||
|
||||
describe('mount', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
it('renders the component', () => {
|
||||
expect(wrapper.find('div#formusername').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
describe('username in store is empty', () => {
|
||||
it('renders an empty username', () => {
|
||||
expect(wrapper.find('div.display-username').text()).toEqual('@')
|
||||
})
|
||||
|
||||
it('has an edit icon', () => {
|
||||
expect(wrapper.find('svg.bi-pencil').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
describe('edit username', () => {
|
||||
beforeEach(async () => {
|
||||
await wrapper.find('svg.bi-pencil').trigger('click')
|
||||
})
|
||||
|
||||
it('shows an input field for the username', () => {
|
||||
expect(wrapper.find('input[placeholder="Username"]').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
it('shows an cancel icon', () => {
|
||||
expect(wrapper.find('svg.bi-x-circle').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
it('closes the input when cancel icon is clicked', async () => {
|
||||
wrapper.find('svg.bi-x-circle').trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
expect(wrapper.find('input[placeholder="Username"]').exists()).toBeFalsy()
|
||||
})
|
||||
|
||||
it('does not change the username when cancel is clicked', async () => {
|
||||
wrapper.find('input[placeholder="Username"]').setValue('username')
|
||||
wrapper.find('svg.bi-x-circle').trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
expect(wrapper.find('div.display-username').text()).toEqual('@')
|
||||
})
|
||||
|
||||
it('has a submit button', () => {
|
||||
expect(wrapper.find('button[type="submit"]').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
describe('successfull submit', () => {
|
||||
beforeEach(async () => {
|
||||
await wrapper.find('input[placeholder="Username"]').setValue('username')
|
||||
await wrapper.find('form').trigger('submit')
|
||||
await flushPromises()
|
||||
})
|
||||
|
||||
it('calls the loginAPI', () => {
|
||||
expect(mockAPIcall).toHaveBeenCalledWith(1, 'user@example.org', 'username')
|
||||
})
|
||||
|
||||
it('displays the new username', () => {
|
||||
expect(wrapper.find('div.display-username').text()).toEqual('@username')
|
||||
})
|
||||
|
||||
it('has no edit button anymore', () => {
|
||||
expect(wrapper.find('svg.bi-pencil').exists()).toBeFalsy()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -1,20 +1,19 @@
|
||||
<template>
|
||||
<b-card id="formusername" class="bg-transparent" style="background-color: #ebebeba3 !important">
|
||||
<b-container>
|
||||
<b-container v-if="username === ''">
|
||||
<b-row class="text-right">
|
||||
<b-col class="mb-3">
|
||||
<b-icon
|
||||
v-if="editUsername"
|
||||
@click="editUsername = !editUsername"
|
||||
v-if="showUsername"
|
||||
@click="showUsername = !showUsername"
|
||||
class="pointer"
|
||||
icon="pencil"
|
||||
>
|
||||
{{ $t('form.change') }}
|
||||
</b-icon>
|
||||
|
||||
<b-icon
|
||||
v-else
|
||||
@click="editUsername = !editUsername"
|
||||
@click="cancelEdit"
|
||||
class="pointer"
|
||||
icon="x-circle"
|
||||
variant="danger"
|
||||
@ -22,40 +21,48 @@
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-container>
|
||||
<b-container v-if="editUsername">
|
||||
<b-container v-if="showUsername">
|
||||
<b-row class="mb-3">
|
||||
<b-col class="col-lg-3 col-md-10 col-sm-10 text-md-left text-lg-right">
|
||||
<small>{{ $t('form.username') }}</small>
|
||||
</b-col>
|
||||
<b-col class="col-md-9 col-sm-10">@{{ username }}</b-col>
|
||||
<b-col class="col-md-9 col-sm-10 display-username">@{{ username }}</b-col>
|
||||
</b-row>
|
||||
</b-container>
|
||||
<b-container v-else>
|
||||
<b-row class="mb-3">
|
||||
<b-col class="col-lg-3 col-md-10 col-sm-10 text-md-left text-lg-right">
|
||||
<small>{{ $t('form.username') }}</small>
|
||||
</b-col>
|
||||
<b-col class="col-md-9 col-sm-10">
|
||||
<validation-observer ref="formValidator">
|
||||
<b-form role="form">
|
||||
<b-form-input v-model="form.username" :placeholder="username"></b-form-input>
|
||||
<div>
|
||||
{{ $t('form.change_username_info') }}
|
||||
<validation-observer ref="formValidator" v-slot="{ handleSubmit, valid }">
|
||||
<b-form role="form" @submit.stop.prevent="handleSubmit(onSubmit)">
|
||||
<b-row class="mb-3">
|
||||
<b-col class="col-lg-3 col-md-10 col-sm-10 text-md-left text-lg-right">
|
||||
<small>{{ $t('form.username') }}</small>
|
||||
</b-col>
|
||||
<b-col class="col-md-9 col-sm-10">
|
||||
<validation-provider
|
||||
name="Username"
|
||||
:rules="{ gddUsernameRgex: true, gddUsernameUnique: true }"
|
||||
v-slot="{ errors }"
|
||||
>
|
||||
<div v-if="errors" class="text-right p-3 p-sm-1">
|
||||
<span v-for="error in errors" :key="error" class="errors">{{ error }}</span>
|
||||
</div>
|
||||
<b-form-input v-model="form.username" placeholder="Username"></b-form-input>
|
||||
<div>
|
||||
{{ $t('form.change_username_info') }}
|
||||
</div>
|
||||
</validation-provider>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<b-row class="text-right">
|
||||
<b-col>
|
||||
<div class="text-right" ref="submitButton">
|
||||
<b-button variant="info" type="submit" class="mt-4" :disabled="!valid">
|
||||
{{ $t('form.save') }}
|
||||
</b-button>
|
||||
</div>
|
||||
</b-form>
|
||||
</validation-observer>
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<b-row class="text-right">
|
||||
<b-col>
|
||||
<div class="text-right" ref="submitButton">
|
||||
<b-button variant="info" @click="onSubmit" class="mt-4">
|
||||
{{ $t('form.save') }}
|
||||
</b-button>
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-form>
|
||||
</validation-observer>
|
||||
</b-container>
|
||||
</b-card>
|
||||
</template>
|
||||
@ -66,7 +73,7 @@ export default {
|
||||
name: 'FormUsername',
|
||||
data() {
|
||||
return {
|
||||
editUsername: true,
|
||||
showUsername: true,
|
||||
username: this.$store.state.username,
|
||||
form: {
|
||||
username: this.$store.state.username,
|
||||
@ -74,6 +81,10 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
cancelEdit() {
|
||||
this.username = this.$store.state.username
|
||||
this.showUsername = true
|
||||
},
|
||||
async onSubmit() {
|
||||
const result = await loginAPI.changeUsernameProfile(
|
||||
this.$store.state.sessionId,
|
||||
@ -82,13 +93,21 @@ export default {
|
||||
)
|
||||
if (result.success) {
|
||||
this.$store.commit('username', this.form.username)
|
||||
this.editUserdata = this.editUsername = !this.editUsername
|
||||
alert('Dein Username wurde geändert.')
|
||||
this.username = this.form.username
|
||||
this.showUsername = true
|
||||
this.$toast.success(this.$t('site.profil.user-data.change-success'))
|
||||
} else {
|
||||
alert(result.result.message)
|
||||
this.$toast.error(result.result.message)
|
||||
this.showUsername = true
|
||||
this.username = this.$store.state.username
|
||||
this.form.username = this.$store.state.username
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style></style>
|
||||
<style>
|
||||
span.errors {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -27,9 +27,9 @@ describe('UserProfileOverview', () => {
|
||||
expect(wrapper.findComponent({ name: 'FormUserData' }).exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
it('has a user name form', () => {
|
||||
expect(wrapper.findComponent({ name: 'FormUsername' }).exists()).toBeTruthy()
|
||||
})
|
||||
// it('has a user name form', () => {
|
||||
// expect(wrapper.findComponent({ name: 'FormUsername' }).exists()).toBeTruthy()
|
||||
// })
|
||||
|
||||
it('has a user password form', () => {
|
||||
expect(wrapper.findComponent({ name: 'FormUserPasswort' }).exists()).toBeTruthy()
|
||||
|
||||
@ -2,21 +2,21 @@
|
||||
<b-container fluid>
|
||||
<user-card :balance="balance" :transactionCount="transactionCount"></user-card>
|
||||
<form-user-data />
|
||||
<form-username />
|
||||
<!--<form-username />-->
|
||||
<form-user-passwort />
|
||||
</b-container>
|
||||
</template>
|
||||
<script>
|
||||
import UserCard from './UserProfile/UserCard.vue'
|
||||
import FormUserData from './UserProfile/UserCard_FormUserData.vue'
|
||||
import FormUsername from './UserProfile/UserCard_FormUsername.vue'
|
||||
// import FormUsername from './UserProfile/UserCard_FormUsername.vue'
|
||||
import FormUserPasswort from './UserProfile/UserCard_FormUserPasswort.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
UserCard,
|
||||
FormUserData,
|
||||
FormUsername,
|
||||
// FormUsername,
|
||||
FormUserPasswort,
|
||||
},
|
||||
props: {
|
||||
|
||||
@ -7,7 +7,6 @@ import * as rules from 'vee-validate/dist/rules'
|
||||
import { messages } from 'vee-validate/dist/locale/en.json'
|
||||
import RegeneratorRuntime from 'regenerator-runtime'
|
||||
import SideBar from '@/components/SidebarPlugin'
|
||||
import VueRouter from 'vue-router'
|
||||
import VueQrcode from 'vue-qrcode'
|
||||
|
||||
import VueMoment from 'vue-moment'
|
||||
@ -29,7 +28,6 @@ global.localVue.use(Vuex)
|
||||
global.localVue.use(IconsPlugin)
|
||||
global.localVue.use(RegeneratorRuntime)
|
||||
global.localVue.use(SideBar)
|
||||
global.localVue.use(VueRouter)
|
||||
global.localVue.use(VueQrcode)
|
||||
global.localVue.use(VueMoment)
|
||||
global.localVue.component('validation-provider', ValidationProvider)
|
||||
|
||||
@ -129,6 +129,7 @@ FILE(GLOB TEST_CRYPTO "src/cpp/test/crypto/*.cpp" "src/cpp/test/crypto/*.h")
|
||||
FILE(GLOB TEST_MODEL "src/cpp/test/model/*.cpp" "src/cpp/test/model/*.h")
|
||||
FILE(GLOB TEST_MODEL_TABLE "src/cpp/test/model/table/*.cpp" "src/cpp/test/model/table/*.h")
|
||||
FILE(GLOB TEST_CONTROLLER "src/cpp/test/controller/*.cpp" "src/cpp/test/controller/*.h")
|
||||
FILE(GLOB TEST_JSON_INTERFACE "src/cpp/test/JSONInterface/*.cpp" "src/cpp/test/JSONInterface/*.h")
|
||||
|
||||
SET(LOCAL_SRCS
|
||||
${CONTROLLER} ${TINF} ${MAIN} ${HTTPInterface} ${COMPILED_PAGES}
|
||||
@ -138,7 +139,7 @@ SET(LOCAL_SRCS
|
||||
${PROTO_GRADIDO} ${PROTO_HEDERA}
|
||||
)
|
||||
SET(LOCAL_TEST_SRC
|
||||
${TEST} ${TEST_CRYPTO} ${TEST_MODEL} ${TEST_MODEL_TABLE} ${TEST_CONTROLLER}
|
||||
${TEST} ${TEST_CRYPTO} ${TEST_MODEL} ${TEST_MODEL_TABLE} ${TEST_CONTROLLER} ${TEST_JSON_INTERFACE}
|
||||
)
|
||||
aux_source_directory("src/cpp" LOCAL_SRCS)
|
||||
|
||||
|
||||
@ -1,85 +1,4 @@
|
||||
|
||||
#########################################################################################################
|
||||
# Prepare debug
|
||||
#########################################################################################################
|
||||
FROM gradido/login_dependencies:gcc9-debug-3 as prepare_debug
|
||||
|
||||
ENV DOCKER_WORKDIR="/code"
|
||||
WORKDIR ${DOCKER_WORKDIR}
|
||||
|
||||
RUN echo '/usr/local/lib' >> /etc/ld.so.conf && ldconfig
|
||||
|
||||
COPY ./CMakeLists.txt.lib ./CMakeLists.txt
|
||||
RUN ln -s /usr/local/googletest ./googletest
|
||||
COPY ./src ./src
|
||||
COPY ./cmake/CodeCoverage.cmake ./cmake/CodeCoverage.cmake
|
||||
COPY ./dependencies/cmake-modules ./dependencies/cmake-modules
|
||||
COPY ./dependencies/spirit-po ./dependencies/spirit-po
|
||||
COPY ./dependencies/tinf ./dependencies/tinf
|
||||
COPY ./scripts ./scripts
|
||||
|
||||
|
||||
#########################################################################################################
|
||||
# Install Coverage tool
|
||||
#########################################################################################################
|
||||
FROM prepare_debug as coverage
|
||||
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends python3-pip && \
|
||||
apt-get autoclean && \
|
||||
apt-get autoremove && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN pip3 install gcovr setuptools wheel && \
|
||||
pip3 install fastcov
|
||||
|
||||
|
||||
#########################################################################################################
|
||||
# Build test
|
||||
#########################################################################################################
|
||||
FROM coverage as test
|
||||
|
||||
ENV DOCKER_WORKDIR="/code"
|
||||
WORKDIR ${DOCKER_WORKDIR}
|
||||
|
||||
|
||||
RUN if [ ! -d "./build_cov" ] ; then mkdir build_cov; fi
|
||||
|
||||
RUN cd build_cov && \
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DCOLLECT_COVERAGE_DATA=ON -DCOVERAGE_TOOL=fastcov ..
|
||||
#make -j$(nproc) Gradido_LoginServer_Test
|
||||
|
||||
#RUN chmod +x build_cov/bin/Gradido_LoginServer_Test
|
||||
#CMD gdb -ex run ./build_cov/bin/Gradido_LoginServer_Test
|
||||
#CMD ./build_cov/bin/Gradido_LoginServer_Test
|
||||
|
||||
#ENTRYPOINT make -C build_cov coverage
|
||||
CMD cd build_cov && make -j$(nproc) Gradido_LoginServer_Test && make coverage && \
|
||||
if [ ! -d "./coverage" ] ; then mkdir coverage; fi && \
|
||||
cp coverage.info ./coverage/
|
||||
|
||||
#########################################################################################################
|
||||
# Build debug
|
||||
#########################################################################################################
|
||||
FROM prepare_debug as debug
|
||||
|
||||
ENV DOCKER_WORKDIR="/code"
|
||||
WORKDIR ${DOCKER_WORKDIR}
|
||||
|
||||
RUN mkdir build && \
|
||||
cd build && \
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug .. && \
|
||||
make -j$(nproc) Gradido_LoginServer
|
||||
|
||||
RUN cd scripts && \
|
||||
chmod +x compile_pot.sh && \
|
||||
./compile_pot.sh
|
||||
|
||||
RUN chmod +x build/bin/Gradido_LoginServer
|
||||
ENTRYPOINT ["build/bin/Gradido_LoginServer"]
|
||||
|
||||
#########################################################################################################
|
||||
# Build release
|
||||
#########################################################################################################
|
||||
|
||||
@ -1,3 +1,14 @@
|
||||
# Login-Server Build dependencies for alpine
|
||||
# Uploaded to hub.docker.com with the tag:
|
||||
# gradido/login_dependencies:alpine-debug-3 for debug build
|
||||
# and
|
||||
# gradido/login_dependencies:alpine-release-3 for release build
|
||||
# Update tag when dependencies are added or removed
|
||||
|
||||
# Control Build Type with ARG BUILD_TYPE
|
||||
# Valid values do you find here: https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html
|
||||
# Default is set to Debug
|
||||
|
||||
|
||||
##### BUILD-ENV #####
|
||||
FROM alpine:3.13.5 as alpine-build
|
||||
49
login_server/Dockerfiles/alpine/Dockerfile.release
Normal file
49
login_server/Dockerfiles/alpine/Dockerfile.release
Normal file
@ -0,0 +1,49 @@
|
||||
|
||||
#########################################################################################################
|
||||
# Build release
|
||||
#########################################################################################################
|
||||
FROM gradido/login_dependencies:alpine-release-3 as release
|
||||
|
||||
ENV DOCKER_WORKDIR="/code"
|
||||
WORKDIR ${DOCKER_WORKDIR}
|
||||
|
||||
COPY ./CMakeLists.txt.lib ./CMakeLists.txt
|
||||
COPY ./src ./src
|
||||
RUN ln -s /usr/local/googletest ./googletest
|
||||
COPY ./dependencies/cmake-modules ./dependencies/cmake-modules
|
||||
COPY ./dependencies/spirit-po ./dependencies/spirit-po
|
||||
COPY ./dependencies/tinf ./dependencies/tinf
|
||||
COPY ./scripts ./scripts
|
||||
|
||||
RUN mkdir build && \
|
||||
cd build && \
|
||||
cmake -DCMAKE_BUILD_TYPE=Release .. && \
|
||||
make -j$(nproc) Gradido_LoginServer
|
||||
|
||||
RUN cd scripts && \
|
||||
chmod +x compile_pot.sh && \
|
||||
./compile_pot.sh
|
||||
|
||||
|
||||
#########################################################################################################
|
||||
# run release
|
||||
#########################################################################################################
|
||||
#From alpine:latest as login_server
|
||||
FROM alpine:3.13.5 as login_server
|
||||
|
||||
USER root
|
||||
WORKDIR "/usr/bin"
|
||||
|
||||
COPY --from=release /code/build/bin/Gradido_LoginServer /usr/bin/
|
||||
|
||||
COPY --from=release /usr/local/lib/mariadb/libmariadb.so.3 /usr/local/lib/
|
||||
COPY --from=release /usr/local/lib/libPoco* /usr/local/lib/
|
||||
COPY --from=release /usr/local/lib/libproto* /usr/local/lib/
|
||||
COPY --from=release /usr/lib/libsodium.so.23 /usr/lib/
|
||||
COPY --from=release /usr/lib/libstdc++.so.6 /usr/lib/
|
||||
COPY --from=release /usr/lib/libgcc_s.so.1 /usr/lib/
|
||||
|
||||
|
||||
RUN chmod +x /usr/bin/Gradido_LoginServer
|
||||
ENTRYPOINT ["/usr/bin/Gradido_LoginServer"]
|
||||
#CMD Gradido_LoginServer
|
||||
@ -1,4 +1,9 @@
|
||||
|
||||
|
||||
# Login Server build which contain the config file, found on docker hub with tag:
|
||||
# gradido/login_server:with-config
|
||||
# Used for community-server tests on staging
|
||||
|
||||
#########################################################################################################
|
||||
# Build release
|
||||
#########################################################################################################
|
||||
39
login_server/Dockerfiles/ubuntu/Dockerfile.debug
Normal file
39
login_server/Dockerfiles/ubuntu/Dockerfile.debug
Normal file
@ -0,0 +1,39 @@
|
||||
|
||||
#########################################################################################################
|
||||
# Prepare debug
|
||||
#########################################################################################################
|
||||
FROM gradido/login_dependencies:gcc9-debug-3 as prepare_debug
|
||||
|
||||
ENV DOCKER_WORKDIR="/code"
|
||||
WORKDIR ${DOCKER_WORKDIR}
|
||||
|
||||
RUN echo '/usr/local/lib' >> /etc/ld.so.conf && ldconfig
|
||||
|
||||
COPY ./CMakeLists.txt.lib ./CMakeLists.txt
|
||||
RUN ln -s /usr/local/googletest ./googletest
|
||||
COPY ./src ./src
|
||||
COPY ./cmake/CodeCoverage.cmake ./cmake/CodeCoverage.cmake
|
||||
COPY ./dependencies/cmake-modules ./dependencies/cmake-modules
|
||||
COPY ./dependencies/spirit-po ./dependencies/spirit-po
|
||||
COPY ./dependencies/tinf ./dependencies/tinf
|
||||
COPY ./scripts ./scripts
|
||||
|
||||
|
||||
#########################################################################################################
|
||||
# Build debug
|
||||
#########################################################################################################
|
||||
FROM prepare_debug as debug
|
||||
|
||||
ENV DOCKER_WORKDIR="/code"
|
||||
WORKDIR ${DOCKER_WORKDIR}
|
||||
|
||||
RUN mkdir build && \
|
||||
cd build && \
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug ..
|
||||
|
||||
RUN cd scripts && \
|
||||
chmod +x compile_pot.sh && \
|
||||
./compile_pot.sh
|
||||
|
||||
CMD cd build && cmake .. && make -j$(nproc) Gradido_LoginServer && ./bin/Gradido_LoginServer
|
||||
|
||||
@ -1,3 +1,12 @@
|
||||
# Login-Server Build dependencies for ubuntu
|
||||
# Uploaded to hub.docker.com with the tag:
|
||||
# gradido/login_dependencies:gcc9-debug-3 for debug build
|
||||
# Update tag when dependencies are added or removed
|
||||
|
||||
# Control Build Type with ARG BUILD_TYPE
|
||||
# Valid values do you find here: https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html
|
||||
# Default is set to Debug
|
||||
|
||||
##### BUILD-ENV #####
|
||||
FROM gcc:9 as gcc9_build
|
||||
|
||||
49
login_server/Dockerfiles/ubuntu/Dockerfile.release
Normal file
49
login_server/Dockerfiles/ubuntu/Dockerfile.release
Normal file
@ -0,0 +1,49 @@
|
||||
|
||||
#########################################################################################################
|
||||
# Build release
|
||||
#########################################################################################################
|
||||
FROM gradido/login_dependencies:ubuntu-release-3 as release
|
||||
|
||||
ENV DOCKER_WORKDIR="/code"
|
||||
WORKDIR ${DOCKER_WORKDIR}
|
||||
|
||||
COPY ./CMakeLists.txt.lib ./CMakeLists.txt
|
||||
COPY ./src ./src
|
||||
RUN ln -s /usr/local/googletest ./googletest
|
||||
COPY ./dependencies/cmake-modules ./dependencies/cmake-modules
|
||||
COPY ./dependencies/spirit-po ./dependencies/spirit-po
|
||||
COPY ./dependencies/tinf ./dependencies/tinf
|
||||
COPY ./scripts ./scripts
|
||||
|
||||
RUN mkdir build && \
|
||||
cd build && \
|
||||
cmake -DCMAKE_BUILD_TYPE=Release .. && \
|
||||
make -j$(nproc) Gradido_LoginServer
|
||||
|
||||
RUN cd scripts && \
|
||||
chmod +x compile_pot.sh && \
|
||||
./compile_pot.sh
|
||||
|
||||
|
||||
#########################################################################################################
|
||||
# run release
|
||||
#########################################################################################################
|
||||
#From alpine:latest as login_server
|
||||
FROM ubuntu:latest as login_server
|
||||
|
||||
USER root
|
||||
WORKDIR "/usr/bin"
|
||||
|
||||
COPY --from=release /code/build/bin/Gradido_LoginServer /usr/bin/
|
||||
|
||||
COPY --from=release /usr/local/lib/mariadb/libmariadb.so.3 /usr/local/lib/
|
||||
COPY --from=release /usr/local/lib/libPoco* /usr/local/lib/
|
||||
COPY --from=release /usr/local/lib/libproto* /usr/local/lib/
|
||||
COPY --from=release /usr/lib/libsodium.so.23 /usr/lib/
|
||||
COPY --from=release /usr/lib/libstdc++.so.6 /usr/lib/
|
||||
COPY --from=release /usr/lib/libgcc_s.so.1 /usr/lib/
|
||||
|
||||
|
||||
RUN chmod +x /usr/bin/Gradido_LoginServer
|
||||
ENTRYPOINT ["/usr/bin/Gradido_LoginServer"]
|
||||
#CMD Gradido_LoginServer
|
||||
58
login_server/Dockerfiles/ubuntu/Dockerfile.test
Normal file
58
login_server/Dockerfiles/ubuntu/Dockerfile.test
Normal file
@ -0,0 +1,58 @@
|
||||
|
||||
#########################################################################################################
|
||||
# Prepare debug
|
||||
#########################################################################################################
|
||||
FROM gradido/login_dependencies:gcc9-debug-3 as prepare_debug
|
||||
|
||||
ENV DOCKER_WORKDIR="/code"
|
||||
WORKDIR ${DOCKER_WORKDIR}
|
||||
|
||||
RUN echo '/usr/local/lib' >> /etc/ld.so.conf && ldconfig
|
||||
|
||||
COPY ./CMakeLists.txt.lib ./CMakeLists.txt
|
||||
RUN ln -s /usr/local/googletest ./googletest
|
||||
COPY ./src ./src
|
||||
COPY ./cmake/CodeCoverage.cmake ./cmake/CodeCoverage.cmake
|
||||
COPY ./dependencies/cmake-modules ./dependencies/cmake-modules
|
||||
COPY ./dependencies/spirit-po ./dependencies/spirit-po
|
||||
COPY ./dependencies/tinf ./dependencies/tinf
|
||||
COPY ./scripts ./scripts
|
||||
|
||||
|
||||
#########################################################################################################
|
||||
# Install Coverage tool
|
||||
#########################################################################################################
|
||||
FROM prepare_debug as coverage
|
||||
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends python3-pip && \
|
||||
apt-get autoclean && \
|
||||
apt-get autoremove && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
# fastcov need gcovr to work
|
||||
RUN pip3 install gcovr setuptools wheel && \
|
||||
pip3 install fastcov
|
||||
|
||||
|
||||
#########################################################################################################
|
||||
# Build test
|
||||
#########################################################################################################
|
||||
FROM coverage as test
|
||||
|
||||
ENV DOCKER_WORKDIR="/code"
|
||||
WORKDIR ${DOCKER_WORKDIR}
|
||||
|
||||
|
||||
RUN if [ ! -d "./build_cov" ] ; then mkdir build_cov; fi
|
||||
|
||||
RUN cd build_cov && \
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DCOLLECT_COVERAGE_DATA=ON -DCOVERAGE_TOOL=fastcov .. && \
|
||||
make -j$(nproc) Gradido_LoginServer_Test
|
||||
|
||||
#ENTRYPOINT make -C build_cov coverage
|
||||
CMD cd build_cov && make coverage && \
|
||||
if [ ! -d "./coverage" ] ; then mkdir coverage; fi && \
|
||||
cp coverage.info ./coverage/
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
#include "CheckEmailPage.h"
|
||||
#include "PassphrasePage.h"
|
||||
#include "SaveKeysPage.h"
|
||||
#include "TestUserGenerator.h"
|
||||
#include "ElopageWebhook.h"
|
||||
#include "ElopageWebhookLight.h"
|
||||
#include "UserUpdatePasswordPage.h"
|
||||
@ -229,6 +230,11 @@ Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::createRequestHandler(c
|
||||
return basicSetup(new LoginPage(nullptr), request, timeUsed);
|
||||
}
|
||||
}
|
||||
if (ServerConfig::g_ServerSetupType != ServerConfig::SERVER_TYPE_PRODUCTION) {
|
||||
if (url_first_part == "/testUserGenerator") {
|
||||
return basicSetup(new TestUserGenerator, request, timeUsed);
|
||||
}
|
||||
}
|
||||
return basicSetup(new LoginPage(nullptr), request, timeUsed);
|
||||
//return new HandleFileRequest;
|
||||
//return new PageRequestHandlerFactory;
|
||||
|
||||
@ -10,8 +10,6 @@
|
||||
|
||||
Poco::JSON::Object* JsonGetLogin::handle(Poco::Dynamic::Var params)
|
||||
{
|
||||
|
||||
int session_id = 0;
|
||||
auto sm = SessionManager::getInstance();
|
||||
auto pt = PendingTasksManager::getInstance();
|
||||
auto observer = SingletonTaskObserver::getInstance();
|
||||
@ -58,4 +56,4 @@ Poco::JSON::Object* JsonGetLogin::handle(Poco::Dynamic::Var params)
|
||||
//printf("[JsonGetLogin] %s\n", user_string.data());
|
||||
return result;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -227,6 +227,19 @@ Poco::JSON::Object* JsonRequestHandler::checkAndLoadSession(Poco::Dynamic::Var p
|
||||
return stateError("error parsing query params, Poco Error", ex.displayText());
|
||||
}
|
||||
}
|
||||
else if (params.type() == typeid(Poco::JSON::Object::Ptr)) {
|
||||
try {
|
||||
Poco::JSON::Object::Ptr paramJsonObject = params.extract<Poco::JSON::Object::Ptr>();
|
||||
auto session_id_obj = paramJsonObject->get("session_id");
|
||||
if (session_id_obj.isEmpty()) {
|
||||
return stateError("missing session_id");
|
||||
}
|
||||
session_id_obj.convert(session_id);
|
||||
}
|
||||
catch (Poco::Exception& ex) {
|
||||
return stateError("Poco Exception by reading session_id", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
if (!session_id) {
|
||||
return stateError("empty session id");
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
#include "JsonLoginViaEmailVerificationCode.h"
|
||||
#include "JsonLogout.h"
|
||||
#include "JsonNetworkInfos.h"
|
||||
#include "JsonResetPassword.h"
|
||||
#include "JsonSendEmail.h"
|
||||
#include "JsonAdminEmailVerificationResend.h"
|
||||
#include "JsonGetUserInfos.h"
|
||||
@ -65,7 +66,7 @@ Poco::Net::HTTPRequestHandler* JsonRequestHandlerFactory::createRequestHandler(c
|
||||
|
||||
auto sm = SessionManager::getInstance();
|
||||
Session* s = nullptr;
|
||||
if (!session_id) {
|
||||
if (session_id) {
|
||||
s = sm->getSession(session_id);
|
||||
}
|
||||
|
||||
@ -100,7 +101,7 @@ Poco::Net::HTTPRequestHandler* JsonRequestHandlerFactory::createRequestHandler(c
|
||||
return new JsonGetUserInfos;
|
||||
}
|
||||
else if (url_first_part == "/updateUserInfos") {
|
||||
return new JsonUpdateUserInfos;
|
||||
return new JsonUpdateUserInfos(s);
|
||||
}
|
||||
else if (url_first_part == "/search") {
|
||||
return new JsonSearch;
|
||||
@ -114,6 +115,9 @@ Poco::Net::HTTPRequestHandler* JsonRequestHandlerFactory::createRequestHandler(c
|
||||
else if (url_first_part == "/sendEmail") {
|
||||
return new JsonSendEmail;
|
||||
}
|
||||
else if (url_first_part == "/resetPassword") {
|
||||
return new JsonResetPassword;
|
||||
}
|
||||
else if (url_first_part == "/logout") {
|
||||
return new JsonLogout(client_host);
|
||||
}
|
||||
|
||||
53
login_server/src/cpp/JSONInterface/JsonResetPassword.cpp
Normal file
53
login_server/src/cpp/JSONInterface/JsonResetPassword.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
#include "JsonResetPassword.h"
|
||||
|
||||
#include "SingletonManager/SessionManager.h"
|
||||
#include "SingletonManager/SingletonTaskObserver.h"
|
||||
|
||||
Poco::JSON::Object* JsonResetPassword::handle(Poco::Dynamic::Var params)
|
||||
{
|
||||
auto result_session_check = checkAndLoadSession(params, false);
|
||||
if (result_session_check) {
|
||||
return result_session_check;
|
||||
}
|
||||
|
||||
std::string password;
|
||||
// if is json object
|
||||
if (params.type() == typeid(Poco::JSON::Object::Ptr)) {
|
||||
Poco::JSON::Object::Ptr paramJsonObject = params.extract<Poco::JSON::Object::Ptr>();
|
||||
try {
|
||||
auto password_obj = paramJsonObject->get("password");
|
||||
if (password_obj.isEmpty()) {
|
||||
return stateError("password missing");
|
||||
}
|
||||
password_obj.convert(password);
|
||||
}
|
||||
catch (Poco::Exception& ex) {
|
||||
return stateError("error parsing json", ex.what());
|
||||
}
|
||||
}
|
||||
auto sm = SessionManager::getInstance();
|
||||
NotificationList errors;
|
||||
if (!sm->checkPwdValidation(password, &errors, LanguageManager::getInstance()->getFreeCatalog(LANG_EN))) {
|
||||
return stateError("password isn't valid", &errors);
|
||||
}
|
||||
auto user = mSession->getNewUser();
|
||||
if (user.isNull() || user->getModel().isNull()) {
|
||||
return stateError("invalid user");
|
||||
}
|
||||
|
||||
auto observer = SingletonTaskObserver::getInstance();
|
||||
auto email_hash = observer->makeHash(user->getModel()->getEmail());
|
||||
|
||||
if (observer->getTaskCount(email_hash, TASK_OBSERVER_PASSWORD_CREATION) > 0) {
|
||||
return stateError("password encryption is already running");
|
||||
}
|
||||
|
||||
auto update_password_result = user->setNewPassword(password);
|
||||
if (update_password_result == 2) {
|
||||
KeyPairEd25519* key_pair = NULL;
|
||||
if (!user->tryLoadPassphraseUserBackup(&key_pair)) {
|
||||
user->setGradidoKeyPair(key_pair);
|
||||
}
|
||||
}
|
||||
return stateSuccess();
|
||||
}
|
||||
20
login_server/src/cpp/JSONInterface/JsonResetPassword.h
Normal file
20
login_server/src/cpp/JSONInterface/JsonResetPassword.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef __JSON_INTERFACE_JSON_RESET_PASSWORD_
|
||||
#define __JSON_INTERFACE_JSON_RESET_PASSWORD_
|
||||
|
||||
#include "JsonRequestHandler.h"
|
||||
|
||||
/*!
|
||||
* @author Dario Rekowski
|
||||
* @date 2021-06-16
|
||||
* @brief reset password, if user has forgetten his password
|
||||
*
|
||||
*/
|
||||
|
||||
class JsonResetPassword : public JsonRequestHandler
|
||||
{
|
||||
public:
|
||||
Poco::JSON::Object* handle(Poco::Dynamic::Var params);
|
||||
|
||||
};
|
||||
|
||||
#endif // __JSON_INTERFACE_JSON_RESET_PASSWORD_
|
||||
@ -99,10 +99,10 @@ Poco::JSON::Object* JsonSendEmail::handle(Poco::Dynamic::Var params)
|
||||
return stateError("invalid session");
|
||||
}
|
||||
}
|
||||
|
||||
Poco::Thread::sleep(ServerConfig::g_FakeLoginSleepTime);
|
||||
auto receiver_user = controller::User::create();
|
||||
if (1 != receiver_user->load(email)) {
|
||||
return stateError("invalid email");
|
||||
return stateSuccess();
|
||||
}
|
||||
auto receiver_user_id = receiver_user->getModel()->getID();
|
||||
std::string checkEmailUrl = receiver_user->getGroupBaseUrl() + ServerConfig::g_frontend_checkEmailPath;
|
||||
|
||||
@ -4,6 +4,13 @@
|
||||
#include "../SingletonManager/LanguageManager.h"
|
||||
#include "../tasks/AuthenticatedEncryptionCreateKeyTask.h"
|
||||
|
||||
|
||||
JsonUpdateUserInfos::JsonUpdateUserInfos(Session* session)
|
||||
: JsonRequestHandler(session)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
|
||||
{
|
||||
/*
|
||||
@ -28,7 +35,11 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
|
||||
/// Throws InvalidAccessException if Var is empty.
|
||||
try {
|
||||
paramJsonObject->get("email").convert(email);
|
||||
paramJsonObject->get("session_id").convert(session_id);
|
||||
|
||||
auto session_id_obj = paramJsonObject->get("session_id");
|
||||
if (!session_id_obj.isEmpty()) {
|
||||
session_id_obj.convert(session_id);
|
||||
}
|
||||
updates = paramJsonObject->getObject("update");
|
||||
}
|
||||
catch (Poco::Exception& ex) {
|
||||
@ -39,18 +50,21 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
|
||||
return stateError("parameter format unknown");
|
||||
}
|
||||
|
||||
if (!session_id) {
|
||||
if (!session_id && !mSession) {
|
||||
return stateError("session_id invalid");
|
||||
}
|
||||
if (updates.isNull()) {
|
||||
return stateError("update is zero or not an object");
|
||||
}
|
||||
|
||||
auto session = sm->getSession(session_id);
|
||||
if (!session) {
|
||||
if (session_id) {
|
||||
mSession = sm->getSession(session_id);
|
||||
}
|
||||
|
||||
if (!mSession) {
|
||||
return customStateError("not found", "session not found");
|
||||
}
|
||||
auto user = session->getNewUser();
|
||||
auto user = mSession->getNewUser();
|
||||
auto user_model = user->getModel();
|
||||
if (user_model->getEmail() != email) {
|
||||
return customStateError("not same", "email don't belong to logged in user");
|
||||
@ -61,6 +75,7 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
|
||||
Poco::JSON::Array jsonErrorsArray;
|
||||
|
||||
int extractet_values = 0;
|
||||
bool password_changed = false;
|
||||
//['User.first_name' => 'first_name', 'User.last_name' => 'last_name', 'User.disabled' => 0|1, 'User.language' => 'de']
|
||||
for (auto it = updates->begin(); it != updates->end(); it++) {
|
||||
std::string name = it->first;
|
||||
@ -71,7 +86,7 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
|
||||
if ( "User.first_name" == name) {
|
||||
std::string str_val = validateString(value, "User.first_name", jsonErrorsArray);
|
||||
|
||||
if (str_val.size() > 0) {
|
||||
if (str_val.size() > 0 && user_model->getFirstName() != str_val) {
|
||||
user_model->setFirstName(str_val);
|
||||
extractet_values++;
|
||||
}
|
||||
@ -79,7 +94,7 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
|
||||
else if ("User.last_name" == name ) {
|
||||
std::string str_val = validateString(value, "User.last_name", jsonErrorsArray);
|
||||
|
||||
if (str_val.size() > 0) {
|
||||
if (str_val.size() > 0 && user_model->getLastName() != str_val) {
|
||||
user_model->setLastName(str_val);
|
||||
extractet_values++;
|
||||
}
|
||||
@ -88,14 +103,18 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
|
||||
else if ("User.username" == name) {
|
||||
std::string str_val = validateString(value, "User.username", jsonErrorsArray);
|
||||
|
||||
if (str_val.size() > 0) {
|
||||
if (str_val.size() > 0 && user_model->getUsername() != str_val) {
|
||||
if (user_model->getUsername() != "") {
|
||||
jsonErrorsArray.add("change username currently not supported!");
|
||||
}
|
||||
else if (user_model->getUsername() != str_val) {
|
||||
else
|
||||
{
|
||||
if (user->isUsernameAlreadyUsed(str_val)) {
|
||||
jsonErrorsArray.add("username already used");
|
||||
}
|
||||
else if (!sm->isValid(str_val, VALIDATE_USERNAME)) {
|
||||
jsonErrorsArray.add("username must start with [a-z] or [A-Z] and than can contain also [0-9], - and _");
|
||||
}
|
||||
else {
|
||||
user_model->setUsername(str_val);
|
||||
extractet_values++;
|
||||
@ -106,33 +125,35 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
|
||||
else if ("User.description" == name) {
|
||||
std::string str_val = validateString(value, "User.description", jsonErrorsArray);
|
||||
|
||||
if (str_val.size() > 0) {
|
||||
if (str_val.size() > 0 && str_val != user_model->getDescription()) {
|
||||
user_model->setDescription(str_val);
|
||||
extractet_values++;
|
||||
}
|
||||
|
||||
}
|
||||
else if ("User.disabled" == name) {
|
||||
if (value.isBoolean()) {
|
||||
bool disabled;
|
||||
bool disabled;
|
||||
|
||||
if (value.isInteger()) {
|
||||
int idisabled;
|
||||
value.convert(idisabled);
|
||||
disabled = static_cast<bool>(idisabled);
|
||||
} else if (value.isBoolean()) {
|
||||
value.convert(disabled);
|
||||
user_model->setDisabled(disabled);
|
||||
extractet_values++;
|
||||
}
|
||||
else if (value.isInteger()) {
|
||||
int disabled;
|
||||
value.convert(disabled);
|
||||
user_model->setDisabled(static_cast<bool>(disabled));
|
||||
extractet_values++;
|
||||
}
|
||||
else {
|
||||
jsonErrorsArray.add("User.disabled isn't a boolean or integer");
|
||||
}
|
||||
if (user_model->isDisabled() != disabled) {
|
||||
user_model->setDisabled(disabled);
|
||||
extractet_values++;
|
||||
}
|
||||
}
|
||||
else if ("User.language" == name && value.size() > 0) {
|
||||
else if ("User.language" == name && value.size() > 0)
|
||||
{
|
||||
std::string str_val = validateString(value, "User.language", jsonErrorsArray);
|
||||
|
||||
if (str_val.size() > 0) {
|
||||
if (str_val.size() > 0 && user_model->getLanguageKey() != str_val) {
|
||||
auto lang = LanguageManager::languageFromString(str_val);
|
||||
if (LANG_NULL == lang) {
|
||||
jsonErrorsArray.add("User.language isn't a valid language");
|
||||
@ -144,32 +165,46 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
|
||||
}
|
||||
|
||||
}
|
||||
else if ("User.password" == name && (ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_PASSWORD_REQUESTS) == ServerConfig::UNSECURE_PASSWORD_REQUESTS) {
|
||||
else if ("User.password" == name && (ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_PASSWORD_REQUESTS) == ServerConfig::UNSECURE_PASSWORD_REQUESTS)
|
||||
{
|
||||
std::string str_val = validateString(value, "User.password", jsonErrorsArray);
|
||||
|
||||
if (str_val.size() > 0) {
|
||||
|
||||
NotificationList errors;
|
||||
if (!sm->checkPwdValidation(value.toString(), &errors, LanguageManager::getInstance()->getFreeCatalog(LANG_EN))) {
|
||||
jsonErrorsArray.add("User.password isn't valid");
|
||||
jsonErrorsArray.add(errors.getErrorsArray());
|
||||
if (str_val.size() > 0)
|
||||
{
|
||||
if (!user->hasPassword()) {
|
||||
return stateError("login state invalid");
|
||||
}
|
||||
else {
|
||||
auto result_new_password = user->setNewPassword(value.toString());
|
||||
|
||||
switch (result_new_password) {
|
||||
// 0 = new and current passwords are the same
|
||||
case 0: jsonErrorsArray.add("new password is the same as old password"); break;
|
||||
// 1 = password changed, private key re-encrypted and saved into db
|
||||
//case 1: extractet_values++; break;
|
||||
// 2 = password changed, only hash stored in db, couldn't load private key for re-encryption
|
||||
case 2: jsonErrorsArray.add("password changed, couldn't load private key for re-encryption"); break;
|
||||
// -1 = stored pubkey and private key didn't match
|
||||
case -1: jsonErrorsArray.add("stored pubkey and private key didn't match"); break;
|
||||
if (isOldPasswordValid(updates, jsonErrorsArray))
|
||||
{
|
||||
NotificationList errors;
|
||||
if (!sm->checkPwdValidation(value.toString(), &errors, LanguageManager::getInstance()->getFreeCatalog(LANG_EN))) {
|
||||
jsonErrorsArray.add("User.password isn't valid");
|
||||
jsonErrorsArray.add(errors.getErrorsArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
auto result_new_password = user->setNewPassword(value.toString());
|
||||
|
||||
switch (result_new_password) {
|
||||
// 0 = new and current passwords are the same
|
||||
// 1 = password changed, private key re-encrypted and saved into db
|
||||
case 1:
|
||||
extractet_values++;
|
||||
password_changed = true;
|
||||
break;
|
||||
// 2 = password changed, only hash stored in db, couldn't load private key for re-encryption
|
||||
case 2:
|
||||
jsonErrorsArray.add("password changed, couldn't load private key for re-encryption");
|
||||
extractet_values++;
|
||||
password_changed = true;
|
||||
break;
|
||||
// -1 = stored pubkey and private key didn't match
|
||||
case -1: jsonErrorsArray.add("stored pubkey and private key didn't match"); break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -179,7 +214,9 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
|
||||
jsonErrorsArray.add(error_message);
|
||||
}
|
||||
}
|
||||
if (extractet_values > 0) {
|
||||
// if only password was changed, no need to call an additional db update
|
||||
// password db entry will be updated inside of controller::User::setNewPassword method
|
||||
if (extractet_values - (int)password_changed > 0) {
|
||||
if (1 != user_model->updateFieldsFromCommunityServer()) {
|
||||
user_model->addError(new Error("JsonUpdateUserInfos", "error by saving update to db"));
|
||||
user_model->sendErrorsAsEmail();
|
||||
@ -188,7 +225,13 @@ Poco::JSON::Object* JsonUpdateUserInfos::handle(Poco::Dynamic::Var params)
|
||||
}
|
||||
result->set("errors", jsonErrorsArray);
|
||||
result->set("valid_values", extractet_values);
|
||||
result->set("state", "success");
|
||||
if (!jsonErrorsArray.size()) {
|
||||
result->set("state", "success");
|
||||
}
|
||||
else {
|
||||
result->set("msg", jsonErrorsArray.get(0));
|
||||
result->set("state", "error");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -206,8 +249,51 @@ std::string JsonUpdateUserInfos::validateString(Poco::Dynamic::Var value, const
|
||||
|
||||
if (string_value.size() == 0) {
|
||||
errorMessage += " is empty";
|
||||
errorArray.add(errorArray);
|
||||
errorArray.add(errorMessage);
|
||||
return "";
|
||||
}
|
||||
return string_value;
|
||||
}
|
||||
|
||||
bool JsonUpdateUserInfos::isOldPasswordValid(Poco::JSON::Object::Ptr updates, Poco::JSON::Array& errors)
|
||||
{
|
||||
auto sm = SessionManager::getInstance();
|
||||
auto user = mSession->getNewUser();
|
||||
|
||||
std::string old_password;
|
||||
|
||||
auto old_password_obj = updates->get("User.password_old");
|
||||
if (old_password_obj.isEmpty()) {
|
||||
errors.add("User.password_old not found");
|
||||
}
|
||||
else if (!old_password_obj.isString()) {
|
||||
errors.add("User.password_old isn't a string");
|
||||
}
|
||||
else {
|
||||
old_password_obj.convert(old_password);
|
||||
}
|
||||
|
||||
NotificationList local_errors;
|
||||
if (old_password.size())
|
||||
{
|
||||
if (!sm->checkPwdValidation(old_password, &local_errors, LanguageManager::getInstance()->getFreeCatalog(LANG_EN))) {
|
||||
errors.add("User.password_old didn't match");
|
||||
Poco::Thread::sleep(ServerConfig::g_FakeLoginSleepTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto secret_key = user->createSecretKey(old_password);
|
||||
if (secret_key->getKeyHashed() == user->getModel()->getPasswordHashed()) {
|
||||
return true;
|
||||
}
|
||||
else if (secret_key.isNull()) {
|
||||
errors.add("Password calculation for this user already running, please try again later");
|
||||
}
|
||||
else {
|
||||
errors.add("User.password_old didn't match");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -14,11 +14,13 @@
|
||||
class JsonUpdateUserInfos : public JsonRequestHandler
|
||||
{
|
||||
public:
|
||||
JsonUpdateUserInfos(Session* session);
|
||||
Poco::JSON::Object* handle(Poco::Dynamic::Var params);
|
||||
|
||||
protected:
|
||||
|
||||
std::string validateString(Poco::Dynamic::Var value, const char* fieldName, Poco::JSON::Array& errorArray);
|
||||
bool isOldPasswordValid(Poco::JSON::Object::Ptr updates, Poco::JSON::Array& errors);
|
||||
|
||||
|
||||
};
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
#include "HederaTaskManager.h"
|
||||
|
||||
HederaTaskManager* HederaTaskManager::getInstance()
|
||||
{
|
||||
static HederaTaskManager one;
|
||||
return &one;
|
||||
}
|
||||
|
||||
HederaTaskManager::HederaTaskManager()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
HederaTaskManager::~HederaTaskManager()
|
||||
{
|
||||
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
#ifndef __GRADIDO_LOGIN_SINGLETON_MANAGER_HEDERA_TASK_MANAGER_H
|
||||
#define __GRADIDO_LOGIN_SINGLETON_MANAGER_HEDERA_TASK_MANAGER_H
|
||||
|
||||
/*!
|
||||
* @author: Dario Rekowski
|
||||
*
|
||||
* @date: 11.09.2020
|
||||
*
|
||||
* @brief: Manage Hedera Task, waiting on Consensus for Hedera Transactions
|
||||
*
|
||||
*/
|
||||
|
||||
class HederaTaskManager
|
||||
{
|
||||
public:
|
||||
~HederaTaskManager();
|
||||
|
||||
static HederaTaskManager* getInstance();
|
||||
protected:
|
||||
HederaTaskManager();
|
||||
};
|
||||
|
||||
#endif //__GRADIDO_LOGIN_SINGLETON_MANAGER_HEDERA_TASK_MANAGER_H
|
||||
@ -42,6 +42,7 @@ int PendingTasksManager::addTask(Poco::AutoPtr<controller::PendingTask> task)
|
||||
if (task.isNull() || !task->getModel()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto model = task->getModel();
|
||||
Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
|
||||
auto pending_task_list = getTaskListForUser(model->getUserId());
|
||||
@ -235,30 +236,3 @@ Poco::AutoPtr<controller::PendingTask> PendingTasksManager::getPendingTask(int p
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void PendingTasksManager::reportErrorToCommunityServer(Poco::AutoPtr<controller::PendingTask> task, std::string error, std::string errorDetails)
|
||||
{
|
||||
// TODO: choose user specific server
|
||||
JsonRequest phpServerRequest(ServerConfig::g_php_serverHost, ServerConfig::g_phpServerPort);
|
||||
//Poco::Net::NameValueCollection payload;
|
||||
Poco::JSON::Object payload;
|
||||
|
||||
auto task_model = task->getModel();
|
||||
auto user_model = task->getUser()->getModel();
|
||||
|
||||
payload.set("created", task_model->getCreated());
|
||||
payload.set("id", task_model->getID());
|
||||
payload.set("type", task_model->getTaskTypeString());
|
||||
payload.set("public_key", user_model->getPublicKeyHex());
|
||||
payload.set("error", error);
|
||||
payload.set("errorMessage", errorDetails);
|
||||
|
||||
auto ret = phpServerRequest.request("errorInTransaction", payload);
|
||||
if (ret == JSON_REQUEST_RETURN_ERROR)
|
||||
{
|
||||
auto em = ErrorManager::getInstance();
|
||||
em->addError(new Error("PendingTasksManager::reportErrorToCommunityServer", "php server error"));
|
||||
em->getErrors(&phpServerRequest);
|
||||
em->sendErrorsAsEmail();
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,7 +50,6 @@ public:
|
||||
std::vector<Poco::AutoPtr<controller::PendingTask>> getTransactionsUserMustSign(Poco::AutoPtr<controller::User> user);
|
||||
std::vector<Poco::AutoPtr<controller::PendingTask>> getTransactionSomeoneMustSign(Poco::AutoPtr<controller::User> user);
|
||||
|
||||
void reportErrorToCommunityServer(Poco::AutoPtr<controller::PendingTask> task, std::string error, std::string errorDetails);
|
||||
|
||||
protected:
|
||||
PendingTasksManager();
|
||||
|
||||
@ -44,6 +44,7 @@ bool SessionManager::init()
|
||||
switch (i) {
|
||||
//case VALIDATE_NAME: mValidations[i] = new Poco::RegularExpression("/^[a-zA-Z_ -]{3,}$/"); break;
|
||||
case VALIDATE_NAME: mValidations[i] = new Poco::RegularExpression("^[^<>&;]{3,}$"); break;
|
||||
case VALIDATE_USERNAME: mValidations[i] = new Poco::RegularExpression("^[a-zA-Z][a-zA-Z0-9_-]*$"); break;
|
||||
case VALIDATE_EMAIL: mValidations[i] = new Poco::RegularExpression("^[a-zA-Z0-9.!#$%&?*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$"); break;
|
||||
case VALIDATE_PASSWORD: mValidations[i] = new Poco::RegularExpression("^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[@$!%*?&+-_])[A-Za-z0-9@$!%*?&+-_]{8,}$"); break;
|
||||
case VALIDATE_PASSPHRASE: mValidations[i] = new Poco::RegularExpression("^(?:[a-z]* ){23}[a-z]*\s*$"); break;
|
||||
@ -56,17 +57,17 @@ bool SessionManager::init()
|
||||
//case VALIDATE_ONLY_URL: mValidations[i] = new Poco::RegularExpression("^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}$"); break;
|
||||
case VALIDATE_ONLY_URL: mValidations[i] = new Poco::RegularExpression("^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\/?"); break;
|
||||
case VALIDATE_HAS_SPECIAL_CHARACTER: mValidations[i] = new Poco::RegularExpression(".*[@$!%*?&+-].*"); break;
|
||||
case VALIDATE_HAS_UPPERCASE_LETTER:
|
||||
mValidations[i] = new Poco::RegularExpression(".*[A-Z].*");
|
||||
case VALIDATE_HAS_UPPERCASE_LETTER:
|
||||
mValidations[i] = new Poco::RegularExpression(".*[A-Z].*");
|
||||
ServerConfig::g_ServerKeySeed->put(i, DRRandom::r64());
|
||||
break;
|
||||
case VALIDATE_HAS_LOWERCASE_LETTER: mValidations[i] = new Poco::RegularExpression(".*[a-z].*"); break;
|
||||
default: printf("[SessionManager::%s] unknown validation type\n", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mInitalized = true;
|
||||
|
||||
mInitalized = true;
|
||||
mWorkingMutex.unlock();
|
||||
return true;
|
||||
}
|
||||
@ -97,7 +98,7 @@ void SessionManager::deinitalize()
|
||||
}
|
||||
|
||||
printf("[SessionManager::deinitalize] count of dead locked sessions: %d\n", mDeadLockedSessionCount);
|
||||
|
||||
|
||||
mInitalized = false;
|
||||
mWorkingMutex.unlock();
|
||||
}
|
||||
@ -141,7 +142,7 @@ Session* SessionManager::getNewSession(int* handle)
|
||||
// first check if we have any timeouted session to directly reuse it
|
||||
checkTimeoutSession();
|
||||
|
||||
// lock
|
||||
// lock
|
||||
try {
|
||||
//Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500);
|
||||
mWorkingMutex.tryLock(500);
|
||||
@ -155,8 +156,8 @@ Session* SessionManager::getNewSession(int* handle)
|
||||
//UniLib::controller::TaskPtr checkSessionTimeout(new CheckSessionTimeouted);
|
||||
//checkSessionTimeout->scheduleTask(checkSessionTimeout);
|
||||
|
||||
// check if we have an existing session ready to use
|
||||
while (mEmptyRequestStack.size() > 0) {
|
||||
// check if we have an existing session ready to use
|
||||
while (mEmptyRequestStack.size() > 0) {
|
||||
int local_handle = mEmptyRequestStack.top();
|
||||
mEmptyRequestStack.pop();
|
||||
auto resultIt = mRequestSessionMap.find(local_handle);
|
||||
@ -185,10 +186,10 @@ Session* SessionManager::getNewSession(int* handle)
|
||||
|
||||
mRequestSessionMap.erase(local_handle);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// else create new RequestSession Object
|
||||
// calculate random handle
|
||||
// check if already exist, if get new
|
||||
@ -210,7 +211,7 @@ Session* SessionManager::getNewSession(int* handle)
|
||||
//printf("[SessionManager::getNewSession] handle: %ld, sum: %u\n", newHandle, mRequestSessionMap.size());
|
||||
mWorkingMutex.unlock();
|
||||
return requestSession;
|
||||
|
||||
|
||||
|
||||
//return nullptr;
|
||||
}
|
||||
@ -230,7 +231,7 @@ bool SessionManager::releaseSession(int requestHandleSession)
|
||||
return false;
|
||||
}
|
||||
//mWorkingMutex.lock();
|
||||
|
||||
|
||||
auto it = mRequestSessionMap.find(requestHandleSession);
|
||||
if (it == mRequestSessionMap.end()) {
|
||||
//printf("[SessionManager::releaseRequestSession] requestSession with handle: %d not found\n", requestHandleSession);
|
||||
@ -241,16 +242,15 @@ bool SessionManager::releaseSession(int requestHandleSession)
|
||||
|
||||
|
||||
// delete session, not reuse as workaround for server freeze bug
|
||||
mRequestSessionMap.erase(requestHandleSession);
|
||||
/*mRequestSessionMap.erase(requestHandleSession);
|
||||
delete session;
|
||||
mWorkingMutex.unlock();
|
||||
return true;
|
||||
|
||||
*/
|
||||
|
||||
|
||||
// check if dead locked
|
||||
if (session->tryLock()) {
|
||||
session->unlock();
|
||||
if (!session->isDeadLocked()) {
|
||||
session->reset();
|
||||
session->setActive(false);
|
||||
}
|
||||
@ -263,9 +263,9 @@ bool SessionManager::releaseSession(int requestHandleSession)
|
||||
mWorkingMutex.unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// change request handle we don't want session hijacking
|
||||
|
||||
|
||||
// hardcoded disabled session max
|
||||
if (mEmptyRequestStack.size() > 100) {
|
||||
mRequestSessionMap.erase(requestHandleSession);
|
||||
@ -284,11 +284,11 @@ bool SessionManager::releaseSession(int requestHandleSession)
|
||||
mWorkingMutex.unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
session->setHandle(newHandle);
|
||||
mRequestSessionMap.insert(std::pair<int, Session*>(newHandle, session));
|
||||
mEmptyRequestStack.push(newHandle);
|
||||
|
||||
|
||||
mWorkingMutex.unlock();
|
||||
return true;
|
||||
}
|
||||
@ -353,13 +353,11 @@ Session* SessionManager::getSession(int handle)
|
||||
}
|
||||
if (0 == handle) return nullptr;
|
||||
Session* result = nullptr;
|
||||
try {
|
||||
//Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500);
|
||||
mWorkingMutex.tryLock(500);
|
||||
}
|
||||
catch (Poco::TimeoutException &ex) {
|
||||
printf("[SessionManager::getSession] exception timout mutex: %s\n", ex.displayText().data());
|
||||
return result;
|
||||
|
||||
|
||||
if(!mWorkingMutex.tryLock(500)) {
|
||||
printf("[SessionManager::getSession] exception timout mutex: \n");
|
||||
return result;
|
||||
}
|
||||
//mWorkingMutex.lock();
|
||||
auto it = mRequestSessionMap.find(handle);
|
||||
@ -375,14 +373,12 @@ Session* SessionManager::getSession(int handle)
|
||||
return nullptr;
|
||||
}
|
||||
if (0 == iResult) {
|
||||
//printf("[SessionManager::getSession] session isn't active\n");
|
||||
mWorkingMutex.unlock();
|
||||
return nullptr;
|
||||
}
|
||||
//result->setActive(true);
|
||||
result->updateTimeout();
|
||||
}
|
||||
//printf("[SessionManager::getSession] handle: %ld\n", handle);
|
||||
mWorkingMutex.unlock();
|
||||
return result;
|
||||
}
|
||||
@ -417,8 +413,8 @@ Session* SessionManager::findByUserId(int userId)
|
||||
}
|
||||
//mWorkingMutex.lock();
|
||||
for (auto it = mRequestSessionMap.begin(); it != mRequestSessionMap.end(); it++) {
|
||||
while (it->second->isDeadLocked())
|
||||
{
|
||||
while (it->second->isDeadLocked())
|
||||
{
|
||||
it = mRequestSessionMap.erase(it);
|
||||
mDeadLockedSessionCount++;
|
||||
auto em = ErrorManager::getInstance();
|
||||
@ -483,7 +479,7 @@ std::vector<Session*> SessionManager::findAllByUserId(int userId)
|
||||
Session* SessionManager::findByEmail(const std::string& email)
|
||||
{
|
||||
assert(email.size() > 0);
|
||||
|
||||
|
||||
try {
|
||||
//Poco::Mutex::ScopedLock _lock(mWorkingMutex, 500);
|
||||
mWorkingMutex.tryLock(500);
|
||||
@ -604,23 +600,23 @@ bool SessionManager::checkPwdValidation(const std::string& pwd, NotificationList
|
||||
|
||||
if (!isValid(pwd, VALIDATE_PASSWORD)) {
|
||||
errorReciver->addError(new Error(
|
||||
lang->gettext("Password"),
|
||||
lang->gettext("Password"),
|
||||
lang->gettext("Please enter a valid password with at least 8 characters, upper and lower case letters, at least one number and one special character (@$!%*?&+-_)!")));
|
||||
|
||||
// @$!%*?&+-
|
||||
if (pwd.size() < 8) {
|
||||
errorReciver->addError(new Error(
|
||||
lang->gettext("Password"),
|
||||
lang->gettext("Password"),
|
||||
lang->gettext("Your password is to short!")));
|
||||
}
|
||||
else if (!isValid(pwd, VALIDATE_HAS_LOWERCASE_LETTER)) {
|
||||
errorReciver->addError(new Error(
|
||||
lang->gettext("Password"),
|
||||
lang->gettext("Password"),
|
||||
lang->gettext("Your password does not contain lowercase letters!")));
|
||||
}
|
||||
else if (!isValid(pwd, VALIDATE_HAS_UPPERCASE_LETTER)) {
|
||||
errorReciver->addError(new Error(
|
||||
lang->gettext("Password"),
|
||||
lang->gettext("Password"),
|
||||
lang->gettext("Your password does not contain any capital letters!")));
|
||||
}
|
||||
else if (!isValid(pwd, VALIDATE_HAS_NUMBER)) {
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
|
||||
enum SessionValidationTypes {
|
||||
VALIDATE_NAME,
|
||||
VALIDATE_USERNAME,
|
||||
VALIDATE_EMAIL,
|
||||
VALIDATE_PASSWORD,
|
||||
VALIDATE_PASSPHRASE,
|
||||
|
||||
@ -194,20 +194,14 @@ namespace controller {
|
||||
return json;
|
||||
}
|
||||
|
||||
int User::login(const std::string& password)
|
||||
Poco::AutoPtr<SecretKeyCryptography> User::createSecretKey(const std::string& password)
|
||||
{
|
||||
if (!mPassword.isNull() && mPassword->hasKey()) {
|
||||
return 2;
|
||||
}
|
||||
auto observer = SingletonTaskObserver::getInstance();
|
||||
|
||||
std::unique_lock<std::shared_mutex> _lock(mSharedMutex);
|
||||
assert(mPassword.isNull());
|
||||
|
||||
auto model = getModel();
|
||||
auto email_hash = observer->makeHash(model->getEmail());
|
||||
if (observer->getTaskCount(email_hash, TASK_OBSERVER_PASSWORD_CREATION) > 0) {
|
||||
return -3;
|
||||
return nullptr;
|
||||
}
|
||||
observer->addTask(email_hash, TASK_OBSERVER_PASSWORD_CREATION);
|
||||
Poco::AutoPtr<SecretKeyCryptography> authenticated_encryption(new SecretKeyCryptography);
|
||||
@ -215,7 +209,23 @@ namespace controller {
|
||||
authenticated_encryption->createKey(model->getEmail(), password);
|
||||
|
||||
observer->removeTask(email_hash, TASK_OBSERVER_PASSWORD_CREATION);
|
||||
return authenticated_encryption;
|
||||
}
|
||||
|
||||
int User::login(const std::string& password)
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> _lock(mSharedMutex);
|
||||
|
||||
if (!mPassword.isNull() && mPassword->hasKey()) {
|
||||
return 2;
|
||||
}
|
||||
assert(mPassword.isNull());
|
||||
|
||||
auto authenticated_encryption = createSecretKey(password);
|
||||
if (authenticated_encryption.isNull()) {
|
||||
return -3;
|
||||
}
|
||||
auto model = getModel();
|
||||
if (authenticated_encryption->getKeyHashed() == model->getPasswordHashed())
|
||||
{
|
||||
// printf("[User::login] password key hashed is the same as saved password hash\n");
|
||||
|
||||
@ -96,6 +96,9 @@ namespace controller {
|
||||
//! - create authenticated encryption key from password and email
|
||||
//! - compare hash with in db saved hash
|
||||
int login(const std::string& password);
|
||||
|
||||
//! \brief simply check if password is correct, independent if user is already logged in or not
|
||||
Poco::AutoPtr<SecretKeyCryptography> createSecretKey(const std::string& password);
|
||||
|
||||
// ***********************************************************************************
|
||||
// password related
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
/*!
|
||||
|
||||
|
||||
\brief Container Wrapper class for mutex protected container
|
||||
changed to poco mutex for gradido login server
|
||||
default mutex from poco is recursive so it is some heavy thing
|
||||
@ -47,7 +47,7 @@ namespace UniLib {
|
||||
// \return false if mutex was locked from another thread
|
||||
bool tryLock();
|
||||
|
||||
inline void unlock() { mLastSucceededLock = ""; mWorkMutex.unlock(); }
|
||||
inline void unlock() { mWorkMutex.unlock(); mLastSucceededLock = ""; }
|
||||
|
||||
inline const std::string& getLastSucceededLock() { return mLastSucceededLock; }
|
||||
protected:
|
||||
@ -58,4 +58,4 @@ namespace UniLib {
|
||||
}
|
||||
}
|
||||
|
||||
#endif //__DR_UNIVERSUM_LIB_LIB_MULTITHREAD_CONTAINER_H__
|
||||
#endif //__DR_UNIVERSUM_LIB_LIB_MULTITHREAD_CONTAINER_H__
|
||||
|
||||
@ -84,29 +84,30 @@ void Session::reset()
|
||||
int Session::isActive()
|
||||
{
|
||||
int ret = 0;
|
||||
try {
|
||||
mWorkMutex.tryLock(100);
|
||||
}
|
||||
catch (Poco::TimeoutException &ex) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!mWorkMutex.tryLock(100)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = (int)mActive;
|
||||
unlock();
|
||||
|
||||
try {
|
||||
unlock();
|
||||
} catch(Poco::SystemException& ex) {
|
||||
addError(new ParamError("Session::isActive", "exception unlocking mutex", ex.what()));
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
bool Session::isDeadLocked()
|
||||
{
|
||||
try {
|
||||
mWorkMutex.tryLock(200);
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
catch (Poco::Exception& ex) {
|
||||
|
||||
}
|
||||
return true;
|
||||
if(!mWorkMutex.tryLock(200)) {
|
||||
return true;
|
||||
};
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Session::setActive(bool active)
|
||||
@ -922,12 +923,11 @@ bool Session::useOrGeneratePassphrase(const std::string& passphase)
|
||||
bool Session::lastTransactionTheSame(Poco::AutoPtr<model::gradido::Transaction> newTransaction)
|
||||
{
|
||||
assert(!newTransaction.isNull());
|
||||
lock();
|
||||
Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
|
||||
if (mLastTransaction.isNull()) {
|
||||
return false;
|
||||
}
|
||||
bool result = mLastTransaction->isTheSameTransaction(newTransaction);
|
||||
unlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -358,6 +358,9 @@ namespace model {
|
||||
}
|
||||
//UniLib::controller::TaskPtr transaction_send_task(new SendTransactionTask(Poco::AutoPtr<Transaction>(this, true)));
|
||||
//transaction_send_task->scheduleTask(transaction_send_task);
|
||||
auto pt = PendingTasksManager::getInstance();
|
||||
|
||||
pt->removeTask(Poco::AutoPtr<Transaction>(this, true));
|
||||
return 1 == runSendTransaction();
|
||||
//return true;
|
||||
}
|
||||
@ -507,9 +510,6 @@ namespace model {
|
||||
addError(new ParamError(function_name, "unknown error", TransactionValidationToString(result)));
|
||||
//sendErrorsAsEmail();
|
||||
}
|
||||
|
||||
auto pt = PendingTasksManager::getInstance();
|
||||
pt->reportErrorToCommunityServer(Poco::AutoPtr<Transaction>(this, true), error_name, error_description);
|
||||
addError(new ParamError(function_name, error_name, error_description));
|
||||
}
|
||||
return -1;
|
||||
@ -563,13 +563,13 @@ namespace model {
|
||||
auto result = json_request.request("putTransaction", param);
|
||||
json_request.getWarnings(&json_request);
|
||||
|
||||
if (JSON_REQUEST_RETURN_OK == result)
|
||||
{
|
||||
if (JSON_REQUEST_RETURN_OK == result)
|
||||
{
|
||||
if (!json_request.errorCount()) {
|
||||
finishSuccess();
|
||||
}
|
||||
else {
|
||||
getErrors(&json_request);
|
||||
getErrors(&json_request);
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
|
||||
@ -56,9 +56,9 @@ namespace model {
|
||||
try {
|
||||
auto res = select.execute();
|
||||
if (1 == res) { return true; }
|
||||
|
||||
|
||||
}
|
||||
catch (Poco::Exception& ex) {
|
||||
catch (Poco::Exception& ex) {
|
||||
addError(new ParamError(getTableName(), "mysql error by select id", ex.displayText().data()));
|
||||
addError(new ParamError(getTableName(), "data set: ", toString().data()));
|
||||
}
|
||||
@ -126,20 +126,22 @@ namespace model {
|
||||
{
|
||||
Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
|
||||
mReferenceCount++;
|
||||
//printf("[ModelBase::duplicate] new value: %d\n", mReferenceCount);
|
||||
}
|
||||
|
||||
void ModelBase::release()
|
||||
{
|
||||
Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
|
||||
if(mReferenceCount <= 0) {
|
||||
throw Poco::Exception("ModelBase already released", getTableName());
|
||||
}
|
||||
|
||||
Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
|
||||
|
||||
mReferenceCount--;
|
||||
//printf("[ModelBase::release] new value: %d\n", mReferenceCount);
|
||||
|
||||
if (0 == mReferenceCount) {
|
||||
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Poco::Data::Statement ModelBase::_loadFromDB(Poco::Data::Session session, const std::vector<std::string>& fieldNames, MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/)
|
||||
@ -180,7 +182,7 @@ namespace model {
|
||||
Poco::Mutex& timeMutex = ServerConfig::g_TimeMutex;
|
||||
|
||||
int year, month, day, hour, minute, second;
|
||||
// ex: 2009-10-29
|
||||
// ex: 2009-10-29
|
||||
if (sscanf(decodedDateString.data(), "%d-%d-%dT%d:%dZ", &year, &month, &day, &hour, &minute) != EOF) {
|
||||
time_t rawTime;
|
||||
time(&rawTime);
|
||||
|
||||
@ -70,7 +70,11 @@ namespace model
|
||||
{
|
||||
SHARED_LOCK;
|
||||
temp = mResultJsonString;
|
||||
if(!mResultJsonString.size()) {
|
||||
return new Poco::JSON::Object;
|
||||
}
|
||||
}
|
||||
|
||||
Poco::JSON::Parser parser;
|
||||
Poco::Dynamic::Var result;
|
||||
try
|
||||
|
||||
@ -68,7 +68,6 @@ TEST(TestJsonCheckUsername, UsernameWithoutGroup)
|
||||
ASSERT_TRUE(msg.isString());
|
||||
ASSERT_EQ(msg.toString(), "no group given");
|
||||
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
@ -89,6 +88,8 @@ TEST(TestJsonCheckUsername, ExistingUsername)
|
||||
ASSERT_FALSE(msg.isEmpty());
|
||||
ASSERT_TRUE(msg.isString());
|
||||
ASSERT_EQ(msg.toString(), "username already in use");
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
TEST(TestJsonCheckUsername, NewUsername)
|
||||
@ -103,6 +104,8 @@ TEST(TestJsonCheckUsername, NewUsername)
|
||||
ASSERT_FALSE(state.isEmpty());
|
||||
ASSERT_TRUE(state.isString());
|
||||
ASSERT_EQ(state.toString(), "success");
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
TEST(TestJsonCheckUsername, UsernameExistInOtherGroup)
|
||||
@ -118,6 +121,7 @@ TEST(TestJsonCheckUsername, UsernameExistInOtherGroup)
|
||||
ASSERT_TRUE(state.isString());
|
||||
ASSERT_EQ(state.toString(), "success");
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,100 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "JSONInterface/JsonResetPassword.h"
|
||||
#include "TestJsonResetPassword.h"
|
||||
#include "lib/Profiler.h"
|
||||
|
||||
|
||||
void TestJsonResetPassword::SetUp()
|
||||
{
|
||||
auto sm = SessionManager::getInstance();
|
||||
//sm->init();
|
||||
mUserSession = sm->getNewSession();
|
||||
auto user = controller::User::create();
|
||||
user->load("Nikola_Tesla@email.de");
|
||||
mUserSession->setUser(user);
|
||||
}
|
||||
|
||||
void TestJsonResetPassword::TearDown()
|
||||
{
|
||||
auto sm = SessionManager::getInstance();
|
||||
if (!mUserSession) {
|
||||
sm->releaseSession(mUserSession);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_F(TestJsonResetPassword, WithoutSession)
|
||||
{
|
||||
JsonResetPassword jsonCall;
|
||||
Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
|
||||
params->set("password", "ashze_Sja/63");
|
||||
auto result = jsonCall.handle(params);
|
||||
|
||||
auto state = result->get("state");
|
||||
ASSERT_FALSE(state.isEmpty());
|
||||
ASSERT_TRUE(state.isString());
|
||||
ASSERT_EQ(state.toString(), "error");
|
||||
|
||||
auto msg = result->get("msg");
|
||||
ASSERT_FALSE(msg.isEmpty());
|
||||
ASSERT_TRUE(msg.isString());
|
||||
ASSERT_EQ(msg.toString(), "missing session_id");
|
||||
|
||||
}
|
||||
|
||||
TEST_F(TestJsonResetPassword, WithoutPassword)
|
||||
{
|
||||
JsonResetPassword jsonCall;
|
||||
Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
|
||||
params->set("session_id", mUserSession->getHandle());
|
||||
auto result = jsonCall.handle(params);
|
||||
|
||||
auto state = result->get("state");
|
||||
ASSERT_FALSE(state.isEmpty());
|
||||
ASSERT_TRUE(state.isString());
|
||||
ASSERT_EQ(state.toString(), "error");
|
||||
|
||||
auto msg = result->get("msg");
|
||||
ASSERT_FALSE(msg.isEmpty());
|
||||
ASSERT_TRUE(msg.isString());
|
||||
ASSERT_EQ(msg.toString(), "password missing");
|
||||
}
|
||||
|
||||
TEST_F(TestJsonResetPassword, InvalidPassword)
|
||||
{
|
||||
JsonResetPassword jsonCall;
|
||||
Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
|
||||
params->set("session_id", mUserSession->getHandle());
|
||||
params->set("password", "ash");
|
||||
auto result = jsonCall.handle(params);
|
||||
|
||||
auto state = result->get("state");
|
||||
ASSERT_FALSE(state.isEmpty());
|
||||
ASSERT_TRUE(state.isString());
|
||||
if ((ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_ALLOW_ALL_PASSWORDS) == ServerConfig::UNSECURE_ALLOW_ALL_PASSWORDS) {
|
||||
ASSERT_EQ(state.toString(), "success");
|
||||
}
|
||||
else {
|
||||
ASSERT_EQ(state.toString(), "error");
|
||||
|
||||
auto msg = result->get("msg");
|
||||
ASSERT_FALSE(msg.isEmpty());
|
||||
ASSERT_TRUE(msg.isString());
|
||||
ASSERT_EQ(msg.toString(), "password isn't valid");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestJsonResetPassword, ValidPassword)
|
||||
{
|
||||
JsonResetPassword jsonCall;
|
||||
Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
|
||||
params->set("session_id", mUserSession->getHandle());
|
||||
params->set("password", "hath6/&Sja");
|
||||
auto result = jsonCall.handle(params);
|
||||
|
||||
auto state = result->get("state");
|
||||
ASSERT_FALSE(state.isEmpty());
|
||||
ASSERT_TRUE(state.isString());
|
||||
ASSERT_EQ(state.toString(), "success");
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
#ifndef __GRADIDO_LOGIN_SERVER_TEST_JSON_INTERFACE_TEST_JSON_RESET_PASSWORD_H
|
||||
#define __GRADIDO_LOGIN_SERVER_TEST_JSON_INTERFACE_TEST_JSON_RESET_PASSWORD_H
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "SingletonManager/SessionManager.h"
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
|
||||
class TestJsonResetPassword : public ::testing::Test
|
||||
{
|
||||
|
||||
protected:
|
||||
void SetUp() override;
|
||||
void TearDown() override;
|
||||
|
||||
Session* mUserSession;
|
||||
|
||||
};
|
||||
|
||||
#endif //__GRADIDO_LOGIN_SERVER_TEST_JSON_INTERFACE_TEST_JSON_RESET_PASSWORD_H
|
||||
@ -0,0 +1,317 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "JSONInterface/JsonUpdateUserInfos.h"
|
||||
#include "TestJsonUpdateUserInfos.h"
|
||||
#include "lib/Profiler.h"
|
||||
|
||||
|
||||
void TestJsonUpdateUserInfos::SetUp()
|
||||
{
|
||||
auto sm = SessionManager::getInstance();
|
||||
//sm->init();
|
||||
mUserSession = sm->getNewSession();
|
||||
auto user = controller::User::create();
|
||||
user->load("Jeet_bb@gmail.com");
|
||||
mUserSession->setUser(user);
|
||||
}
|
||||
|
||||
void TestJsonUpdateUserInfos::TearDown()
|
||||
{
|
||||
auto sm = SessionManager::getInstance();
|
||||
if (!mUserSession) {
|
||||
sm->releaseSession(mUserSession);
|
||||
}
|
||||
}
|
||||
|
||||
Poco::JSON::Object::Ptr TestJsonUpdateUserInfos::chooseAccount(const Poco::JSON::Object::Ptr update)
|
||||
{
|
||||
Poco::JSON::Object::Ptr params = new Poco::JSON::Object;
|
||||
params->set("email", mUserSession->getNewUser()->getModel()->getEmail());
|
||||
params->set("update", update);
|
||||
return params;
|
||||
}
|
||||
|
||||
|
||||
TEST_F(TestJsonUpdateUserInfos, EmptyOldPassword)
|
||||
{
|
||||
JsonUpdateUserInfos jsonCall(mUserSession);
|
||||
ASSERT_EQ(mUserSession->loadUser("Jeet_bb@gmail.com", "TestP4ssword&H"), USER_COMPLETE);
|
||||
|
||||
Poco::JSON::Object::Ptr update = new Poco::JSON::Object;
|
||||
|
||||
update->set("User.password", "haLL1o_/%s");
|
||||
|
||||
auto params = chooseAccount(update);
|
||||
Profiler timeUsed;
|
||||
auto result = jsonCall.handle(params);
|
||||
ASSERT_LE(timeUsed.millis(), 300);
|
||||
|
||||
auto errors = result->get("errors");
|
||||
ASSERT_TRUE(errors.isArray());
|
||||
auto valid_values_obj = result->get("valid_values");
|
||||
ASSERT_TRUE(valid_values_obj.isInteger());
|
||||
int valid_values = 0;
|
||||
valid_values_obj.convert(valid_values);
|
||||
ASSERT_EQ(valid_values, 0);
|
||||
//User.password_old not found
|
||||
Poco::JSON::Array error_array = errors.extract<Poco::JSON::Array>();
|
||||
|
||||
ASSERT_EQ(error_array.size(), 1);
|
||||
ASSERT_EQ(error_array.getElement<std::string>(0), "User.password_old not found");
|
||||
|
||||
auto state = result->get("state");
|
||||
ASSERT_FALSE(state.isEmpty());
|
||||
ASSERT_TRUE(state.isString());
|
||||
ASSERT_EQ(state.toString(), "error");
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
TEST_F(TestJsonUpdateUserInfos, OnlyOldPassword)
|
||||
{
|
||||
JsonUpdateUserInfos jsonCall(mUserSession);
|
||||
Poco::JSON::Object::Ptr update = new Poco::JSON::Object;
|
||||
|
||||
update->set("User.password_old", "TestP4ssword&H");
|
||||
|
||||
auto params = chooseAccount(update);
|
||||
Profiler timeUsed;
|
||||
auto result = jsonCall.handle(params);
|
||||
ASSERT_LE(timeUsed.millis(), 200);
|
||||
|
||||
auto errors = result->get("errors");
|
||||
ASSERT_TRUE(errors.isArray());
|
||||
auto valid_values_obj = result->get("valid_values");
|
||||
ASSERT_TRUE(valid_values_obj.isInteger());
|
||||
int valid_values = 0;
|
||||
valid_values_obj.convert(valid_values);
|
||||
ASSERT_EQ(valid_values, 0);
|
||||
Poco::JSON::Array error_array = errors.extract<Poco::JSON::Array>();
|
||||
ASSERT_EQ(error_array.size(), 0);
|
||||
|
||||
auto state = result->get("state");
|
||||
ASSERT_FALSE(state.isEmpty());
|
||||
ASSERT_TRUE(state.isString());
|
||||
ASSERT_EQ(state.toString(), "success");
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
TEST_F(TestJsonUpdateUserInfos, WrongPassword)
|
||||
{
|
||||
JsonUpdateUserInfos jsonCall(mUserSession);
|
||||
ASSERT_EQ(mUserSession->loadUser("Jeet_bb@gmail.com", "TestP4ssword&H"), USER_COMPLETE);
|
||||
Poco::JSON::Object::Ptr update = new Poco::JSON::Object;
|
||||
|
||||
update->set("User.password", "newPassword");
|
||||
update->set("User.password_old", "TestP4sswordH");
|
||||
|
||||
auto params = chooseAccount(update);
|
||||
Profiler timeUsed;
|
||||
auto result = jsonCall.handle(params);
|
||||
ASSERT_GE(timeUsed.millis(), ServerConfig::g_FakeLoginSleepTime * 0.75);
|
||||
|
||||
auto errors = result->get("errors");
|
||||
ASSERT_TRUE(errors.isArray());
|
||||
auto valid_values_obj = result->get("valid_values");
|
||||
ASSERT_TRUE(valid_values_obj.isInteger());
|
||||
int valid_values = 0;
|
||||
valid_values_obj.convert(valid_values);
|
||||
ASSERT_EQ(valid_values, 0);
|
||||
Poco::JSON::Array error_array = errors.extract<Poco::JSON::Array>();
|
||||
ASSERT_EQ(error_array.size(), 1);
|
||||
ASSERT_EQ(error_array.getElement<std::string>(0), "User.password_old didn't match");
|
||||
|
||||
auto state = result->get("state");
|
||||
ASSERT_FALSE(state.isEmpty());
|
||||
ASSERT_TRUE(state.isString());
|
||||
ASSERT_EQ(state.toString(), "error");
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
TEST_F(TestJsonUpdateUserInfos, EmptyPassword)
|
||||
{
|
||||
JsonUpdateUserInfos jsonCall(mUserSession);
|
||||
Poco::JSON::Object::Ptr update = new Poco::JSON::Object;
|
||||
|
||||
update->set("User.password", "");
|
||||
update->set("User.password_old", "TestP4sswordH");
|
||||
|
||||
auto params = chooseAccount(update);
|
||||
Profiler timeUsed;
|
||||
auto result = jsonCall.handle(params);
|
||||
ASSERT_LE(timeUsed.millis(), 200);
|
||||
|
||||
auto errors = result->get("errors");
|
||||
ASSERT_TRUE(errors.isArray());
|
||||
auto valid_values_obj = result->get("valid_values");
|
||||
ASSERT_TRUE(valid_values_obj.isInteger());
|
||||
int valid_values = 0;
|
||||
valid_values_obj.convert(valid_values);
|
||||
ASSERT_EQ(valid_values, 0);
|
||||
Poco::JSON::Array error_array = errors.extract<Poco::JSON::Array>();
|
||||
ASSERT_EQ(error_array.size(), 1);
|
||||
ASSERT_EQ(error_array.getElement<std::string>(0), "User.password is empty");
|
||||
|
||||
auto state = result->get("state");
|
||||
ASSERT_FALSE(state.isEmpty());
|
||||
ASSERT_TRUE(state.isString());
|
||||
ASSERT_EQ(state.toString(), "error");
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
TEST_F(TestJsonUpdateUserInfos, NewPasswordSameAsOldPassword)
|
||||
{
|
||||
JsonUpdateUserInfos jsonCall(mUserSession);
|
||||
ASSERT_EQ(mUserSession->loadUser("Jeet_bb@gmail.com", "TestP4ssword&H"), USER_COMPLETE);
|
||||
|
||||
Poco::JSON::Object::Ptr update = new Poco::JSON::Object;
|
||||
|
||||
update->set("User.password", "TestP4ssword&H");
|
||||
update->set("User.password_old", "TestP4ssword&H");
|
||||
|
||||
auto params = chooseAccount(update);
|
||||
Profiler timeUsed;
|
||||
auto result = jsonCall.handle(params);
|
||||
ASSERT_GE(timeUsed.millis(), ServerConfig::g_FakeLoginSleepTime * 0.75);
|
||||
|
||||
auto errors = result->get("errors");
|
||||
ASSERT_TRUE(errors.isArray());
|
||||
auto valid_values_obj = result->get("valid_values");
|
||||
ASSERT_TRUE(valid_values_obj.isInteger());
|
||||
int valid_values = 0;
|
||||
valid_values_obj.convert(valid_values);
|
||||
|
||||
Poco::JSON::Array error_array = errors.extract<Poco::JSON::Array>();
|
||||
auto state = result->get("state");
|
||||
ASSERT_FALSE(state.isEmpty());
|
||||
ASSERT_TRUE(state.isString());
|
||||
|
||||
|
||||
EXPECT_EQ(valid_values, 0);
|
||||
ASSERT_EQ(error_array.size(), 0);
|
||||
ASSERT_EQ(state.toString(), "success");
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
TEST_F(TestJsonUpdateUserInfos, PasswordNotSecureEnough)
|
||||
{
|
||||
JsonUpdateUserInfos jsonCall(mUserSession);
|
||||
ASSERT_EQ(mUserSession->loadUser("Jeet_bb@gmail.com", "TestP4ssword&H"), USER_COMPLETE);
|
||||
|
||||
Poco::JSON::Object::Ptr update = new Poco::JSON::Object;
|
||||
|
||||
update->set("User.password", "newPassword");
|
||||
update->set("User.password_old", "TestP4ssword&H");
|
||||
|
||||
auto params = chooseAccount(update);
|
||||
Profiler timeUsed;
|
||||
auto result = jsonCall.handle(params);
|
||||
ASSERT_GE(timeUsed.millis(), ServerConfig::g_FakeLoginSleepTime * 0.75);
|
||||
|
||||
auto errors = result->get("errors");
|
||||
ASSERT_TRUE(errors.isArray());
|
||||
auto valid_values_obj = result->get("valid_values");
|
||||
ASSERT_TRUE(valid_values_obj.isInteger());
|
||||
int valid_values = 0;
|
||||
valid_values_obj.convert(valid_values);
|
||||
|
||||
Poco::JSON::Array error_array = errors.extract<Poco::JSON::Array>();
|
||||
auto state = result->get("state");
|
||||
ASSERT_FALSE(state.isEmpty());
|
||||
ASSERT_TRUE(state.isString());
|
||||
|
||||
if ((ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_ALLOW_ALL_PASSWORDS) == ServerConfig::UNSECURE_ALLOW_ALL_PASSWORDS) {
|
||||
EXPECT_EQ(valid_values, 1);
|
||||
ASSERT_EQ(error_array.size(), 0);
|
||||
ASSERT_EQ(state.toString(), "success");
|
||||
}
|
||||
else {
|
||||
EXPECT_EQ(valid_values, 0);
|
||||
|
||||
ASSERT_EQ(error_array.size(), 2);
|
||||
ASSERT_EQ(error_array.getElement<std::string>(0), "User.password isn't valid");
|
||||
|
||||
ASSERT_EQ(state.toString(), "error");
|
||||
}
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
|
||||
TEST_F(TestJsonUpdateUserInfos, PasswordCorrect)
|
||||
{
|
||||
JsonUpdateUserInfos jsonCall(mUserSession);
|
||||
Poco::JSON::Object::Ptr update = new Poco::JSON::Object;
|
||||
|
||||
update->set("User.password", "uasjUs7ZS/as12");
|
||||
|
||||
if ((ServerConfig::g_AllowUnsecureFlags & ServerConfig::UNSECURE_ALLOW_ALL_PASSWORDS) == ServerConfig::UNSECURE_ALLOW_ALL_PASSWORDS) {
|
||||
ASSERT_EQ(mUserSession->loadUser("Jeet_bb@gmail.com", "newPassword"), USER_COMPLETE);
|
||||
update->set("User.password_old", "newPassword");
|
||||
}
|
||||
else {
|
||||
ASSERT_EQ(mUserSession->loadUser("Jeet_bb@gmail.com", "TestP4ssword&H"), USER_COMPLETE);
|
||||
update->set("User.password_old", "TestP4ssword&H");
|
||||
}
|
||||
|
||||
auto params = chooseAccount(update);
|
||||
Profiler timeUsed;
|
||||
auto result = jsonCall.handle(params);
|
||||
ASSERT_GE(timeUsed.millis(), ServerConfig::g_FakeLoginSleepTime * 0.75);
|
||||
|
||||
auto errors = result->get("errors");
|
||||
ASSERT_TRUE(errors.isArray());
|
||||
auto valid_values_obj = result->get("valid_values");
|
||||
ASSERT_TRUE(valid_values_obj.isInteger());
|
||||
int valid_values = 0;
|
||||
valid_values_obj.convert(valid_values);
|
||||
|
||||
Poco::JSON::Array error_array = errors.extract<Poco::JSON::Array>();
|
||||
auto state = result->get("state");
|
||||
ASSERT_FALSE(state.isEmpty());
|
||||
ASSERT_TRUE(state.isString());
|
||||
|
||||
EXPECT_EQ(valid_values, 1);
|
||||
ASSERT_EQ(error_array.size(), 0);
|
||||
ASSERT_EQ(state.toString(), "success");
|
||||
|
||||
delete result;
|
||||
}
|
||||
//*/
|
||||
TEST_F(TestJsonUpdateUserInfos, NoChanges)
|
||||
{
|
||||
JsonUpdateUserInfos jsonCall(mUserSession);
|
||||
|
||||
Poco::JSON::Object::Ptr update = new Poco::JSON::Object;
|
||||
|
||||
update->set("User.first_name", "Darios");
|
||||
update->set("User.last_name", "Bruder");
|
||||
|
||||
auto params = chooseAccount(update);
|
||||
Profiler timeUsed;
|
||||
auto result = jsonCall.handle(params);
|
||||
|
||||
auto errors = result->get("errors");
|
||||
ASSERT_TRUE(errors.isArray());
|
||||
auto valid_values_obj = result->get("valid_values");
|
||||
ASSERT_TRUE(valid_values_obj.isInteger());
|
||||
int valid_values = 0;
|
||||
valid_values_obj.convert(valid_values);
|
||||
|
||||
Poco::JSON::Array error_array = errors.extract<Poco::JSON::Array>();
|
||||
auto state = result->get("state");
|
||||
ASSERT_FALSE(state.isEmpty());
|
||||
ASSERT_TRUE(state.isString());
|
||||
|
||||
|
||||
EXPECT_EQ(valid_values, 0);
|
||||
ASSERT_EQ(error_array.size(), 0);
|
||||
ASSERT_EQ(state.toString(), "success");
|
||||
|
||||
|
||||
delete result;
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
#ifndef __GRADIDO_LOGIN_SERVER_TEST_JSON_INTERFACE_TEST_JSON_UPDATE_USER_INFOS_H
|
||||
#define __GRADIDO_LOGIN_SERVER_TEST_JSON_INTERFACE_TEST_JSON_UPDATE_USER_INFOS_H
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "SingletonManager/SessionManager.h"
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
|
||||
class TestJsonUpdateUserInfos : public ::testing::Test
|
||||
{
|
||||
|
||||
protected:
|
||||
void SetUp() override;
|
||||
void TearDown() override;
|
||||
|
||||
Poco::JSON::Object::Ptr chooseAccount(const Poco::JSON::Object::Ptr update);
|
||||
|
||||
Session* mUserSession;
|
||||
std::string mEmail;
|
||||
|
||||
};
|
||||
|
||||
#endif //__GRADIDO_LOGIN_SERVER_TEST_JSON_INTERFACE_TEST_JSON_UPDATE_USER_INFOS_H
|
||||
@ -13,9 +13,12 @@
|
||||
#include "Poco/SplitterChannel.h"
|
||||
|
||||
#include "../SingletonManager/ConnectionManager.h"
|
||||
#include "../SingletonManager/SessionManager.h"
|
||||
|
||||
#include "../lib/Profiler.h"
|
||||
|
||||
#include "Crypto/SecretKeyCryptography.h"
|
||||
|
||||
|
||||
std::list<Test*> gTests;
|
||||
|
||||
@ -27,7 +30,7 @@ void fillTests()
|
||||
// gTests.push_back(new LoginTest());
|
||||
}
|
||||
|
||||
void runMysql(std::string sqlQuery)
|
||||
int runMysql(std::string sqlQuery)
|
||||
{
|
||||
auto cm = ConnectionManager::getInstance();
|
||||
auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER);
|
||||
@ -38,8 +41,10 @@ void runMysql(std::string sqlQuery)
|
||||
mysqlStatement.execute(true);
|
||||
}
|
||||
catch (Poco::Exception& ex) {
|
||||
printf("exception in runMysql: %s\n", ex.displayText().data());
|
||||
std::clog << "exception in runMysql: " << ex.displayText() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int load(int argc, char* argv[]) {
|
||||
@ -47,6 +52,9 @@ int load(int argc, char* argv[]) {
|
||||
std::clog << "[load]" << std::endl;
|
||||
Poco::AutoPtr<Poco::Util::LayeredConfiguration> test_config(new Poco::Util::LayeredConfiguration);
|
||||
std::string config_file_name = Poco::Path::config() + "grd_login/grd_login_test.properties";
|
||||
#ifdef WIN32
|
||||
config_file_name = "Gradido_LoginServer_Test.properties";
|
||||
#endif
|
||||
if(argc > 1 && strlen(argv[1]) > 4) {
|
||||
config_file_name = argv[1];
|
||||
}
|
||||
@ -66,11 +74,11 @@ int load(int argc, char* argv[]) {
|
||||
|
||||
if (!ServerConfig::initServerCrypto(*test_config)) {
|
||||
//printf("[Gradido_LoginServer::%s] error init server crypto\n", __FUNCTION__);
|
||||
printf("[load] error init server crypto");
|
||||
std::clog << "[load] error init server crypto" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
if (!ServerConfig::loadMnemonicWordLists()) {
|
||||
printf("[load] error in loadMnemonicWordLists");
|
||||
std::clog << "[load] error in loadMnemonicWordLists" << std::endl;
|
||||
return -2;
|
||||
}
|
||||
|
||||
@ -79,6 +87,9 @@ int load(int argc, char* argv[]) {
|
||||
|
||||
ServerConfig::g_CPUScheduler = new UniLib::controller::CPUSheduler(worker_count, "Default Worker");
|
||||
ServerConfig::g_CryptoCPUScheduler = new UniLib::controller::CPUSheduler(2, "Crypto Worker");
|
||||
ServerConfig::g_disableEmail = true;
|
||||
|
||||
SessionManager::getInstance()->init();
|
||||
|
||||
// load up connection configs
|
||||
// register MySQL connector
|
||||
@ -95,7 +106,7 @@ int load(int argc, char* argv[]) {
|
||||
}
|
||||
catch (Poco::Exception& ex) {
|
||||
// maybe we in docker environment and db needs some time to start up
|
||||
printf("Poco Exception by connecting to db: %s, let's try again\n", ex.displayText().data());
|
||||
std::clog << "Poco Exception by connecting to db: " << ex.displayText() << ", let's try again" << std::endl;
|
||||
}
|
||||
if(!connected) {
|
||||
// let's wait 10 seconds
|
||||
@ -110,7 +121,7 @@ int load(int argc, char* argv[]) {
|
||||
connected = true;
|
||||
}
|
||||
} catch(Poco::Exception& ex) {
|
||||
printf("Poco Exception by connecting to db: %s, let's wait another 10 seconds\n", ex.displayText().data());
|
||||
std::clog << "Poco Exception by connecting to db: " << ex.displayText() << ", let's wait another 10 seconds" << std::endl;
|
||||
}
|
||||
}
|
||||
if(!connected) {
|
||||
@ -118,10 +129,21 @@ int load(int argc, char* argv[]) {
|
||||
try {
|
||||
conn->setConnectionsFromConfig(*test_config, CONNECTION_MYSQL_LOGIN_SERVER);
|
||||
} catch(Poco::Exception& ex) {
|
||||
printf("Poco Exception by connecting to db: %s, exit\n", ex.displayText().data());
|
||||
std::clog << "Poco Exception by connecting to db: " << ex.displayText() << ", exit" << std::endl;
|
||||
return -4;
|
||||
}
|
||||
}
|
||||
|
||||
// password hash from user 2 in test user entry
|
||||
Poco::UInt64 precalculated_password_hash = 10417562666175322069;
|
||||
|
||||
std::clog << "measure Time for secret key generation..." << std::endl;
|
||||
Profiler timeForArgon2;
|
||||
SecretKeyCryptography secret_cryptografie;
|
||||
secret_cryptografie.createKey("Jeet_bb@gmail.com", "TestP4ssword&H");
|
||||
ServerConfig::g_FakeLoginSleepTime = timeForArgon2.millis();
|
||||
|
||||
std::clog << "time for secret key generation: " << timeForArgon2.string() << std::endl;
|
||||
|
||||
std::string log_Path = "/var/log/grd_login/";
|
||||
//#ifdef _WIN32
|
||||
@ -144,6 +166,7 @@ int load(int argc, char* argv[]) {
|
||||
|
||||
log.error("Test Error");
|
||||
|
||||
|
||||
//errorLog
|
||||
|
||||
//printf("try connect php server mysql \n");
|
||||
@ -157,31 +180,47 @@ int load(int argc, char* argv[]) {
|
||||
"users"
|
||||
};
|
||||
for (int i = 0; i < 2; i++) {
|
||||
runMysql("TRUNCATE " + tables[i]);
|
||||
runMysql("ALTER TABLE " + tables[i] + " AUTO_INCREMENT = 1");
|
||||
if (runMysql("TRUNCATE " + tables[i])) {
|
||||
return -1;
|
||||
}
|
||||
if (runMysql("ALTER TABLE " + tables[i] + " AUTO_INCREMENT = 1")) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
// password = TestP4ssword&H
|
||||
ss << "INSERT INTO `users` (`id`, `email`, `first_name`, `last_name`, `username`, `password`, `pubkey`, `privkey`, `created`, `email_checked`, `passphrase_shown`, `language`, `disabled`, `group_id`) VALUES "
|
||||
<< "(1, 'd_schultz32@gmx.de', 'DDD', 'Schultz', 'Diddel', 13134558453895551556, 0x146d3fb9e88abc0fca0b0091c1ab1b32b399be037436f340befa8bf004461889, 0x0dcc08960f45f631fe23bc7ddee0724cedc9ec0c861ce30f5091d20ffd96062d08ca215726fb9bd64860c754772e945eea4cc872ed0a36c7b640e8b0bf7a873ec6765fa510711622341347ce2307b5ce, '2020-02-20 16:05:44', 1, 0, 'de', 0, 1), "
|
||||
<< "(2, 'Jeet_bb@gmail.com', 'Darios', 'Bruder', 'Jeet', 12910944485867375321, 0x952e215a21d4376b4ac252c4bf41e156e1498e1b6b8ccf2a6826d96712f4f461, 0x4d40bf0860655f728312140dc3741e897bc2d13d00ea80a63e2961046a5a7bd8315397dfb488b89377087bc1a5f4f3af8ffdcf203329ae23ba04be7d38ad3852699d90ff1fc00e5b1ca92b64cc59c01f, '2020-02-20 16:05:44', 1, 0, 'de', 0, 1), "
|
||||
<< "(3, 'Tiger_231@yahoo.com', 'Dieter', 'Schultz', 'Tiger', 13528673707291575501, 0xb539944bf6444a2bfc988244f0c0c9dc326452be9b8a2a43fcd90663719f4f6d, 0x5461fda60b719b65ba00bd6298e48410c4cbf0e89deb13cc784ba8978cf047454e8556ee3eddc8487ee835c33a83163bc8d8babbf2a5c431876bc0a0c114ff0a0d6b57baa12cf8f23c64fb642c862db5, '2020-02-20 16:05:45', 1, 0, 'de', 0, 1), "
|
||||
<< "(4, 'Nikola_Tesla@email.de', 'Nikola', 'Tesla', 'Erfinder', 15522411320147607375, 0x476b059744f08b0995522b484c90f8d2f47d9b59f4b3c96d9dc0ae6ab7b84979, 0x5277bf044cba4fec64e6f4d38da132755b029161231daefc9a7b4692ad37e05cdd88e0a2c2215baf854dd3a813578c214167af1113607e9f999ca848a7598ba5068e38f2a1afb097e4752a88024d79c8, '2020-02-20 16:05:46', 1, 0, 'de', 0, 1), "
|
||||
<< "(5, 'Elfenhausen@arcor.de', 'Thomas', 'Markuk', 'Elf', 7022671043835614958, 0xb1584e169d60a7e771d3a348235dfd7b5f9e8235fcc26090761a0264b0daa6ff, 0xb46fb7110bf91e28f367aa80f84d1bbd639b6f689f4b0aa28c0f71529232df9bf9ee0fb02fa4c1b9f5a6799c82d119e5646f7231d011517379faaacf6513d973ac3043d4c786490ba62d56d75b86164d, '2020-02-20 16:05:46', 1, 0, 'de', 0, 1), "
|
||||
<< "(6, 'coin-info12@gradido.net', 'coin-info12', 'Test', 'Test Username', 1548398919826089202, 0x4046ae49c1b620f2a321aba0c874fa2bc7ba844ab808bb0eeb18a908d468db14, 0x9522657ecd7456eedf86d065aa087ba7a94a8961a8e4950d044136155d38fe0840f2c0a2876ce055b3eaa6e9ab95c5feba89e535e0434fb2648d94d6e6ec68211aa2ea9e42d1ccd40b6b3c31e41f848e, '2020-02-20 16:05:47', 1, 0, 'de', 0, 1), "
|
||||
<< "(7, 'AlexWesper@gmail.com', 'Alex', 'Wesper', 'Wespe', 5822761891727948301, 0xb13ede3402abb8f29722b14fec0a2006ae7a3a51fb677cd6a2bbd797ac6905a5, 0x6aa39d7670c64a31639c7d89b874ad929b2eaeb2e5992dbad71b6cea700bf9e3c6cf866d0f0fdc22b44a0ebf51a860799e880ef86266199931dd0a301e5552db44b9b7fa99ed5945652bc7b31eff767c, '2020-02-20 16:05:47', 1, 0, 'de', 0, 1); ";
|
||||
runMysql(ss.str());
|
||||
<< "(1, 'd_schultz32@gmx.de', 'DDD', 'Schultz', 'Diddel', 18242007140018938940, 0x69f2fefd6fa6947a370b9f8d3147f6617cf67416517ce25cb2d63901c666933c, 0x567f3e623a1899d1f8d69190c5799433c134ce0137c0c38cc0347874586d6234a19f2a0b484e6cc1863502e580ae6c17db1131f29a35eba45a46be29c7ee592940a3bd3ad519075fdeed6e368f0eb818, '2020-02-20 16:05:44', 1, 0, 'de', 0, 1), ";
|
||||
|
||||
// if this isn't the same, some tests will fail, so we update the test data here.
|
||||
if (secret_cryptografie.getKeyHashed() != precalculated_password_hash) {
|
||||
ss << "(2, 'Jeet_bb@gmail.com', 'Darios', 'Bruder', 'Jeet', " << secret_cryptografie.getKeyHashed() << ", 0, 0, '2020-02-20 16:05:44', 1, 0, 'de', 0, 1), ";
|
||||
}
|
||||
else {
|
||||
ss << "(2, 'Jeet_bb@gmail.com', 'Darios', 'Bruder', 'Jeet', 10417562666175322069, 0x6afd24f46eb79a839281fe537a1888155b102d4fbe0613ea92d51845bd8036cb, 0xe7aed71cd4ae2d1aba9343ffb3822b759f972e41b63a6032b7f6c69f566217784c2e7bcdaeaa2f7dd16bf3b6f1540b22afa65fc054550a9296454c6ecdbd4131eac7f9c703318a867e666691e1808a6e, '2020-02-20 16:05:44', 1, 0, 'de', 0, 1), ";
|
||||
}
|
||||
ss << "(3, 'Tiger_231@yahoo.com', 'Dieter', 'Schultz', 'Tiger', 13790258844849208764, 0x9a79a5daea92218608fa1e3a657d78961dc04c97ff996cc0ea17d6896b5368e6, 0x4993a156a120728f0fa93fc63ab01482ed85ecf433c729c8426c4bb93f0b7ce6142fda531b11f5d5e925acd1d2e55fdfef94fe07dbb78d43322f7df1234c7251aa58946c96ec6e551395f0fb5e87decf, '2020-02-20 16:05:45', 1, 0, 'de', 0, 1), "
|
||||
<< "(4, 'Nikola_Tesla@email.de', 'Nikola', 'Tesla', 'Erfinder', 1914014100253540772, 0x1c199421a66070afb28cb7c37de98865b28924bff26161bb65faaf5695050ee3, 0xe38ca460ca748954b29d79f0e943eed3ba85e7e13b18f69349666e31a8e3b06c9df105171796b37b4201895a2f3fe8ec8bf58a181700caaa5752a94a968c50e90ebb6280002a056126b2055ff75d69d1, '2020-02-20 16:05:46', 1, 0, 'de', 0, 1), "
|
||||
<< "(5, 'Elfenhausen@arcor.de', 'Thomas', 'Markuk', 'Elf', 8105871797752167168, 0x98d703f0ea1def3ef9e6265a76281d125a94c80665425bd7a844580ec1a2ce98, 0x63612a1d07d78a0c945d765a10a30d9de2be602e79e3f39268d731bc6f7fa945d7d04c638000bae089ac058263f52e7c1f2c3550b35b5727e41523f2f592781add65d12b8b8c0b3226f32174cfa1bcee, '2020-02-20 16:05:46', 1, 0, 'de', 0, 1), "
|
||||
<< "(6, 'coin-info12@gradido.net', 'coin-info12', 'Test', 'Test Username', 9005874071610817324, 0xb3ee1c82a9877f664d05364106e259621b2e203bfbb5323edb7b597051efecc2, 0xa039da7d59e2475dd1aaa635f803ec1aeffc2506e7a96a934bf8d7cf4ac2a96dc962d4e1bdf8e11c5ce7e18189edc36014b89e9e72628004ec5901be6c407a955efb5142a1ee9a2f3aed888125a44aa2, '2020-02-20 16:05:47', 1, 0, 'de', 0, 1), "
|
||||
<< "(7, 'AlexWesper@gmail.com', 'Alex', 'Wesper', 'Wespe', 7264393213873828644, 0x735a5c22ebe84ab1d6453991d50019b677b82b0663b023c30127ec906ee9b59a, 0xaec30051ad3ab2d2132a76e9dfe5a396d2dfbcc83a4eb27223b4da8803893959af9e29c6963f9e73eddc447cb3d3995527b94054e7fdecd7d5f8cb45c3954ff9bb2c9e0374f2124b3170301f990c5d7d, '2020-02-20 16:05:47', 1, 0, 'de', 0, 1); ";
|
||||
if (runMysql(ss.str())) {
|
||||
return -1;
|
||||
}
|
||||
ss.str(std::string());
|
||||
|
||||
ss << "INSERT INTO `groups` (`id`, `alias`, `name`, `url`, `description`) VALUES"
|
||||
<< "(1, 'gdd1', 'Gradido1', 'gdd1.gradido.com', 'Der erste offizielle Gradido Server (zum Testen)'), "
|
||||
<< "(2, 'gdd_test', 'Gradido Test', 'gdd1.gradido.com', 'Testgroup (zum Testen)'); ";
|
||||
runMysql(ss.str());
|
||||
if (runMysql(ss.str())) {
|
||||
return -1;
|
||||
}
|
||||
ss.str(std::string());
|
||||
|
||||
|
||||
|
||||
printf("init db in : %s\n", timeUsed.string().data());
|
||||
std::clog << "init db in : " << timeUsed.string() << std::endl;
|
||||
|
||||
|
||||
fillTests();
|
||||
@ -198,10 +237,10 @@ int run()
|
||||
std::clog << "[Gradido_LoginServer_Test::run]" << std::endl;
|
||||
for (std::list<Test*>::iterator it = gTests.begin(); it != gTests.end(); it++)
|
||||
{
|
||||
//printf("running: %s\n", it->getName());
|
||||
printf("running test: %s\n", (*it)->getName());
|
||||
std::string name = (*it)->getName();
|
||||
std::clog << "running test: " << name << std::endl;
|
||||
try {
|
||||
if (!(*it)->test()) printf("success\n");
|
||||
if (!(*it)->test()) std::clog << "Success" << std::endl;
|
||||
} catch(std::exception& ex) {
|
||||
std::clog << "exception in running test: " << ex.what() << std::endl;
|
||||
}
|
||||
@ -209,7 +248,7 @@ int run()
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ende()
|
||||
void endegTests()
|
||||
{
|
||||
for (std::list<Test*>::iterator it = gTests.begin(); it != gTests.end(); it++)
|
||||
{
|
||||
@ -219,6 +258,7 @@ void ende()
|
||||
|
||||
}
|
||||
gTests.clear();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -226,20 +266,24 @@ int main(int argc, char** argv)
|
||||
{
|
||||
try {
|
||||
if (load(argc, argv) < 0) {
|
||||
printf("early exit\n");
|
||||
std::clog << "early exit" << std::endl;
|
||||
return -42;
|
||||
}
|
||||
} catch(std::exception& ex) {
|
||||
printf("no catched exception while loading: %s\n", ex.what());
|
||||
std::string exception_text = ex.what();
|
||||
std::clog << "no catched exception while loading: " << exception_text << std::endl;
|
||||
}
|
||||
|
||||
//printf ("\nStack Limit = %ld and %ld max\n", limit.rlim_cur, limit.rlim_max);
|
||||
|
||||
run();
|
||||
ende();
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
endegTests();
|
||||
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
auto result = RUN_ALL_TESTS();
|
||||
|
||||
SessionManager::getInstance()->deinitalize();
|
||||
ServerConfig::unload();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
102
login_server/src/cpsp/TestUserGenerator.cpsp
Normal file
102
login_server/src/cpsp/TestUserGenerator.cpsp
Normal file
@ -0,0 +1,102 @@
|
||||
<%@ page class="TestUserGenerator" %>
|
||||
<%@ page form="true" %>
|
||||
<%@ page baseClass="PageRequestMessagedHandler" %>
|
||||
<%@ header include="HTTPInterface/PageRequestMessagedHandler.h" %>
|
||||
<%!
|
||||
#include "Crypto/SecretKeyCryptography.h"
|
||||
#include "Crypto/KeyPairEd25519.h"
|
||||
#include "ServerConfig.h"
|
||||
#include "lib/DataTypeConverter.h"
|
||||
|
||||
#include "controller/User.h"
|
||||
%>
|
||||
<%%
|
||||
const char* pageName = "Test User Generator";
|
||||
// needed for header_large
|
||||
auto user = controller::User::create();
|
||||
|
||||
std::string email;
|
||||
std::string password_hashed;
|
||||
std::string pubkey_hex;
|
||||
std::string privkey_hex_encrypted;
|
||||
std::string passphrase_str;
|
||||
|
||||
bool user_created = false;
|
||||
// add
|
||||
if(!form.empty()) {
|
||||
email = form.get("email", "");
|
||||
auto password = form.get("password", "");
|
||||
if(email == "") {
|
||||
addError(new Error("Create User", "E-Mail is empty!"));
|
||||
}
|
||||
else if(password == "") {
|
||||
addError(new Error("Create User", "Password is empty!"));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto passphrase = Passphrase::generate(&ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER]);
|
||||
passphrase_str = passphrase->getString();
|
||||
auto key_pair = KeyPairEd25519::create(passphrase);
|
||||
Poco::AutoPtr<SecretKeyCryptography> secret_key = new SecretKeyCryptography;
|
||||
secret_key->createKey(email, password);
|
||||
password_hashed = std::to_string(secret_key->getKeyHashed());
|
||||
auto privkey_encrypted = key_pair->getCryptedPrivKey(secret_key);
|
||||
privkey_hex_encrypted = DataTypeConverter::binToHex(privkey_encrypted);
|
||||
pubkey_hex = key_pair->getPublicKeyHex();
|
||||
user_created = true;
|
||||
delete key_pair;
|
||||
}
|
||||
}
|
||||
|
||||
// select all
|
||||
auto groups = controller::Group::listAll();
|
||||
//auto groups = controller::Group::load("gdd1");
|
||||
//std::vector<Poco::SharedPtr<controller::Group>> groups;
|
||||
|
||||
%><%@ include file="include/header_large.cpsp" %>
|
||||
<%= getErrorsHtml() %>
|
||||
<div class="center-form-container">
|
||||
<div class="center-form-title">
|
||||
<h3>Einen neuen User anlegen</h3>
|
||||
</div>
|
||||
<div class="center-form-form">
|
||||
<form method="POST">
|
||||
<label class="form-label" for="email">Email</label>
|
||||
<input class="form-control" id="email" type="text" name="email"/>
|
||||
<label class="form-label" for="password">Password</label>
|
||||
<input class="form-control" id="password" type="text" name="password"/>
|
||||
<input class="center-form-submit form-button" type="submit" name="submit" value="Create User">
|
||||
</form>
|
||||
</div>
|
||||
<% if(user_created) { %>
|
||||
<div class="content-list">
|
||||
<div class="content-list-title">
|
||||
<h2>Generierte Daten</h2>
|
||||
</div>
|
||||
<div class="content-list-table">
|
||||
<div class="row">
|
||||
<div class="cell header-cell c4">E-Mail</div>
|
||||
<div class="cell c4"><%= email %></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell header-cell c4">Password hash</div>
|
||||
<div class="cell c3"><%= password_hashed %></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell header-cell c4">public key</div>
|
||||
<div class="cell c5">0x<%= pubkey_hex %></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell header-cell c4">private key encrypted</div>
|
||||
<div class="cell c6">0x<%= privkey_hex_encrypted %></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="cell header-cell c4">Passphrase</div>
|
||||
<div class="cell c10"><%= passphrase_str %></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<pre>'<%= email %>', <%= password_hashed %>, 0x<%= pubkey_hex %>, 0x<%= privkey_hex_encrypted %></pre>
|
||||
<% } %>
|
||||
</div>
|
||||
<%@ include file="include/footer.cpsp" %>
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gradido",
|
||||
"version": "1.0.2",
|
||||
"version": "1.1.0",
|
||||
"description": "Gradido",
|
||||
"main": "index.js",
|
||||
"repository": "git@github.com:gradido/gradido.git",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user