Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions keeperapi/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion keeperapi/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@keeper-security/keeperapi",
"description": "Keeper API Javascript SDK",
"version": "18.0.2",
"version": "18.0.3",
"browser": "dist/browser/index.js",
"main": "dist/index.cjs.js",
"types": "dist/node/index.d.ts",
Expand Down
6 changes: 5 additions & 1 deletion keeperapi/scripts/generate-proto.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const PROTO_FILES = [
'router.proto',
'record_endpoints.proto',
'remove.proto',
'workflow.proto',
]

// Explicit filename overrides. 'folder' (lowercase) collides with 'Folder' on case-insensitive
Expand Down Expand Up @@ -94,7 +95,10 @@ async function main() {
for (let i = 0; i < splits.length; i++) {
const { name, startLine } = splits[i]
const endLine = i + 1 < splits.length ? splits[i + 1].startLine : lines.length
const body = lines.slice(startLine, endLine).join('\n')
const body = lines
.slice(startLine, endLine)
.filter((l) => l !== 'export { $root as default };')
.join('\n')
const filename = FILENAME_OVERRIDES[name] ?? name

writeFileSync(
Expand Down
14 changes: 13 additions & 1 deletion keeperapi/src/__tests__/endpoint.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { ClientConfigurationInternal, TransmissionKey } from '../configuration'
import { AllowedMlKemKeyIds, isAllowedEcKeyId, isAllowedMlKemKeyId } from '../transmissionKeys'
import { KeeperError } from '../configuration'
import { Authentication, Router, GraphSync, PAM } from '../proto'
import { startLoginMessage, pamGetLeafsMessage, getControllers } from '../restMessages'
import { startLoginMessage, pamGetLeafsMessage, getControllers, requestWorkflowAccessMessage } from '../restMessages'
import { HPKE_ECDH_KYBER, Ciphersuite, MlKemVariant, mlKemKeygen, encodeMlKemPublicKeyToPem } from '../qrc'
import { getKeeperMlKemKeyVariant } from '../transmissionKeys'
import { KeeperHttpResponse } from '../commands'
Expand Down Expand Up @@ -605,6 +605,18 @@ describe('executeRouterRest', () => {
const message = getControllers()
expect(message.path).toBe('pam/get_controllers')
})

it('returns void for RestInMessage with empty 200 response', async () => {
jest.spyOn(platform, 'post').mockResolvedValue({
data: new Uint8Array(0),
statusCode: 200,
headers: new Headers(),
})

const message = requestWorkflowAccessMessage({ resource: { value: new Uint8Array([1, 2, 3]) } })
const result = await endpoint.executeRouterRest(message, sessionToken)
expect(result).toBeUndefined()
})
})

async function mockPlatformPost(_, requestBody): Promise<KeeperHttpResponse> {
Expand Down
4 changes: 4 additions & 0 deletions keeperapi/src/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1300,6 +1300,10 @@ export class Auth {
return this.endpoint.executeRouterRest(message, this._sessionToken)
}

async executeRouterRestAction<TIn>(message: RestInMessage<TIn>): Promise<void> {
return this.endpoint.executeRouterRest(message, this._sessionToken)
}

async executeRestCommand<Request, Response>(command: RestCommand<Request, Response>): Promise<Response> {
if (!command.baseRequest.username) {
command.baseRequest.username = this._username
Expand Down
12 changes: 10 additions & 2 deletions keeperapi/src/endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,13 @@ export class KeeperEndpoint {
async executeRouterRest<TIn, TOut>(
message: RestMessage<TIn, TOut> | RestOutMessage<TOut>,
sessionToken: string
): Promise<TOut> {
): Promise<TOut>
async executeRouterRest<TIn>(message: RestInMessage<TIn>, sessionToken: string): Promise<void>
async executeRouterRest<TOut>(message: RestOutMessage<TOut>, sessionToken: string): Promise<TOut>
async executeRouterRest<TIn, TOut>(
message: RestMessage<TIn, TOut> | RestOutMessage<TOut> | RestInMessage<TIn>,
sessionToken: string
): Promise<TOut | void> {
const transmissionKey = await this.getTransmissionKey()
const sessionTokenBytes = normal64Bytes(sessionToken)
const encryptedSessionToken = await platform.aesGcmEncrypt(sessionTokenBytes, transmissionKey.key)
Expand All @@ -211,7 +217,8 @@ export class KeeperEndpoint {
const startTime = Date.now()
const response = await platform.post(url, encryptedPayload, headers)
if (!response.data || response.data.length === 0) {
throw new Error(`Empty response from router for ${message.path}`)
if ('fromBytes' in message) throw new Error(`Empty response from router for ${message.path}`)
return
}
if (response.statusCode !== 200) {
logger.debug(`← ${requestId} Response code:`, response.statusCode)
Expand All @@ -233,6 +240,7 @@ export class KeeperEndpoint {
} as KeeperError
}
const decryptedPayload = await platform.aesGcmDecrypt(routerResponse.encryptedPayload, transmissionKey.key)
if (!('fromBytes' in message)) return
const result = message.fromBytes(decryptedPayload)
if (isLevelEnabled('debug')) {
logger.debug(...formatProto(`← ${requestId} ${formatTimeDiff(new Date(Date.now() - startTime))}s`, result))
Expand Down
Loading
Loading