From 6d040e17a2b76401a85f010862f08f4538b85875 Mon Sep 17 00:00:00 2001 From: benjamin Date: Sun, 11 Aug 2019 01:51:37 +0200 Subject: [PATCH] authentification --- WEB/package-lock.json | 1016 ++++++++++++++++- WEB/package.json | 2 + WEB/src/app/account/account-routing.module.ts | 17 + WEB/src/app/account/account.module.ts | 14 + .../components/login/login.component.html | 21 + .../components/login/login.component.less | 5 + .../components/login/login.component.spec.ts | 25 + .../login/components/login/login.component.ts | 41 + .../modules/login/login-routing.module.ts | 19 + .../app/account/modules/login/login.module.ts | 24 + WEB/src/app/app-routing.module.ts | 8 +- WEB/src/app/app.module.ts | 10 + WEB/src/app/guards/auth.guard.spec.ts | 15 + WEB/src/app/guards/auth.guard.ts | 27 + .../app/services/access-right.service.spec.ts | 41 + WEB/src/app/services/access-right.service.ts | 43 + WEB/src/app/services/auth.service.spec.ts | 47 + WEB/src/app/services/auth.service.ts | 64 ++ WEB/src/app/services/role.definition.ts | 7 + WEB/src/app/services/roles.model.ts | 5 + WEB/src/app/services/user.model.ts | 10 + .../songs/table/table.component.less | 20 - WEB/src/environments/environment.ts | 11 +- WEB/src/styles.less | 79 +- WEB/tslint.json | 1 - 25 files changed, 1471 insertions(+), 101 deletions(-) create mode 100644 WEB/src/app/account/account-routing.module.ts create mode 100644 WEB/src/app/account/account.module.ts create mode 100644 WEB/src/app/account/modules/login/components/login/login.component.html create mode 100644 WEB/src/app/account/modules/login/components/login/login.component.less create mode 100644 WEB/src/app/account/modules/login/components/login/login.component.spec.ts create mode 100644 WEB/src/app/account/modules/login/components/login/login.component.ts create mode 100644 WEB/src/app/account/modules/login/login-routing.module.ts create mode 100644 WEB/src/app/account/modules/login/login.module.ts create mode 100644 WEB/src/app/guards/auth.guard.spec.ts create mode 100644 WEB/src/app/guards/auth.guard.ts create mode 100644 WEB/src/app/services/access-right.service.spec.ts create mode 100644 WEB/src/app/services/access-right.service.ts create mode 100644 WEB/src/app/services/auth.service.spec.ts create mode 100644 WEB/src/app/services/auth.service.ts create mode 100644 WEB/src/app/services/role.definition.ts create mode 100644 WEB/src/app/services/roles.model.ts create mode 100644 WEB/src/app/services/user.model.ts diff --git a/WEB/package-lock.json b/WEB/package-lock.json index bd78330..13ac577 100644 --- a/WEB/package-lock.json +++ b/WEB/package-lock.json @@ -472,6 +472,11 @@ "tslib": "^1.9.0" } }, + "@angular/fire": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@angular/fire/-/fire-5.2.1.tgz", + "integrity": "sha512-pS4zWhLLANzMbYVIKNtebDQKhm9+KANUDvDV6DwKP24XHzkZdvazKe1HC6uXWlf7QmDxSPFleCSBkn0tnQQzdQ==" + }, "@angular/forms": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-8.2.0.tgz", @@ -686,6 +691,258 @@ } } }, + "@firebase/app": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.4.13.tgz", + "integrity": "sha512-LWiIKRoik1dFsY24k3pQ6NrQyWvSt+HzJKratUHfzqDBACdxcw7+9kwFMnS4MHGc/GGFVC42rHrI0PHeRe779w==", + "requires": { + "@firebase/app-types": "0.4.3", + "@firebase/logger": "0.1.21", + "@firebase/util": "0.2.24", + "dom-storage": "2.1.0", + "tslib": "1.10.0", + "xmlhttprequest": "1.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } + } + }, + "@firebase/app-types": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.4.3.tgz", + "integrity": "sha512-VU5c+ZjejvefLVH4cjiX3Hy1w9HYMv7TtZ1tF9ZmOqT4DSIU1a3VISWoo8///cGGffr5IirMO+Q/WZLI4p8VcA==" + }, + "@firebase/auth": { + "version": "0.11.7", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-0.11.7.tgz", + "integrity": "sha512-qloLTfUPja0ivRvyC0FnEMif6bYPZb9DsJsV83KiBWaYMSkCeNHuA34p73JvjmgHrT571t+zFpJ3OrBH+va4ow==", + "requires": { + "@firebase/auth-types": "0.7.2" + } + }, + "@firebase/auth-types": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.7.2.tgz", + "integrity": "sha512-xm3evp6671LoI+6M8Om3OhikabLf88Ivz1e7aR8uZjVBYptEYbF3seDIyHn/3wWdVYbp20WK4aWixKlRnHl+6Q==" + }, + "@firebase/database": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.4.11.tgz", + "integrity": "sha512-g6VcEiw1HqBbV31p0j61CleLKZQ2XEOqpv1MSuiH9YYMsbHI7uUaebj3dxIdLSdLMoWNpGYmlXva/AWkirAV8Q==", + "requires": { + "@firebase/database-types": "0.4.2", + "@firebase/logger": "0.1.21", + "@firebase/util": "0.2.24", + "faye-websocket": "0.11.3", + "tslib": "1.10.0" + }, + "dependencies": { + "faye-websocket": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", + "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } + } + }, + "@firebase/database-types": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.4.2.tgz", + "integrity": "sha512-rBF/Sp4S4zzVg+a6h0iEiXR2GdNRrvx2BR6IcvGHnSPF7XVpj9UuUWtZMJyO+vWP3zlIGDvlNRJ4qF01Y6KxGg==" + }, + "@firebase/firestore": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-1.4.8.tgz", + "integrity": "sha512-/Ult2LpbweinNnpqGrGiMw+EAaMEy6uA71DWN868oZoUmnn/+s/DCe2J0P+On2HATqvg5WggrQRa9I0in8fFag==", + "requires": { + "@firebase/firestore-types": "1.4.4", + "@firebase/logger": "0.1.21", + "@firebase/util": "0.2.24", + "@firebase/webchannel-wrapper": "0.2.23", + "@grpc/proto-loader": "^0.5.0", + "grpc": "1.22.2", + "tslib": "1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } + } + }, + "@firebase/firestore-types": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-1.4.4.tgz", + "integrity": "sha512-kFpmzkUKfzrXkcMad+TQlMs55dWNY0q1UxGICW82EneX3Yg6HN3Nx36kYfqH+SLBFUN1ZTikN07alMp0MA9p9g==" + }, + "@firebase/functions": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.4.14.tgz", + "integrity": "sha512-rWYWIp2NIRfNGREkSEhu9fD7WsqkUARnonn7+g+DOCxlf23AkwwDwp6q9cnSia7iJ9kmkiz4hyQVI0vB1QlV5A==", + "requires": { + "@firebase/functions-types": "0.3.8", + "@firebase/messaging-types": "0.3.2", + "isomorphic-fetch": "2.2.1", + "tslib": "1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } + } + }, + "@firebase/functions-types": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.3.8.tgz", + "integrity": "sha512-9hajHxA4UWVCGFmoL8PBYHpamE3JTNjObieMmnvZw3cMRTP2EwipMpzZi+GPbMlA/9swF9yHCY/XFAEkwbvdgQ==" + }, + "@firebase/installations": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.2.3.tgz", + "integrity": "sha512-HhHMn1xvyqBCvw8HmjZ5w856BQ0+xX4tKe/48k+dyKUzzSjwrFjILWTDV2GIHZcVyMHuSS3/bX9ehIBULB5yAA==", + "requires": { + "@firebase/installations-types": "0.1.2", + "@firebase/util": "0.2.24", + "idb": "3.0.2", + "tslib": "1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } + } + }, + "@firebase/installations-types": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.1.2.tgz", + "integrity": "sha512-fQaWIW8hyX1XUN7+FCSPjvM1agFjGidVuF4Sxi7aFwfyh5t+4fD2VpM4wCQbWmodnx4fZLvsuQd9mkxxU+lGYQ==" + }, + "@firebase/logger": { + "version": "0.1.21", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.1.21.tgz", + "integrity": "sha512-O4aIK1wkMpczqnDSwzDaEcQ8a5puVU4Bpt+16PfenicsBSrIR+gKq44crPM3nv/LURWtDpUVSYGoqhKPeodPAg==" + }, + "@firebase/messaging": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.4.7.tgz", + "integrity": "sha512-Kzx64ELqOhEniyKawyCmDiQo8tX+wiF7Jsk5kp7moh7090dOPb8p8snkq770UFwUZjhouVrl8tOKzD3SInVIFA==", + "requires": { + "@firebase/messaging-types": "0.3.2", + "@firebase/util": "0.2.24", + "tslib": "1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } + } + }, + "@firebase/messaging-types": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@firebase/messaging-types/-/messaging-types-0.3.2.tgz", + "integrity": "sha512-2qa2qNKqpalmtwaUV3+wQqfCm5myP/dViIBv+pXF8HinemIfO1IPQtr9pCNfsSYyus78qEhtfldnPWXxUH5v0w==" + }, + "@firebase/performance": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.2.14.tgz", + "integrity": "sha512-WNhJkVEq9q6OazUldzeRcESmGl0W2kw82CfUII/uPATdMvF5wXvda60BN0zwquRVSdLTt7qVRQA/8wLQYnX/Kw==", + "requires": { + "@firebase/installations": "0.2.3", + "@firebase/logger": "0.1.21", + "@firebase/performance-types": "0.0.3", + "@firebase/util": "0.2.24", + "tslib": "1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } + } + }, + "@firebase/performance-types": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.0.3.tgz", + "integrity": "sha512-RuC63nYJPJU65AsrNMc3fTRcRgHiyNcQLh9ufeKUT1mEsFgpxr167gMb+tpzNU4jsbvM6+c6nQAFdHpqcGkRlQ==" + }, + "@firebase/polyfill": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@firebase/polyfill/-/polyfill-0.3.18.tgz", + "integrity": "sha512-Erp0vuFYMS8BlQzuAWR6zf10rxDT4GHRGJypxoW7arU4J61KIb6CPmrO9tVtf/rVEZuUXsDO65etDEFA8elCYA==", + "requires": { + "core-js": "3.1.4", + "promise-polyfill": "8.1.3", + "whatwg-fetch": "2.0.4" + }, + "dependencies": { + "whatwg-fetch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", + "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" + } + } + }, + "@firebase/storage": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.3.8.tgz", + "integrity": "sha512-u/JHEkoIPKkRigHhcHcmHq6Ymu27Iyei6SqDFPm17vfC85jDetdg6aO9K+UxbtdDICa60P86UguqDHTMLVwKIg==", + "requires": { + "@firebase/storage-types": "0.3.3", + "@firebase/util": "0.2.24", + "tslib": "1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } + } + }, + "@firebase/storage-types": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.3.3.tgz", + "integrity": "sha512-fUp4kpbxwDiWs/aIBJqBvXgFHZvgoND2JA0gJYSEsXtWtVwfgzY/710plErgZDeQKopX5eOR1sHskZkQUy0U6w==" + }, + "@firebase/util": { + "version": "0.2.24", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.24.tgz", + "integrity": "sha512-XFBNxfkMajl2zSUdcCQ3H32IN9JSM7Dacv8RK72DKoFV8Zn8dx4iZvtx8RB/VTFpXfcl435A0RzXqkLfSSEK/A==", + "requires": { + "tslib": "1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + } + } + }, + "@firebase/webchannel-wrapper": { + "version": "0.2.23", + "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.2.23.tgz", + "integrity": "sha512-BJqOF51sPQjmRoX+WFMbZ5mhuy53JrFN0t1KY+HffcvDRb+82+vkFatKnwG3wTCKV183vJW5tGQIytb4T8pUBg==" + }, "@fortawesome/angular-fontawesome": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/@fortawesome/angular-fontawesome/-/angular-fontawesome-0.4.0.tgz", @@ -715,6 +972,15 @@ "@fortawesome/fontawesome-common-types": "^0.2.21" } }, + "@grpc/proto-loader": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.5.1.tgz", + "integrity": "sha512-3y0FhacYAwWvyXshH18eDkUI40wT/uGio7MAegzY8lO5+wVsc19+1A7T0pPptae4kl7bdITL+0cHpnAPmryBjQ==", + "requires": { + "lodash.camelcase": "^4.3.0", + "protobufjs": "^6.8.6" + } + }, "@ngtools/webpack": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-8.2.0.tgz", @@ -739,6 +1005,60 @@ } } }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, "@schematics/angular": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-8.2.0.tgz", @@ -814,6 +1134,11 @@ "@types/jasmine": "*" } }, + "@types/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.0.tgz", + "integrity": "sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q==" + }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", @@ -1169,8 +1494,7 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "ansi-styles": { "version": "3.2.1", @@ -1300,6 +1624,15 @@ "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", "dev": true }, + "ascli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ascli/-/ascli-1.0.1.tgz", + "integrity": "sha1-vPpZdKYvGOgcq660lzKrSoj5Brw=", + "requires": { + "colour": "~0.7.1", + "optjs": "~3.2.2" + } + }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -1580,8 +1913,7 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "base": { "version": "0.11.2", @@ -1769,7 +2101,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1970,6 +2301,21 @@ "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", "dev": true }, + "bytebuffer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz", + "integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=", + "requires": { + "long": "~3" + }, + "dependencies": { + "long": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", + "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" + } + } + }, "bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", @@ -2366,8 +2712,7 @@ "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "codelyzer": { "version": "5.1.0", @@ -2431,6 +2776,11 @@ "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", "dev": true }, + "colour": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/colour/-/colour-0.7.1.tgz", + "integrity": "sha1-nLFpkX7F0SwHNtPoaFdG3xyt93g=" + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -2503,8 +2853,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concat-stream": { "version": "1.6.2", @@ -2816,8 +3165,7 @@ "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, "decode-uri-component": { "version": "0.2.0", @@ -3090,6 +3438,11 @@ "void-elements": "^2.0.0" } }, + "dom-storage": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/dom-storage/-/dom-storage-2.1.0.tgz", + "integrity": "sha512-g6RpyWXzl0RR6OTElHKBl7nwnK87GUyZMYC7JWsB/IA73vpqK2K6LT39x4VepLxlSsWBFrPVLnsSR5Jyty0+2Q==" + }, "domain-browser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", @@ -3167,7 +3520,6 @@ "version": "0.1.12", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", - "dev": true, "requires": { "iconv-lite": "~0.4.13" } @@ -3777,6 +4129,25 @@ "locate-path": "^3.0.0" } }, + "firebase": { + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-6.3.4.tgz", + "integrity": "sha512-UvLCXApdrhYZkGl1N/4dPPFVa3zFd+K963guaP9ckQhagch66Hv1xLwL8urmlBAGk9UZECMAk8f7YcLD217HkA==", + "requires": { + "@firebase/app": "0.4.13", + "@firebase/app-types": "0.4.3", + "@firebase/auth": "0.11.7", + "@firebase/database": "0.4.11", + "@firebase/firestore": "1.4.8", + "@firebase/functions": "0.4.14", + "@firebase/installations": "0.2.3", + "@firebase/messaging": "0.4.7", + "@firebase/performance": "0.2.14", + "@firebase/polyfill": "0.3.18", + "@firebase/storage": "0.3.8", + "@firebase/util": "0.2.24" + } + }, "flatted": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", @@ -3917,8 +4288,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { "version": "1.2.9", @@ -4514,7 +4884,6 @@ "version": "7.1.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -4579,6 +4948,493 @@ "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", "dev": true }, + "grpc": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/grpc/-/grpc-1.22.2.tgz", + "integrity": "sha512-gaK59oAA5/mlOIn+hQO5JROPoAzsaGRpEMcrAayW5WGETS8QScpBoQ+XBxEWAAF0kbeGIELuGRCVEObKS1SLmw==", + "requires": { + "lodash.camelcase": "^4.3.0", + "lodash.clone": "^4.5.0", + "nan": "^2.13.2", + "node-pre-gyp": "^0.13.0", + "protobufjs": "^5.0.3" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + }, + "chownr": { + "version": "1.1.1", + "bundled": true + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true + }, + "fs-minipass": { + "version": "1.2.6", + "bundled": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true + }, + "iconv-lite": { + "version": "0.4.23", + "bundled": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "ini": { + "version": "1.3.5", + "bundled": true + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "requires": { + "invert-kv": "^1.0.0" + } + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.0", + "bundled": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "bundled": true + } + } + }, + "needle": { + "version": "2.4.0", + "bundled": true, + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "bundled": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "bundled": true + } + } + }, + "node-pre-gyp": { + "version": "0.13.0", + "bundled": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "requires": { + "lcid": "^1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true + }, + "process-nextick-args": { + "version": "2.0.1", + "bundled": true + }, + "protobufjs": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-5.0.3.tgz", + "integrity": "sha512-55Kcx1MhPZX0zTbVosMQEO5R6/rikNXd9b6RQK4KSPcrSIIwoXTtebIczUrXlwaSrbz4x8XUVThGPob1n8I4QA==", + "requires": { + "ascli": "~1", + "bytebuffer": "~5", + "glob": "^7.0.5", + "yargs": "^3.10.0" + } + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.1.4", + "bundled": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true + }, + "sax": { + "version": "1.2.4", + "bundled": true + }, + "semver": { + "version": "5.7.0", + "bundled": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true + }, + "signal-exit": { + "version": "3.0.1", + "bundled": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true + }, + "tar": { + "version": "4.4.10", + "bundled": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.5", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" + }, + "yallist": { + "version": "3.0.3", + "bundled": true + }, + "yargs": { + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", + "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", + "requires": { + "camelcase": "^2.0.1", + "cliui": "^3.0.3", + "decamelize": "^1.1.1", + "os-locale": "^1.4.0", + "string-width": "^1.0.1", + "window-size": "^0.1.4", + "y18n": "^3.2.0" + } + } + } + }, "handle-thing": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz", @@ -4789,8 +5645,7 @@ "http-parser-js": { "version": "0.4.10", "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz", - "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=", - "dev": true + "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=" }, "http-proxy": { "version": "1.17.0", @@ -4893,11 +5748,15 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } }, + "idb": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/idb/-/idb-3.0.2.tgz", + "integrity": "sha512-+FLa/0sTXqyux0o6C+i2lOR0VoS60LU/jzUo5xjfY6+7sEEgy4Gz1O7yFBXvjd7N0NyIGWIRg8DcQSLEG+VSPw==" + }, "ieee754": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", @@ -4998,7 +5857,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -5007,8 +5865,7 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "ini": { "version": "1.3.5", @@ -5255,7 +6112,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5346,8 +6202,7 @@ "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, "is-symbol": { "version": "1.0.2", @@ -5403,6 +6258,15 @@ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, + "isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "requires": { + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" + } + }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -5996,6 +6860,16 @@ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + }, + "lodash.clone": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", + "integrity": "sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y=" + }, "lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", @@ -6044,6 +6918,11 @@ "integrity": "sha512-LoEDv5pgpvWgPF4kNYuIp0qqSJVWak/dML0RY74xlzMZiT9w77teNAwKYKWBTYjlokMirg+o3jBwp+vlLrcfAA==", "dev": true }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -6311,7 +7190,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -6460,9 +7338,7 @@ "nan": { "version": "2.14.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", - "dev": true, - "optional": true + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" }, "nanomatch": { "version": "1.2.13", @@ -6506,6 +7382,15 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, "node-fetch-npm": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz", @@ -6681,8 +7566,7 @@ "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "oauth-sign": { "version": "0.9.0", @@ -6800,7 +7684,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1" } @@ -6858,6 +7741,11 @@ } } }, + "optjs": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/optjs/-/optjs-3.2.2.tgz", + "integrity": "sha1-aabOicRCpEQDFBrS+bNwvVu29O4=" + }, "original": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", @@ -7137,8 +8025,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { "version": "1.0.2", @@ -7371,6 +8258,11 @@ "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", "dev": true }, + "promise-polyfill": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.1.3.tgz", + "integrity": "sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g==" + }, "promise-retry": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", @@ -7389,6 +8281,33 @@ } } }, + "protobufjs": { + "version": "6.8.8", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz", + "integrity": "sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.0", + "@types/node": "^10.1.0", + "long": "^4.0.0" + }, + "dependencies": { + "@types/node": { + "version": "10.14.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.15.tgz", + "integrity": "sha512-CBR5avlLcu0YCILJiDIXeU2pTw7UK/NIxfC63m7d7CVamho1qDEzXKkOtEauQRPMy6MI8mLozth+JJkas7HY6g==" + } + } + }, "protoduck": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz", @@ -8019,8 +8938,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safe-regex": { "version": "1.1.0", @@ -8034,8 +8952,7 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sass": { "version": "1.22.7", @@ -8968,7 +9885,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -8988,7 +9904,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, "requires": { "ansi-regex": "^2.0.0" } @@ -9967,7 +10882,6 @@ "version": "0.7.3", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz", "integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==", - "dev": true, "requires": { "http-parser-js": ">=0.4.0 <0.4.11", "safe-buffer": ">=5.1.0", @@ -9977,8 +10891,12 @@ "websocket-extensions": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", - "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", - "dev": true + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==" + }, + "whatwg-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", + "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==" }, "when": { "version": "3.6.4", @@ -10001,6 +10919,11 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "window-size": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", + "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=" + }, "wordwrap": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", @@ -10029,7 +10952,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, "requires": { "string-width": "^1.0.1", "strip-ansi": "^3.0.1" @@ -10038,8 +10960,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "ws": { "version": "3.3.3", @@ -10076,6 +10997,11 @@ "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", "dev": true }, + "xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", + "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=" + }, "xmlhttprequest-ssl": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", diff --git a/WEB/package.json b/WEB/package.json index f91a3e9..e999491 100644 --- a/WEB/package.json +++ b/WEB/package.json @@ -17,6 +17,7 @@ "@angular/common": "~8.2.0", "@angular/compiler": "~8.2.0", "@angular/core": "~8.2.0", + "@angular/fire": "^5.2.1", "@angular/forms": "~8.2.0", "@angular/http": "~7.2.15", "@angular/material": "^8.1.2", @@ -28,6 +29,7 @@ "@fortawesome/free-solid-svg-icons": "^5.10.1", "angular2-uuid": "^1.1.1", "core-js": "^3.1.4", + "firebase": "^6.3.4", "ng2-file-upload": "^1.3.0", "odata-v4-ng": "^1.2.1", "rxjs": "^6.5.2", diff --git a/WEB/src/app/account/account-routing.module.ts b/WEB/src/app/account/account-routing.module.ts new file mode 100644 index 0000000..c21a21d --- /dev/null +++ b/WEB/src/app/account/account-routing.module.ts @@ -0,0 +1,17 @@ +import {NgModule} from '@angular/core'; +import {RouterModule, Routes} from '@angular/router'; + +const routes: Routes = [ + { + path: 'login', + loadChildren: () => import('./modules/login/login.module').then(_ => _.LoginModule) + } + ] +; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class AccountRoutingModule { +} diff --git a/WEB/src/app/account/account.module.ts b/WEB/src/app/account/account.module.ts new file mode 100644 index 0000000..97b7bf8 --- /dev/null +++ b/WEB/src/app/account/account.module.ts @@ -0,0 +1,14 @@ +import {NgModule} from '@angular/core'; +import {CommonModule} from '@angular/common'; + +import {AccountRoutingModule} from './account-routing.module'; + + +@NgModule({ + imports: [ + CommonModule, + AccountRoutingModule, + ] +}) +export class AccountModule { +} diff --git a/WEB/src/app/account/modules/login/components/login/login.component.html b/WEB/src/app/account/modules/login/components/login/login.component.html new file mode 100644 index 0000000..731a3a1 --- /dev/null +++ b/WEB/src/app/account/modules/login/components/login/login.component.html @@ -0,0 +1,21 @@ + + + Login + + + +
+ + + + + + + +
+
+ + + + +
diff --git a/WEB/src/app/account/modules/login/components/login/login.component.less b/WEB/src/app/account/modules/login/components/login/login.component.less new file mode 100644 index 0000000..a5c2526 --- /dev/null +++ b/WEB/src/app/account/modules/login/components/login/login.component.less @@ -0,0 +1,5 @@ +form { + display: flex; + flex-direction: column; + padding: 20px 0; +} diff --git a/WEB/src/app/account/modules/login/components/login/login.component.spec.ts b/WEB/src/app/account/modules/login/components/login/login.component.spec.ts new file mode 100644 index 0000000..cdf157d --- /dev/null +++ b/WEB/src/app/account/modules/login/components/login/login.component.spec.ts @@ -0,0 +1,25 @@ +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; + +import {LoginComponent} from './login.component'; + +describe('LoginComponent', () => { + let component: LoginComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [LoginComponent] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LoginComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/WEB/src/app/account/modules/login/components/login/login.component.ts b/WEB/src/app/account/modules/login/components/login/login.component.ts new file mode 100644 index 0000000..e64d57d --- /dev/null +++ b/WEB/src/app/account/modules/login/components/login/login.component.ts @@ -0,0 +1,41 @@ +import {Component, OnInit} from '@angular/core'; +import {AuthService} from '../../../../../services/auth.service'; +import {FormControl} from '@angular/forms'; +import {ActivatedRoute, Router} from '@angular/router'; + +@Component({ + selector: 'app-login', + templateUrl: './login.component.html', + styleUrls: ['./login.component.less'] +}) +export class LoginComponent implements OnInit { + public user = new FormControl(); + public pass = new FormControl(); + public loginError = false; + + private redirect: string = null; + + constructor( + private authService: AuthService, + private router: Router, + activatedRoute: ActivatedRoute + ) { + activatedRoute.queryParams.subscribe(_ => this.redirect = _.redirect); + } + + ngOnInit() { + this.loginError = false; + } + + public onLogin(): void { + this.authService.login$(this.user.value, this.pass.value).subscribe(_ => { + if (_ === null) { + this.loginError = true; + } else { + if (this.redirect) { + this.router.navigateByUrl('/' + this.redirect); + } + } + }); + } +} diff --git a/WEB/src/app/account/modules/login/login-routing.module.ts b/WEB/src/app/account/modules/login/login-routing.module.ts new file mode 100644 index 0000000..99c4042 --- /dev/null +++ b/WEB/src/app/account/modules/login/login-routing.module.ts @@ -0,0 +1,19 @@ +import {NgModule} from '@angular/core'; +import {RouterModule, Routes} from '@angular/router'; +import {LoginComponent} from './components/login/login.component'; + + +const routes: Routes = [ + { + path: '', + component: LoginComponent, + pathMatch: 'full' + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class LoginRoutingModule { +} diff --git a/WEB/src/app/account/modules/login/login.module.ts b/WEB/src/app/account/modules/login/login.module.ts new file mode 100644 index 0000000..8689770 --- /dev/null +++ b/WEB/src/app/account/modules/login/login.module.ts @@ -0,0 +1,24 @@ +import {NgModule} from '@angular/core'; +import {CommonModule} from '@angular/common'; + +import {LoginRoutingModule} from './login-routing.module'; +import {LoginComponent} from './components/login/login.component'; +import {MatButtonModule, MatCardModule, MatInputModule} from '@angular/material'; +import {FormsModule, ReactiveFormsModule} from '@angular/forms'; + + +@NgModule({ + declarations: [LoginComponent], + imports: [ + CommonModule, + LoginRoutingModule, + FormsModule, + ReactiveFormsModule, + + MatCardModule, + MatInputModule, + MatButtonModule + ] +}) +export class LoginModule { +} diff --git a/WEB/src/app/app-routing.module.ts b/WEB/src/app/app-routing.module.ts index 334302e..6bee292 100644 --- a/WEB/src/app/app-routing.module.ts +++ b/WEB/src/app/app-routing.module.ts @@ -1,5 +1,6 @@ import {NgModule} from '@angular/core'; import {RouterModule, Routes} from '@angular/router'; +import {AuthGuard} from './guards/auth.guard'; const routes: Routes = [ @@ -10,7 +11,12 @@ const routes: Routes = [ }, { path: 'songs', - loadChildren: () => import('./songs/songs.module').then(_ => _.SongsModule) + loadChildren: () => import('./songs/songs.module').then(_ => _.SongsModule), + canActivate: [AuthGuard], + }, + { + path: 'account', + loadChildren: () => import('./account/account.module').then(_ => _.AccountModule) } ]; diff --git a/WEB/src/app/app.module.ts b/WEB/src/app/app.module.ts index 94a8bd3..d95142b 100644 --- a/WEB/src/app/app.module.ts +++ b/WEB/src/app/app.module.ts @@ -19,6 +19,11 @@ import {MatSelectModule} from '@angular/material/select'; import {MatTooltipModule} from '@angular/material/tooltip'; import {MatProgressBarModule} from '@angular/material/progress-bar'; import {FileUploadModule} from 'ng2-file-upload'; +import {AngularFireModule} from '@angular/fire'; +import {AngularFireAuthModule} from '@angular/fire/auth'; +import {AngularFirestoreModule} from '@angular/fire/firestore'; +import {environment} from '../environments/environment'; +import {AngularFireDatabaseModule} from '@angular/fire/database'; @NgModule({ declarations: [ @@ -45,6 +50,11 @@ import {FileUploadModule} from 'ng2-file-upload'; FontAwesomeModule, FileUploadModule, AppRoutingModule, + + AngularFireModule.initializeApp(environment.firebase), + AngularFirestoreModule, // imports firebase/firestore, only needed for database features + AngularFireAuthModule, // imports firebase/auth, only needed for auth features + AngularFireDatabaseModule, ], providers: [], bootstrap: [AppComponent] diff --git a/WEB/src/app/guards/auth.guard.spec.ts b/WEB/src/app/guards/auth.guard.spec.ts new file mode 100644 index 0000000..66586d9 --- /dev/null +++ b/WEB/src/app/guards/auth.guard.spec.ts @@ -0,0 +1,15 @@ +import {inject, TestBed} from '@angular/core/testing'; + +import {AuthGuard} from './auth.guard'; + +describe('AuthGuard', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [AuthGuard] + }); + }); + + it('should ...', inject([AuthGuard], (guard: AuthGuard) => { + expect(guard).toBeTruthy(); + })); +}); diff --git a/WEB/src/app/guards/auth.guard.ts b/WEB/src/app/guards/auth.guard.ts new file mode 100644 index 0000000..11ac400 --- /dev/null +++ b/WEB/src/app/guards/auth.guard.ts @@ -0,0 +1,27 @@ +import {Injectable} from '@angular/core'; +import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree} from '@angular/router'; +import {AuthService} from '../services/auth.service'; +import {Observable} from 'rxjs'; +import {map} from 'rxjs/operators'; +import {Role} from '../services/roles.model'; + +@Injectable({ + providedIn: 'root' +}) +export class AuthGuard implements CanActivate { + + constructor(private authService: AuthService, + private router: Router + ) { + } + + canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + return this.authService.userMay$(Role.reader).pipe( + map(_ => { + return _ + ? true + : this.router.createUrlTree(['/account/login'], {queryParams: {redirect: route.url}}); + }) + ); + } +} diff --git a/WEB/src/app/services/access-right.service.spec.ts b/WEB/src/app/services/access-right.service.spec.ts new file mode 100644 index 0000000..934a013 --- /dev/null +++ b/WEB/src/app/services/access-right.service.spec.ts @@ -0,0 +1,41 @@ +import {async, TestBed} from '@angular/core/testing'; + +import {AccessRightService} from './access-right.service'; +import {AngularFirestore} from '@angular/fire/firestore'; +import {of} from 'rxjs'; +import {Role} from './roles.model'; + +describe('AccessRightService', () => { + const mockAngularFirestore = { + collection: () => ({ + doc: () => ({ + valueChanges: () => of({ + role: 'reader' + }) + }) + }) + }; + + beforeEach(() => TestBed.configureTestingModule({ + providers: [ + {provide: AngularFirestore, useValue: mockAngularFirestore} + ] + })); + + it('should be created', () => { + const service: AccessRightService = TestBed.get(AccessRightService); + expect(service).toBeTruthy(); + }); + + it('should get user', async(() => { + const service: AccessRightService = TestBed.get(AccessRightService); + service.getUserInfo('userid').subscribe(_ => { + expect(_).toEqual({ + user: 'userid', + role: Role.reader + }); + }); + })); + + +}); diff --git a/WEB/src/app/services/access-right.service.ts b/WEB/src/app/services/access-right.service.ts new file mode 100644 index 0000000..1d47d0d --- /dev/null +++ b/WEB/src/app/services/access-right.service.ts @@ -0,0 +1,43 @@ +import {Injectable} from '@angular/core'; +import {AngularFirestore} from '@angular/fire/firestore'; +import {map} from 'rxjs/operators'; +import {User, UserDB} from './user.model'; +import {Observable} from 'rxjs'; +import {Role} from './roles.model'; +import {RoleDefinitions} from './role.definition'; + +@Injectable({ + providedIn: 'root' +}) +export class AccessRightService { + + constructor( + private angularFirestore: AngularFirestore + ) { + } + + public getUserInfo(userId: string): Observable { + if (userId === null) { + return null; + } + + const user$ = this.angularFirestore + .collection('/user') + .doc(userId) + .valueChanges() + .pipe + (map(user => ({ + user: userId, + role: user.role + }))); + + return user$; + } + + public userMay(role: Role, requestedRole: Role): boolean { + const allowedRoles = RoleDefinitions.filter(_ => _.role === requestedRole)[0].when; + const isAllowed = allowedRoles.indexOf(role) !== -1; + + return isAllowed; + } +} diff --git a/WEB/src/app/services/auth.service.spec.ts b/WEB/src/app/services/auth.service.spec.ts new file mode 100644 index 0000000..e5cb5fc --- /dev/null +++ b/WEB/src/app/services/auth.service.spec.ts @@ -0,0 +1,47 @@ +import {fakeAsync, TestBed, tick} from '@angular/core/testing'; + +import {AuthService} from './auth.service'; +import {of} from 'rxjs'; +import {Role} from './roles.model'; +import {AccessRightService} from './access-right.service'; +import {AngularFireAuth} from '@angular/fire/auth'; + +describe('AuthService', () => { + const mockAccessRightService = { + getUserInfo: () => of({ + user: 'userid', + role: Role.reader + }) + }; + const mockAngularFireAuth = { + auth: { + signInWithEmailAndPassword: Promise.resolve({user: {uid: 'userid'}}) + } + }; + beforeEach(() => TestBed.configureTestingModule({ + providers: [ + {provide: AccessRightService, useValue: mockAccessRightService}, + {provide: AngularFireAuth, useValue: mockAngularFireAuth}, + ] + })); + + it('should be created', () => { + const service: AuthService = TestBed.get(AuthService); + expect(service).toBeTruthy(); + }); + + it('should be created', fakeAsync(() => { + const service: AuthService = TestBed.get(AuthService); + const authSpy = spyOn(TestBed.get(AngularFireAuth).auth, 'signInWithEmailAndPassword'); + const accessSpy = spyOn(TestBed.get(AccessRightService), 'getUserInfo'); + service.login$('user', 'pass'); + + expect(authSpy).toHaveBeenCalledWith('user', 'pass'); + tick(); + expect(accessSpy).toHaveBeenCalledWith('userid'); + tick(); + expect(service.user.user).toBe('userid'); + expect(service.user.user).toBe(Role.reader); + + })); +}); diff --git a/WEB/src/app/services/auth.service.ts b/WEB/src/app/services/auth.service.ts new file mode 100644 index 0000000..35cf93d --- /dev/null +++ b/WEB/src/app/services/auth.service.ts @@ -0,0 +1,64 @@ +import {Injectable} from '@angular/core'; +import {AngularFireAuth} from '@angular/fire/auth'; +import {from, Observable, of, OperatorFunction} from 'rxjs'; +import {AccessRightService} from './access-right.service'; +import {catchError, map, switchMap, tap} from 'rxjs/operators'; +import {User} from './user.model'; +import {Role} from './roles.model'; + +@Injectable({ + providedIn: 'root' +}) +export class AuthService { + private _user: User = null; + + constructor( + private angularFireAuth: AngularFireAuth, + private accessRightService: AccessRightService + ) { + angularFireAuth.authState.subscribe(_ => console.log(_)); + } + + public login$(user: string, pass: string): Observable { + const authPromise = this.angularFireAuth.auth.signInWithEmailAndPassword(user, pass); + const auth$ = from(authPromise).pipe( + map(_ => _.user.uid), + this.processLogin() + ); + + return auth$; + } + + public getUser$(): Observable { + if (this._user) { + return of(this._user); + } + + return this.angularFireAuth.authState.pipe( + map(_ => _ ? _.uid : null), + this.processLogin() + ); + } + + public userMay$(requestedRole: Role): Observable { + const allowed$ = this.getUser$().pipe( + map(_ => _ ? this.accessRightService.userMay(_.role, requestedRole) : false) + ); + + return allowed$; + } + + private processLogin(): OperatorFunction { + const self = this; + return function (source$: Observable): Observable { + return source$.pipe( + switchMap(_ => self.accessRightService.getUserInfo(_)), + tap((_ => self._user = _)), + catchError(_ => { + self._user = null; + return of(null); + }) + ); + }; + } +} diff --git a/WEB/src/app/services/role.definition.ts b/WEB/src/app/services/role.definition.ts new file mode 100644 index 0000000..79e661f --- /dev/null +++ b/WEB/src/app/services/role.definition.ts @@ -0,0 +1,7 @@ +import {Role} from './roles.model'; + +export const RoleDefinitions = [ + {role: Role.reader, when: [Role.admin, Role.writer, Role.reader]}, + {role: Role.writer, when: [Role.admin, Role.writer]}, + {role: Role.admin, when: [Role.admin]}, +]; diff --git a/WEB/src/app/services/roles.model.ts b/WEB/src/app/services/roles.model.ts new file mode 100644 index 0000000..4070146 --- /dev/null +++ b/WEB/src/app/services/roles.model.ts @@ -0,0 +1,5 @@ +export enum Role { + admin = 'admin', + reader = 'reader', + writer = 'writer' +} diff --git a/WEB/src/app/services/user.model.ts b/WEB/src/app/services/user.model.ts new file mode 100644 index 0000000..65b4d2a --- /dev/null +++ b/WEB/src/app/services/user.model.ts @@ -0,0 +1,10 @@ +import {Role} from './roles.model'; + +export interface User { + user: string; + role: Role; +} + +export interface UserDB { + role: Role; +} diff --git a/WEB/src/app/songs/components/songs/table/table.component.less b/WEB/src/app/songs/components/songs/table/table.component.less index 5b92298..1764daf 100644 --- a/WEB/src/app/songs/components/songs/table/table.component.less +++ b/WEB/src/app/songs/components/songs/table/table.component.less @@ -1,24 +1,4 @@ -table { - border-radius: 8px; - background: #fffe; - tr.selected { - background-color: #0002; - } - - tr:hover { - cursor: pointer; - background-color: #0001; - - td { - color: #ff9900; - } - } - - td.mat-cell { - padding: 0 5px; - } -} .table-container { overflow: auto; diff --git a/WEB/src/environments/environment.ts b/WEB/src/environments/environment.ts index 1a0052d..03001be 100644 --- a/WEB/src/environments/environment.ts +++ b/WEB/src/environments/environment.ts @@ -4,7 +4,16 @@ export const environment = { production: false, - api: 'http://test.benjamin-ifland.de' + api: 'http://test.benjamin-ifland.de', + firebase: { + apiKey: 'AIzaSyBcIa6m8F7fT4gRLTx2zcBufUEE81gWVFg', + authDomain: 'worshipgenerator.firebaseapp.com', + databaseURL: 'https://worshipgenerator.firebaseio.com', + projectId: 'worshipgenerator', + storageBucket: 'worshipgenerator.appspot.com', + messagingSenderId: '317378238562', + appId: '1:317378238562:web:552ca27bc5e9086e' + } }; /* diff --git a/WEB/src/styles.less b/WEB/src/styles.less index 114e428..32c6940 100644 --- a/WEB/src/styles.less +++ b/WEB/src/styles.less @@ -2,7 +2,14 @@ @import "~@angular/material/prebuilt-themes/indigo-pink.css"; html { - background-image: url(https://images.unsplash.com/photo-1476136236990-838240be4859?ixlib=rb-1.2.1&auto=format&fit=crop&w=2167&q=80); + background: #2c3e50; /* fallback for old browsers */ + background: -webkit-linear-gradient(to top, #2c3e50, #3498db); /* Chrome 10-25, Safari 5.1-6 */ + background: linear-gradient(to top, #2c3e50, #3498db); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */ + height: 100vh; +} + +.card-3 { + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23); } body { @@ -14,53 +21,28 @@ body { } .page-container { - padding: 10px; - box-sizing: border-box; + .card-3; + margin: 10px; overflow: hidden; border-radius: 8px; - .mat-table tbody { + table.mat-table thead, + table.mat-table tbody { background: none; } - th.mat-header-cell:first-of-type { - border-top-left-radius: 8px; - } - - th.mat-header-cell:last-of-type { - border-top-right-radius: 8px; - } - - .mat-table thead { - border-top-right-radius: 8px; - border-top-left-radius: 8px; - } - &.pinned { padding: 0; max-width: 300px; - border-radius: 0; - - th.mat-header-cell:first-of-type { - border-top-left-radius: 0; - } - - th.mat-header-cell:last-of-type { - border-top-right-radius: 0; - } - - .mat-table thead { - border-top-right-radius: 0; - border-top-left-radius: 0; - } } } .mat-card { + .card-3; width: 600px; border-radius: 8px; - background: #fffd; + background: #fffa; margin: 10px; box-sizing: border-box; } @@ -92,7 +74,7 @@ body { padding: 0; } - table { + table.mat-table { width: 100%; background: none; box-shadow: none; @@ -105,4 +87,35 @@ body { } } + .mat-paginator { + background: #fffa; + } + + table.mat-table { + background: #fffa; + + tr.selected { + background-color: #0002; + } + + tr:hover { + cursor: pointer; + background-color: #0001; + + td { + color: #ff9900; + } + } + + tr:focus { + outline: none; + } + + td.mat-cell { + padding: 0 5px; + } + + + } + } diff --git a/WEB/tslint.json b/WEB/tslint.json index 6ddb6b2..64559a9 100644 --- a/WEB/tslint.json +++ b/WEB/tslint.json @@ -10,7 +10,6 @@ true, "check-space" ], - "curly": true, "deprecation": { "severity": "warn" },