mirror of
https://github.com/hcengineering/platform.git
synced 2025-01-03 17:05:16 +03:00
initial account
contribution
Signed-off-by: Andrey Platov <andrey@hardcoreeng.com>
This commit is contained in:
parent
978ab09afb
commit
6011a75e05
@ -3,6 +3,7 @@ lockfileVersion: 5.3
|
||||
specifiers:
|
||||
'@elastic/elasticsearch': ^7.14.0
|
||||
'@microsoft/api-extractor': ^7.18.4
|
||||
'@rush-temp/account': file:./projects/account.tgz
|
||||
'@rush-temp/chunter': file:./projects/chunter.tgz
|
||||
'@rush-temp/chunter-assets': file:./projects/chunter-assets.tgz
|
||||
'@rush-temp/chunter-resources': file:./projects/chunter-resources.tgz
|
||||
@ -72,6 +73,7 @@ specifiers:
|
||||
'@tiptap/extension-typography': ~2.0.0-beta.13
|
||||
'@tiptap/starter-kit': ~2.0.0-beta.89
|
||||
'@types/cors': ^2.8.12
|
||||
'@types/deep-equal': ^1.0.1
|
||||
'@types/express': ^4.17.13
|
||||
'@types/express-fileupload': ^1.1.7
|
||||
'@types/heft-jest': ^1.0.2
|
||||
@ -99,7 +101,6 @@ specifiers:
|
||||
intl-messageformat: ^9.7.1
|
||||
mini-css-extract-plugin: ^2.2.0
|
||||
minio: ^7.0.19
|
||||
mongodb: ^4.1.0
|
||||
node-html-parser: ^4.1.3
|
||||
postcss: ^8.3.4
|
||||
postcss-load-config: ^3.1.0
|
||||
@ -122,6 +123,7 @@ specifiers:
|
||||
dependencies:
|
||||
'@elastic/elasticsearch': 7.14.0
|
||||
'@microsoft/api-extractor': 7.18.4
|
||||
'@rush-temp/account': file:projects/account.tgz_6c259fadfeb3a4b20890aefe87070b8b
|
||||
'@rush-temp/chunter': file:projects/chunter.tgz_6c259fadfeb3a4b20890aefe87070b8b
|
||||
'@rush-temp/chunter-assets': file:projects/chunter-assets.tgz
|
||||
'@rush-temp/chunter-resources': file:projects/chunter-resources.tgz_c38cf1a7a413db8918b0b4754c21e4c5
|
||||
@ -191,6 +193,7 @@ dependencies:
|
||||
'@tiptap/extension-typography': 2.0.0-beta.13_@tiptap+core@2.0.0-beta.93
|
||||
'@tiptap/starter-kit': 2.0.0-beta.89
|
||||
'@types/cors': 2.8.12
|
||||
'@types/deep-equal': 1.0.1
|
||||
'@types/express': 4.17.13
|
||||
'@types/express-fileupload': 1.1.7
|
||||
'@types/heft-jest': 1.0.2
|
||||
@ -218,7 +221,6 @@ dependencies:
|
||||
intl-messageformat: 9.8.1
|
||||
mini-css-extract-plugin: 2.2.0_webpack@5.48.0
|
||||
minio: 7.0.19
|
||||
mongodb: 4.1.1
|
||||
node-html-parser: 4.1.3
|
||||
postcss: 8.3.6
|
||||
postcss-load-config: 3.1.0
|
||||
@ -1670,7 +1672,7 @@ packages:
|
||||
/@types/whatwg-url/8.2.1:
|
||||
resolution: {integrity: sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ==}
|
||||
dependencies:
|
||||
'@types/node': 16.7.1
|
||||
'@types/node': 16.7.5
|
||||
'@types/webidl-conversions': 6.1.1
|
||||
dev: false
|
||||
|
||||
@ -9090,6 +9092,26 @@ packages:
|
||||
commander: 2.20.3
|
||||
dev: false
|
||||
|
||||
file:projects/account.tgz_6c259fadfeb3a4b20890aefe87070b8b:
|
||||
resolution: {integrity: sha512-jykJZHqGILUDDIrPnSs2RQYlkU5YgPheSAJaxztshirE23ZgdqZRUb9VgqfHIhIRm6etoo0KliQCAurKoS6/kw==, tarball: file:projects/account.tgz}
|
||||
id: file:projects/account.tgz
|
||||
name: '@rush-temp/account'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
'@types/heft-jest': 1.0.2
|
||||
'@typescript-eslint/eslint-plugin': 4.28.5_a8e83fcad666e1ba86be4b2e27a20aea
|
||||
eslint: 7.32.0
|
||||
eslint-plugin-import: 2.23.4_eslint@7.32.0
|
||||
eslint-plugin-node: 11.1.0_eslint@7.32.0
|
||||
eslint-plugin-promise: 4.3.1
|
||||
jwt-simple: 0.5.6
|
||||
mongodb: 4.1.1
|
||||
transitivePeerDependencies:
|
||||
- '@typescript-eslint/parser'
|
||||
- supports-color
|
||||
- typescript
|
||||
dev: false
|
||||
|
||||
file:projects/chunter-assets.tgz:
|
||||
resolution: {integrity: sha512-kMTEO1cP8cmeoA2tImDBtT2SXfjo4AW0MWEbzFvzhZkLZaMmJGtl5ZHclKn/Wwg/LBA1zDc21fKlpeahmuNS4A==, tarball: file:projects/chunter-assets.tgz}
|
||||
name: '@rush-temp/chunter-assets'
|
||||
@ -9834,7 +9856,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/recruit-resources.tgz_c38cf1a7a413db8918b0b4754c21e4c5:
|
||||
resolution: {integrity: sha512-ZTxU5DPTttq85I1jEwAbJ+RCuL1t9sFCQ0gJo/ax4VzfEN6M/6inkXZ5HQF812UD9vGcYlRF2+zqfnuoAfZxmA==, tarball: file:projects/recruit-resources.tgz}
|
||||
resolution: {integrity: sha512-vsSwhXuC8vyxhYf1emb/0aTu4FCsXtuz2MPwgUskCveuUBtF2ROAqzo9Qy9HXZNHX1eOeDWVDcjbFmRuU4Peqg==, tarball: file:projects/recruit-resources.tgz}
|
||||
id: file:projects/recruit-resources.tgz
|
||||
name: '@rush-temp/recruit-resources'
|
||||
version: 0.0.0
|
||||
|
@ -746,5 +746,10 @@
|
||||
"projectFolder": "server/front",
|
||||
"shouldPublish": true
|
||||
},
|
||||
{
|
||||
"packageName": "@anticrm/account",
|
||||
"projectFolder": "server/account",
|
||||
"shouldPublish": true
|
||||
},
|
||||
]
|
||||
}
|
||||
|
6
server/account/.eslintrc.js
Normal file
6
server/account/.eslintrc.js
Normal file
@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
extends: ['./node_modules/@anticrm/platform-rig/profiles/default/config/eslint.config.json'],
|
||||
parserOptions: {
|
||||
project: './tsconfig.json'
|
||||
}
|
||||
}
|
4
server/account/.npmignore
Normal file
4
server/account/.npmignore
Normal file
@ -0,0 +1,4 @@
|
||||
*
|
||||
!/lib/**
|
||||
!CHANGELOG.md
|
||||
/lib/**/__tests__/
|
18
server/account/config/rig.json
Normal file
18
server/account/config/rig.json
Normal file
@ -0,0 +1,18 @@
|
||||
// The "rig.json" file directs tools to look for their config files in an external package.
|
||||
// Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||
|
||||
/**
|
||||
* (Required) The name of the rig package to inherit from.
|
||||
* It should be an NPM package name with the "-rig" suffix.
|
||||
*/
|
||||
"rigPackageName": "@anticrm/platform-rig"
|
||||
|
||||
/**
|
||||
* (Optional) Selects a config profile from the rig package. The name must consist of
|
||||
* lowercase alphanumeric words separated by hyphens, for example "sample-profile".
|
||||
* If omitted, then the "default" profile will be used."
|
||||
*/
|
||||
// "rigProfile": "your-profile-name"
|
||||
}
|
25
server/account/package.json
Normal file
25
server/account/package.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "@anticrm/account",
|
||||
"version": "0.6.0",
|
||||
"main": "lib/index.js",
|
||||
"author": "Anticrm Platform Contributors",
|
||||
"license": "EPL-2.0",
|
||||
"scripts": {
|
||||
"build": "heft build",
|
||||
"lint:fix": "eslint --fix src"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@anticrm/platform-rig":"~0.6.0",
|
||||
"@types/heft-jest":"^1.0.2",
|
||||
"@typescript-eslint/eslint-plugin":"4",
|
||||
"eslint-plugin-import":"2",
|
||||
"eslint-plugin-promise":"4",
|
||||
"eslint-plugin-node":"11",
|
||||
"eslint":"^7.32.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"mongodb":"^4.1.1",
|
||||
"@anticrm/platform":"~0.6.5",
|
||||
"jwt-simple":"~0.5.6"
|
||||
}
|
||||
}
|
140
server/account/src/index.ts
Normal file
140
server/account/src/index.ts
Normal file
@ -0,0 +1,140 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { Plugin, StatusCode } from '@anticrm/platform'
|
||||
import { PlatformError, Severity, Status, plugin } from '@anticrm/platform'
|
||||
import { Binary, Db, ObjectId } from 'mongodb'
|
||||
import { pbkdf2Sync } from 'crypto'
|
||||
import { encode } from 'jwt-simple'
|
||||
|
||||
const WORKSPACE_COLLECTION = 'workspace'
|
||||
const ACCOUNT_COLLECTION = 'account'
|
||||
|
||||
const endpoint = 'wss://transactor.hc.engineering/'
|
||||
const secret = 'secret'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export const accountId = 'account' as Plugin
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
const accountPlugin = plugin(accountId, {
|
||||
status: {
|
||||
AccountNotFound: '' as StatusCode<{account: string}>,
|
||||
InvalidPassword: '' as StatusCode<{account: string}>,
|
||||
Forbidden: '' as StatusCode
|
||||
}
|
||||
})
|
||||
|
||||
interface Account {
|
||||
_id: ObjectId
|
||||
email: string
|
||||
hash: Binary
|
||||
salt: Binary
|
||||
workspaces: ObjectId[]
|
||||
}
|
||||
|
||||
interface Workspace {
|
||||
_id: ObjectId
|
||||
workspace: string
|
||||
organisation: string
|
||||
accounts: ObjectId[]
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface LoginInfo {
|
||||
email: string
|
||||
token: string
|
||||
endpoint: string
|
||||
}
|
||||
|
||||
type AccountInfo = Omit<Account, 'hash' | 'salt'>
|
||||
|
||||
function hashWithSalt (password: string, salt: Buffer): Buffer {
|
||||
return pbkdf2Sync(password, salt, 1000, 32, 'sha256')
|
||||
}
|
||||
|
||||
function verifyPassword (password: string, hash: Buffer, salt: Buffer): boolean {
|
||||
return Buffer.compare(hash, hashWithSalt(password, salt)) === 0
|
||||
}
|
||||
|
||||
async function getAccount (db: Db, email: string): Promise<Account | null> {
|
||||
return await db.collection(ACCOUNT_COLLECTION).findOne<Account>({ email })
|
||||
}
|
||||
|
||||
async function getWorkspace (db: Db, workspace: string): Promise<Workspace | null> {
|
||||
return await db.collection(WORKSPACE_COLLECTION).findOne<Workspace>({
|
||||
workspace
|
||||
})
|
||||
}
|
||||
|
||||
function toAccountInfo (account: Account): AccountInfo {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { hash, salt, ...result } = account
|
||||
return result
|
||||
}
|
||||
|
||||
async function getAccountInfo (db: Db, email: string, password: string): Promise<AccountInfo> {
|
||||
const account = await getAccount(db, email)
|
||||
if (account === null) {
|
||||
throw new PlatformError(new Status(Severity.ERROR, accountPlugin.status.AccountNotFound, { account: email }))
|
||||
}
|
||||
if (!verifyPassword(password, account.hash.buffer, account.salt.buffer)) {
|
||||
throw new PlatformError(new Status(Severity.ERROR, accountPlugin.status.InvalidPassword, { account: email }))
|
||||
}
|
||||
return toAccountInfo(account)
|
||||
}
|
||||
|
||||
function generateToken (email: string, workspace: string): string {
|
||||
return encode({ email, workspace }, secret)
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param db -
|
||||
* @param email -
|
||||
* @param password -
|
||||
* @param workspace -
|
||||
* @returns
|
||||
*/
|
||||
export async function login (db: Db, email: string, password: string, workspace: string): Promise<LoginInfo> {
|
||||
const accountInfo = await getAccountInfo(db, email, password)
|
||||
const workspaceInfo = await getWorkspace(db, workspace)
|
||||
|
||||
if (workspaceInfo !== null) {
|
||||
const workspaces = accountInfo.workspaces
|
||||
|
||||
for (const w of workspaces) {
|
||||
if (w.equals(workspaceInfo._id)) {
|
||||
const result = {
|
||||
endpoint,
|
||||
email,
|
||||
token: generateToken(email, workspace)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new PlatformError(new Status(Severity.ERROR, accountPlugin.status.Forbidden, {}))
|
||||
}
|
||||
|
||||
export default accountPlugin
|
8
server/account/tsconfig.json
Normal file
8
server/account/tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "./node_modules/@anticrm/platform-rig/profiles/default/tsconfig.json",
|
||||
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./lib"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user