@owlmeans/server-auth 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +490 -0
- package/build/.gitkeep +0 -0
- package/build/actions/index.d.ts +2 -0
- package/build/actions/index.d.ts.map +1 -0
- package/build/actions/index.js +2 -0
- package/build/actions/index.js.map +1 -0
- package/build/actions/service.d.ts +4 -0
- package/build/actions/service.d.ts.map +1 -0
- package/build/actions/service.js +7 -0
- package/build/actions/service.js.map +1 -0
- package/build/consts.d.ts +5 -0
- package/build/consts.d.ts.map +1 -0
- package/build/consts.js +5 -0
- package/build/consts.js.map +1 -0
- package/build/index.d.ts +6 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +5 -0
- package/build/index.js.map +1 -0
- package/build/manager/actions/index.d.ts +2 -0
- package/build/manager/actions/index.d.ts.map +1 -0
- package/build/manager/actions/index.js +2 -0
- package/build/manager/actions/index.js.map +1 -0
- package/build/manager/actions/manager.d.ts +6 -0
- package/build/manager/actions/manager.d.ts.map +1 -0
- package/build/manager/actions/manager.js +10 -0
- package/build/manager/actions/manager.js.map +1 -0
- package/build/manager/consts.d.ts +3 -0
- package/build/manager/consts.d.ts.map +1 -0
- package/build/manager/consts.js +3 -0
- package/build/manager/consts.js.map +1 -0
- package/build/manager/context.d.ts +3 -0
- package/build/manager/context.d.ts.map +1 -0
- package/build/manager/context.js +26 -0
- package/build/manager/context.js.map +1 -0
- package/build/manager/exports.d.ts +16 -0
- package/build/manager/exports.d.ts.map +1 -0
- package/build/manager/exports.js +13 -0
- package/build/manager/exports.js.map +1 -0
- package/build/manager/index.d.ts +11 -0
- package/build/manager/index.d.ts.map +1 -0
- package/build/manager/index.js +10 -0
- package/build/manager/index.js.map +1 -0
- package/build/manager/main.d.ts +3 -0
- package/build/manager/main.d.ts.map +1 -0
- package/build/manager/main.js +7 -0
- package/build/manager/main.js.map +1 -0
- package/build/manager/model.d.ts +3 -0
- package/build/manager/model.d.ts.map +1 -0
- package/build/manager/model.js +68 -0
- package/build/manager/model.js.map +1 -0
- package/build/manager/modules.d.ts +2 -0
- package/build/manager/modules.d.ts.map +1 -0
- package/build/manager/modules.js +21 -0
- package/build/manager/modules.js.map +1 -0
- package/build/manager/plugins/basic-ed25519.d.ts +4 -0
- package/build/manager/plugins/basic-ed25519.d.ts.map +1 -0
- package/build/manager/plugins/basic-ed25519.js +42 -0
- package/build/manager/plugins/basic-ed25519.js.map +1 -0
- package/build/manager/plugins/basic-rely.d.ts +4 -0
- package/build/manager/plugins/basic-rely.d.ts.map +1 -0
- package/build/manager/plugins/basic-rely.js +152 -0
- package/build/manager/plugins/basic-rely.js.map +1 -0
- package/build/manager/plugins/export.d.ts +6 -0
- package/build/manager/plugins/export.d.ts.map +1 -0
- package/build/manager/plugins/export.js +5 -0
- package/build/manager/plugins/export.js.map +1 -0
- package/build/manager/plugins/index.d.ts +4 -0
- package/build/manager/plugins/index.d.ts.map +1 -0
- package/build/manager/plugins/index.js +9 -0
- package/build/manager/plugins/index.js.map +1 -0
- package/build/manager/plugins/re-captcha.d.ts +4 -0
- package/build/manager/plugins/re-captcha.d.ts.map +1 -0
- package/build/manager/plugins/re-captcha.js +49 -0
- package/build/manager/plugins/re-captcha.js.map +1 -0
- package/build/manager/plugins/types.d.ts +25 -0
- package/build/manager/plugins/types.d.ts.map +1 -0
- package/build/manager/plugins/types.js +2 -0
- package/build/manager/plugins/types.js.map +1 -0
- package/build/manager/plugins/utils.d.ts +8 -0
- package/build/manager/plugins/utils.d.ts.map +1 -0
- package/build/manager/plugins/utils.js +18 -0
- package/build/manager/plugins/utils.js.map +1 -0
- package/build/manager/rely/flow.d.ts +5 -0
- package/build/manager/rely/flow.d.ts.map +1 -0
- package/build/manager/rely/flow.js +127 -0
- package/build/manager/rely/flow.js.map +1 -0
- package/build/manager/rely/index.d.ts +2 -0
- package/build/manager/rely/index.d.ts.map +1 -0
- package/build/manager/rely/index.js +2 -0
- package/build/manager/rely/index.js.map +1 -0
- package/build/manager/rely.d.ts +3 -0
- package/build/manager/rely.d.ts.map +1 -0
- package/build/manager/rely.js +63 -0
- package/build/manager/rely.js.map +1 -0
- package/build/manager/types.d.ts +33 -0
- package/build/manager/types.d.ts.map +1 -0
- package/build/manager/types.js +2 -0
- package/build/manager/types.js.map +1 -0
- package/build/manager/utils/index.d.ts +2 -0
- package/build/manager/utils/index.d.ts.map +1 -0
- package/build/manager/utils/index.js +2 -0
- package/build/manager/utils/index.js.map +1 -0
- package/build/manager/utils/trusted.d.ts +5 -0
- package/build/manager/utils/trusted.d.ts.map +1 -0
- package/build/manager/utils/trusted.js +11 -0
- package/build/manager/utils/trusted.js.map +1 -0
- package/build/model/index.d.ts +2 -0
- package/build/model/index.d.ts.map +1 -0
- package/build/model/index.js +2 -0
- package/build/model/index.js.map +1 -0
- package/build/model/rely/consumer.d.ts +3 -0
- package/build/model/rely/consumer.d.ts.map +1 -0
- package/build/model/rely/consumer.js +9 -0
- package/build/model/rely/consumer.js.map +1 -0
- package/build/model/rely/index.d.ts +5 -0
- package/build/model/rely/index.d.ts.map +1 -0
- package/build/model/rely/index.js +4 -0
- package/build/model/rely/index.js.map +1 -0
- package/build/model/rely/peer.d.ts +5 -0
- package/build/model/rely/peer.d.ts.map +1 -0
- package/build/model/rely/peer.js +36 -0
- package/build/model/rely/peer.js.map +1 -0
- package/build/model/rely/provider.d.ts +3 -0
- package/build/model/rely/provider.d.ts.map +1 -0
- package/build/model/rely/provider.js +6 -0
- package/build/model/rely/provider.js.map +1 -0
- package/build/model/rely/types.d.ts +8 -0
- package/build/model/rely/types.d.ts.map +1 -0
- package/build/model/rely/types.js +2 -0
- package/build/model/rely/types.js.map +1 -0
- package/build/modules.d.ts +3 -0
- package/build/modules.d.ts.map +1 -0
- package/build/modules.js +11 -0
- package/build/modules.js.map +1 -0
- package/build/service.d.ts +7 -0
- package/build/service.d.ts.map +1 -0
- package/build/service.js +90 -0
- package/build/service.js.map +1 -0
- package/build/types.d.ts +13 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/package.json +76 -0
- package/src/actions/index.ts +2 -0
- package/src/actions/service.ts +16 -0
- package/src/consts.ts +8 -0
- package/src/index.ts +6 -0
- package/src/manager/README.md +507 -0
- package/src/manager/actions/index.ts +2 -0
- package/src/manager/actions/manager.ts +23 -0
- package/src/manager/consts.ts +4 -0
- package/src/manager/context.ts +33 -0
- package/src/manager/exports.ts +17 -0
- package/src/manager/index.ts +11 -0
- package/src/manager/main.ts +9 -0
- package/src/manager/model.ts +93 -0
- package/src/manager/modules.ts +29 -0
- package/src/manager/plugins/basic-ed25519.ts +56 -0
- package/src/manager/plugins/basic-rely.ts +167 -0
- package/src/manager/plugins/export.ts +6 -0
- package/src/manager/plugins/index.ts +13 -0
- package/src/manager/plugins/re-captcha.ts +62 -0
- package/src/manager/plugins/types.ts +27 -0
- package/src/manager/plugins/utils.ts +21 -0
- package/src/manager/rely/flow.ts +135 -0
- package/src/manager/rely/index.ts +2 -0
- package/src/manager/rely.ts +90 -0
- package/src/manager/types.ts +42 -0
- package/src/manager/utils/index.ts +2 -0
- package/src/manager/utils/trusted.ts +16 -0
- package/src/model/index.ts +2 -0
- package/src/model/rely/consumer.ts +11 -0
- package/src/model/rely/index.ts +5 -0
- package/src/model/rely/peer.ts +43 -0
- package/src/model/rely/provider.ts +9 -0
- package/src/model/rely/types.ts +8 -0
- package/src/modules.ts +17 -0
- package/src/service.ts +126 -0
- package/src/types.ts +15 -0
- package/tsconfig.json +15 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { assertContext, createService } from '@owlmeans/context'
|
|
2
|
+
import { DEFAULT_RELY } from './consts.js'
|
|
3
|
+
import type { AppContext, RelyService } from './types.js'
|
|
4
|
+
import { AUTH_QUERY, AuthenFailed, AuthenticationType } from '@owlmeans/auth'
|
|
5
|
+
import type { Auth, AuthCredentials, AuthToken } from '@owlmeans/auth'
|
|
6
|
+
import type { AbstractRequest, AbstractResponse } from '@owlmeans/module'
|
|
7
|
+
import { EnvelopeKind, makeEnvelopeModel } from '@owlmeans/basic-envelope'
|
|
8
|
+
import type { ServerConfig, ServerContext } from '@owlmeans/server-context'
|
|
9
|
+
import { AUTH_CACHE, AUTHEN_TIMEFRAME } from '../consts.js'
|
|
10
|
+
import type { AuthSpent } from '../types.js'
|
|
11
|
+
import type { Resource } from '@owlmeans/resource'
|
|
12
|
+
import { trusted } from './utils/trusted.js'
|
|
13
|
+
|
|
14
|
+
type Config = ServerConfig
|
|
15
|
+
type Context = ServerContext<Config>
|
|
16
|
+
|
|
17
|
+
export const createRelyService = (alias: string = DEFAULT_RELY): RelyService => {
|
|
18
|
+
const _keyPair = async (context: Context) => {
|
|
19
|
+
const [, keyPair] = await trusted(context as AppContext)
|
|
20
|
+
|
|
21
|
+
return keyPair
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const service: RelyService = createService<RelyService>(alias, {
|
|
25
|
+
match: async (req: AbstractRequest<AuthToken>) => {
|
|
26
|
+
const authorization: string | null = req.query[AUTH_QUERY] != null
|
|
27
|
+
? `${req.query[AUTH_QUERY]}` : null
|
|
28
|
+
|
|
29
|
+
if (authorization == null) {
|
|
30
|
+
// This is optional Guard. So it can not match only on provided authorization
|
|
31
|
+
// that is not valid. In other cases it's passed and need to be handled
|
|
32
|
+
// to provide or null authentication object.
|
|
33
|
+
return true
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const token = makeEnvelopeModel<Auth>(authorization, EnvelopeKind.Token)
|
|
37
|
+
const auth = token.message()
|
|
38
|
+
|
|
39
|
+
return auth.type === AuthenticationType.OneTimeToken
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
handle: async <T>(req: AbstractRequest<AuthToken>, res: AbstractResponse<Auth>) => {
|
|
43
|
+
const context = assertContext<Config, Context>(service.ctx as Context)
|
|
44
|
+
const authorization = req.query[AUTH_QUERY]
|
|
45
|
+
// We authorize in cases when there is no authorization or it's valid one
|
|
46
|
+
if (authorization == null) {
|
|
47
|
+
return true as T
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// @TODO it's likely something is wrong with AbstractRequest types - so it should be fixed there
|
|
51
|
+
if (typeof authorization !== 'string') {
|
|
52
|
+
return false as T
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const envelope = makeEnvelopeModel<AuthCredentials>(authorization, EnvelopeKind.Token)
|
|
56
|
+
|
|
57
|
+
if (!await envelope.verify(await _keyPair(context))) {
|
|
58
|
+
return false as T
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const msg = envelope.message()
|
|
62
|
+
if (msg.source !== AuthenticationType.WalletDid) {
|
|
63
|
+
return false as T
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const cache = (context: Context): Resource<AuthSpent> =>
|
|
68
|
+
context.resource<Resource<AuthSpent>>(AUTH_CACHE)
|
|
69
|
+
|
|
70
|
+
await cache(context).create(
|
|
71
|
+
{ id: msg.challenge },
|
|
72
|
+
{ ttl: (envelope.envelope.ttl ?? AUTHEN_TIMEFRAME) / 1000 }
|
|
73
|
+
)
|
|
74
|
+
} catch (e) {
|
|
75
|
+
const error = new AuthenFailed('challenge')
|
|
76
|
+
if (e instanceof Error) {
|
|
77
|
+
error.oiriginalStack = `${e} : ${e.stack}`
|
|
78
|
+
}
|
|
79
|
+
throw error
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// @TODO Actually there is some mess. We know that it aint Auth but AuthCredentials
|
|
83
|
+
res.resolve(msg as unknown as Auth)
|
|
84
|
+
|
|
85
|
+
return true as T
|
|
86
|
+
}
|
|
87
|
+
}, service => async () => { service.initialized = true })
|
|
88
|
+
|
|
89
|
+
return service
|
|
90
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { AllowanceRequest, AllowanceResponse, Auth, AuthCredentials, AuthToken, RelyToken } from '@owlmeans/auth'
|
|
2
|
+
import type { KlusterConfig } from '@owlmeans/kluster'
|
|
3
|
+
import type { GuardService } from '@owlmeans/module'
|
|
4
|
+
import type { ApiServerAppend } from '@owlmeans/server-api'
|
|
5
|
+
import type { ServerContext, ServerConfig } from '@owlmeans/server-context'
|
|
6
|
+
import type { ServiceRoute } from '@owlmeans/server-route'
|
|
7
|
+
import type { Connection } from '@owlmeans/socket'
|
|
8
|
+
import type { StaticResourceAppend } from '@owlmeans/static-resource'
|
|
9
|
+
|
|
10
|
+
export interface AppConfig extends ServerConfig, KlusterConfig {
|
|
11
|
+
services: Record<string, ServiceRoute>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface AuthModel {
|
|
15
|
+
init: (request: AllowanceRequest) => Promise<AllowanceResponse>
|
|
16
|
+
|
|
17
|
+
authenticate: (credential: AuthCredentials) => Promise<AuthToken>
|
|
18
|
+
|
|
19
|
+
rely: (conn: Connection, source?: Auth | null) => Promise<void>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface AppContext<C extends AppConfig = AppConfig> extends ServerContext<C>
|
|
23
|
+
, ApiServerAppend
|
|
24
|
+
, StaticResourceAppend { }
|
|
25
|
+
|
|
26
|
+
export interface RelyService extends GuardService {
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface RelyAllowanceRequest extends AllowanceRequest {
|
|
30
|
+
auth?: Auth
|
|
31
|
+
provideRely?: RelyLinker
|
|
32
|
+
conn?: Connection
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface RelyLinker {
|
|
36
|
+
(rely: RelyToken, source: RelyToken, notify?: boolean): Promise<void>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface RelyCarrier {
|
|
40
|
+
source: RelyToken,
|
|
41
|
+
rely: RelyToken
|
|
42
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { KeyPairModel } from '@owlmeans/basic-keys'
|
|
2
|
+
import type { AppContext, AppConfig } from '../types.js'
|
|
3
|
+
import { TRUSTED } from '@owlmeans/config'
|
|
4
|
+
import { AUTH_SRV_KEY } from '../../consts.js'
|
|
5
|
+
import type { TrustedRecord } from '@owlmeans/auth-common'
|
|
6
|
+
import { trust } from '@owlmeans/auth-common/utils'
|
|
7
|
+
|
|
8
|
+
export const trusted = async (context: AppContext, userName: string = AUTH_SRV_KEY): Promise<[TrustedRecord, KeyPairModel]> => {
|
|
9
|
+
const trusted = await trust<AppConfig, AppContext>(context, TRUSTED, userName)
|
|
10
|
+
|
|
11
|
+
if (trusted.user.secret == null) {
|
|
12
|
+
throw new SyntaxError(`Auth srvice trusted users should have secret keys to be used ${userName}`)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return [trusted.user, trusted.key]
|
|
16
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { makeRelyModel } from './peer.js'
|
|
2
|
+
import type { RelyOptions } from './types.js'
|
|
3
|
+
|
|
4
|
+
export const makeConsumerRely = (opts?: RelyOptions) => {
|
|
5
|
+
const model = makeRelyModel(opts)
|
|
6
|
+
const msg = model.message()
|
|
7
|
+
delete msg.pin
|
|
8
|
+
model.send(msg)
|
|
9
|
+
|
|
10
|
+
return model
|
|
11
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { RelyToken } from '@owlmeans/auth'
|
|
2
|
+
import { RELY_3RD } from '@owlmeans/auth'
|
|
3
|
+
import type { EnvelopeModel } from '@owlmeans/basic-envelope'
|
|
4
|
+
import { makeEnvelopeModel } from '@owlmeans/basic-envelope'
|
|
5
|
+
import { createRandomPrefix, createIdOfLength, IdStyle } from '@owlmeans/basic-ids'
|
|
6
|
+
import { base58 } from '@scure/base'
|
|
7
|
+
import type { RelyOptions } from './types.js'
|
|
8
|
+
import { RELY_CALL_TIMEOUT } from '@owlmeans/auth-common'
|
|
9
|
+
|
|
10
|
+
export const makeRelyModel = (opts?: RelyOptions): EnvelopeModel<RelyToken> => {
|
|
11
|
+
const envelope = makeEnvelopeModel<RelyToken>(RELY_3RD)
|
|
12
|
+
|
|
13
|
+
const pinLength = opts?.pinLength ?? 6
|
|
14
|
+
const checkLength = opts?.checkLenght ?? 2
|
|
15
|
+
const tokenLength = opts?.tokenLength ?? 16
|
|
16
|
+
const nonceLength = opts?.nonceLength ?? 24
|
|
17
|
+
const pinQty = Math.ceil(pinLength / 2)
|
|
18
|
+
const checkQty = Math.ceil(checkLength / 2)
|
|
19
|
+
const tokenQty = tokenLength
|
|
20
|
+
const source = createRandomPrefix(pinQty + checkQty + tokenQty)
|
|
21
|
+
const bytes = base58.decode(source)
|
|
22
|
+
const pinBytes = bytes.slice(0, pinQty)
|
|
23
|
+
const checkBytes = bytes.slice(pinQty, pinQty + checkQty)
|
|
24
|
+
const tokenBytes = bytes.slice(pinQty + checkQty)
|
|
25
|
+
|
|
26
|
+
const pin = toNumber(pinBytes).substring(0, pinLength)
|
|
27
|
+
envelope.send({
|
|
28
|
+
pin,
|
|
29
|
+
check: toNumber(checkBytes).substring(0, checkLength),
|
|
30
|
+
token: base58.encode(tokenBytes).substring(0, tokenLength),
|
|
31
|
+
nonce: createIdOfLength(nonceLength, IdStyle.Base64)
|
|
32
|
+
}, opts?.liveTime ?? RELY_CALL_TIMEOUT * 1000)
|
|
33
|
+
|
|
34
|
+
return envelope
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const toNumber = (bytes: Uint8Array): string => {
|
|
38
|
+
let pinInt = 0n
|
|
39
|
+
for (let i = bytes.length - 1; i >= 0; i--) {
|
|
40
|
+
pinInt = (pinInt << 8n) | BigInt(bytes[i]);
|
|
41
|
+
}
|
|
42
|
+
return pinInt.toString()
|
|
43
|
+
}
|
package/src/modules.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
import { elevate } from '@owlmeans/server-module'
|
|
3
|
+
import { modules as list } from '@owlmeans/auth-common'
|
|
4
|
+
import { DISPATCHER, DISPATCHER_AUTHEN } from '@owlmeans/auth'
|
|
5
|
+
import type { ServerModule } from '@owlmeans/server-module'
|
|
6
|
+
import { authenticate } from './actions/service.js'
|
|
7
|
+
import { stab, elevate as celevate } from '@owlmeans/client-module'
|
|
8
|
+
|
|
9
|
+
elevate(list, DISPATCHER_AUTHEN, authenticate)
|
|
10
|
+
celevate(list, DISPATCHER, stab)
|
|
11
|
+
|
|
12
|
+
export const modules: ServerModule<unknown>[] = [
|
|
13
|
+
...list.filter(
|
|
14
|
+
(module): module is ServerModule<unknown> =>
|
|
15
|
+
[DISPATCHER, DISPATCHER_AUTHEN].includes(module.getAlias())
|
|
16
|
+
)
|
|
17
|
+
]
|
package/src/service.ts
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type { ServerContext, ServerConfig } from '@owlmeans/server-context'
|
|
2
|
+
import { TRUSTED } from '@owlmeans/config'
|
|
3
|
+
import { AUTH_CACHE, AUTH_SRV_KEY, AUTHEN_TIMEFRAME, DEFAULT_ALIAS } from './consts.js'
|
|
4
|
+
import type { AuthServiceAppend, AuthService, AuthSpent } from './types.js'
|
|
5
|
+
import { assertContext, createService } from '@owlmeans/context'
|
|
6
|
+
import { EnvelopeKind, makeEnvelopeModel } from '@owlmeans/basic-envelope'
|
|
7
|
+
import type { Auth, AuthCredentials } from '@owlmeans/auth'
|
|
8
|
+
import { AuthenFailed, AuthorizationError, AuthroizationType } from '@owlmeans/auth'
|
|
9
|
+
import type { AbstractRequest, AbstractResponse } from '../../module/build/types.js'
|
|
10
|
+
import type { Resource } from '@owlmeans/resource'
|
|
11
|
+
import { createStaticResource } from '@owlmeans/static-resource'
|
|
12
|
+
import { trust, extractAuthToken } from '@owlmeans/auth-common/utils'
|
|
13
|
+
|
|
14
|
+
type Config = ServerConfig
|
|
15
|
+
type Context = ServerContext<Config>
|
|
16
|
+
|
|
17
|
+
export const makeAuthService = (alias: string = DEFAULT_ALIAS): AuthService => {
|
|
18
|
+
const location = `server-auth:${alias}`
|
|
19
|
+
|
|
20
|
+
const cache = (context: Context): Resource<AuthSpent> =>
|
|
21
|
+
context.resource<Resource<AuthSpent>>(AUTH_CACHE)
|
|
22
|
+
|
|
23
|
+
const service: AuthService = createService<AuthService>(alias, {
|
|
24
|
+
match: async req => extractAuthToken(req, AuthroizationType.Ed25519BasicToken) != null,
|
|
25
|
+
|
|
26
|
+
handle: async <T>(req: AbstractRequest, res: AbstractResponse<Auth>) => {
|
|
27
|
+
const context = assertContext(service.ctx) as Context
|
|
28
|
+
const authorization = extractAuthToken(req, AuthroizationType.Ed25519BasicToken)
|
|
29
|
+
if (authorization == null) {
|
|
30
|
+
return false as T
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const envelope = makeEnvelopeModel<Auth>(authorization, EnvelopeKind.Token)
|
|
34
|
+
|
|
35
|
+
const trusted = await trust<Config, Context>(context, TRUSTED, context.cfg.alias ?? context.cfg.service)
|
|
36
|
+
if (!await envelope.verify(trusted.key)) {
|
|
37
|
+
return false as T
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
res.resolve(envelope.message())
|
|
41
|
+
|
|
42
|
+
return true as T
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
unpack: async token => {
|
|
46
|
+
const context = service.assertCtx<Config, Context>()
|
|
47
|
+
const [, authorization] = token.split(' ')
|
|
48
|
+
const envelope = makeEnvelopeModel<Auth>(authorization, EnvelopeKind.Token)
|
|
49
|
+
|
|
50
|
+
const trusted = await trust<Config, Context>(context, TRUSTED, context.cfg.alias ?? context.cfg.service)
|
|
51
|
+
if (!await envelope.verify(trusted.key)) {
|
|
52
|
+
throw new AuthorizationError('unpack')
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return envelope.message()
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
authenticated: async () => {
|
|
59
|
+
return null
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
authenticate: async token => {
|
|
63
|
+
const context = assertContext<Config, Context>(service.ctx as Context, location)
|
|
64
|
+
const envelope = makeEnvelopeModel<AuthCredentials>(token.token, EnvelopeKind.Token)
|
|
65
|
+
|
|
66
|
+
const authService = await trust<Config, Context>(context, TRUSTED, AUTH_SRV_KEY)
|
|
67
|
+
if (!await envelope.verify(authService.key)) {
|
|
68
|
+
throw new AuthenFailed()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const credentials = envelope.message()
|
|
72
|
+
const msg = credentials.challenge
|
|
73
|
+
|
|
74
|
+
// @TODO This operation is not atomic in case of redis store usage and scling
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
await cache(context).create({ id: msg }, { ttl: AUTHEN_TIMEFRAME / 1000 })
|
|
78
|
+
} catch {
|
|
79
|
+
throw new AuthenFailed()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (credentials.credential !== authService.user.id) {
|
|
83
|
+
throw new AuthenFailed()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// @TODO Move to a plugin
|
|
87
|
+
const auth: Auth = {
|
|
88
|
+
token: credentials.challenge,
|
|
89
|
+
userId: credentials.userId,
|
|
90
|
+
scopes: credentials.scopes,
|
|
91
|
+
role: credentials.role,
|
|
92
|
+
type: AuthroizationType.Ed25519BasicToken,
|
|
93
|
+
source: context.cfg.service,
|
|
94
|
+
profileId: credentials.profileId,
|
|
95
|
+
entityId: credentials.entityId,
|
|
96
|
+
isUser: true,
|
|
97
|
+
createdAt: new Date()
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const trusted = await trust<Config, Context>(context, TRUSTED, context.cfg.alias ?? context.cfg.service)
|
|
101
|
+
const authorization = await makeEnvelopeModel<Auth>(AuthroizationType.Ed25519BasicToken)
|
|
102
|
+
.send(auth, null).sign(trusted.key, EnvelopeKind.Token)
|
|
103
|
+
|
|
104
|
+
return { token: `${AuthroizationType.Ed25519BasicToken.toUpperCase()} ${authorization}` }
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
return service
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export const appendAuthService = <C extends Config, T extends ServerContext<C>>(
|
|
112
|
+
ctx: T, alias: string = DEFAULT_ALIAS
|
|
113
|
+
): T & AuthServiceAppend => {
|
|
114
|
+
|
|
115
|
+
if (!ctx.hasResource(AUTH_CACHE)) {
|
|
116
|
+
ctx.registerResource(createStaticResource(AUTH_CACHE))
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const service = makeAuthService(alias)
|
|
120
|
+
const context = ctx as T & AuthServiceAppend
|
|
121
|
+
|
|
122
|
+
context.registerService(service)
|
|
123
|
+
context.auth = () => ctx.service(service.alias)
|
|
124
|
+
|
|
125
|
+
return context
|
|
126
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Auth, AuthToken } from '@owlmeans/auth'
|
|
2
|
+
import type { GuardService } from '@owlmeans/module'
|
|
3
|
+
import type { ResourceRecord } from '@owlmeans/resource'
|
|
4
|
+
|
|
5
|
+
export interface AuthService extends GuardService {
|
|
6
|
+
authenticate: (token: AuthToken) => Promise<AuthToken>
|
|
7
|
+
unpack: (token: string) => Promise<Auth>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface AuthServiceAppend {
|
|
11
|
+
auth: () => AuthService
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface AuthSpent extends ResourceRecord {
|
|
15
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": [
|
|
3
|
+
"../tsconfig.default.json",
|
|
4
|
+
],
|
|
5
|
+
"compilerOptions": {
|
|
6
|
+
"rootDir": "./src/", /* Specify the root folder within your source files. */
|
|
7
|
+
"outDir": "./build/", /* Specify an output folder for all emitted files. */
|
|
8
|
+
"moduleResolution": "Bundler"
|
|
9
|
+
},
|
|
10
|
+
"exclude": [
|
|
11
|
+
"./dist/**/*",
|
|
12
|
+
"./build/**/*",
|
|
13
|
+
"./*.ts"
|
|
14
|
+
]
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"root":["./src/consts.ts","./src/index.ts","./src/modules.ts","./src/service.ts","./src/types.ts","./src/actions/index.ts","./src/actions/service.ts","./src/manager/consts.ts","./src/manager/context.ts","./src/manager/exports.ts","./src/manager/index.ts","./src/manager/main.ts","./src/manager/model.ts","./src/manager/modules.ts","./src/manager/rely.ts","./src/manager/types.ts","./src/manager/actions/index.ts","./src/manager/actions/manager.ts","./src/manager/plugins/basic-ed25519.ts","./src/manager/plugins/basic-rely.ts","./src/manager/plugins/export.ts","./src/manager/plugins/index.ts","./src/manager/plugins/re-captcha.ts","./src/manager/plugins/types.ts","./src/manager/plugins/utils.ts","./src/manager/rely/flow.ts","./src/manager/rely/index.ts","./src/manager/utils/index.ts","./src/manager/utils/trusted.ts","./src/model/index.ts","./src/model/rely/consumer.ts","./src/model/rely/index.ts","./src/model/rely/peer.ts","./src/model/rely/provider.ts","./src/model/rely/types.ts"],"version":"5.6.3"}
|