소스 검색

fix: error handling on gRPC (#937)

Karol Sójko 1 년 전
부모
커밋
8f23c8ab3f

+ 4 - 1
packages/api-gateway/src/Service/gRPC/GRPCServiceProxy.ts

@@ -88,7 +88,10 @@ export class GRPCServiceProxy implements ServiceProxyInterface {
     endpoint: string,
     payload?: Record<string, unknown> | string,
   ): Promise<void> {
-    if (endpoint === 'items/sync') {
+    const requestIsUsingLatestApiVersions =
+      payload !== undefined && typeof payload !== 'string' && 'api' in payload && payload.api === '20200115'
+
+    if (requestIsUsingLatestApiVersions && endpoint === 'items/sync') {
       const result = await this.gRPCSyncingServerServiceProxy.sync(request, response, payload)
 
       response.status(result.status).send({

+ 59 - 46
packages/auth/src/Infra/gRPC/SessionsServer.ts

@@ -19,62 +19,75 @@ export class SessionsServer implements ISessionsServer {
     call: grpc.ServerUnaryCall<AuthorizationHeader, SessionValidationResponse>,
     callback: grpc.sendUnaryData<SessionValidationResponse>,
   ): Promise<void> {
-    this.logger.debug('[SessionsServer] Validating session via gRPC')
+    try {
+      this.logger.debug('[SessionsServer] Validating session via gRPC')
 
-    const authenticateRequestResponse = await this.authenticateRequest.execute({
-      authorizationHeader: call.request.getBearerToken(),
-    })
+      const authenticateRequestResponse = await this.authenticateRequest.execute({
+        authorizationHeader: call.request.getBearerToken(),
+      })
 
-    if (!authenticateRequestResponse.success) {
-      const metadata = new grpc.Metadata()
-      metadata.set('x-auth-error-message', authenticateRequestResponse.errorMessage as string)
-      metadata.set('x-auth-error-tag', authenticateRequestResponse.errorTag as string)
-      metadata.set('x-auth-error-response-code', authenticateRequestResponse.responseCode.toString())
-      return callback(
-        {
-          code: Status.PERMISSION_DENIED,
-          message: authenticateRequestResponse.errorMessage,
-          name: authenticateRequestResponse.errorTag,
-          metadata,
-        },
-        null,
-      )
-    }
+      if (!authenticateRequestResponse.success) {
+        const metadata = new grpc.Metadata()
+        metadata.set('x-auth-error-message', authenticateRequestResponse.errorMessage as string)
+        metadata.set('x-auth-error-tag', authenticateRequestResponse.errorTag as string)
+        metadata.set('x-auth-error-response-code', authenticateRequestResponse.responseCode.toString())
+        return callback(
+          {
+            code: Status.PERMISSION_DENIED,
+            message: authenticateRequestResponse.errorMessage,
+            name: authenticateRequestResponse.errorTag,
+            metadata,
+          },
+          null,
+        )
+      }
 
-    const user = authenticateRequestResponse.user as User
+      const user = authenticateRequestResponse.user as User
 
-    const sharedVaultOwnerMetadata = call.metadata.get('x-shared-vault-owner-context')
-    let sharedVaultOwnerContext = undefined
-    if (sharedVaultOwnerMetadata.length > 0 && sharedVaultOwnerMetadata[0].length > 0) {
-      sharedVaultOwnerContext = sharedVaultOwnerMetadata[0].toString()
-    }
+      const sharedVaultOwnerMetadata = call.metadata.get('x-shared-vault-owner-context')
+      let sharedVaultOwnerContext = undefined
+      if (sharedVaultOwnerMetadata.length > 0 && sharedVaultOwnerMetadata[0].length > 0) {
+        sharedVaultOwnerContext = sharedVaultOwnerMetadata[0].toString()
+      }
+
+      const resultOrError = await this.createCrossServiceToken.execute({
+        user,
+        session: authenticateRequestResponse.session,
+        sharedVaultOwnerContext,
+      })
+      if (resultOrError.isFailed()) {
+        const metadata = new grpc.Metadata()
+        metadata.set('x-auth-error-message', resultOrError.getError())
+        metadata.set('x-auth-error-response-code', '400')
 
-    const resultOrError = await this.createCrossServiceToken.execute({
-      user,
-      session: authenticateRequestResponse.session,
-      sharedVaultOwnerContext,
-    })
-    if (resultOrError.isFailed()) {
-      const metadata = new grpc.Metadata()
-      metadata.set('x-auth-error-message', resultOrError.getError())
-      metadata.set('x-auth-error-response-code', '400')
+        return callback(
+          {
+            code: Status.INVALID_ARGUMENT,
+            message: resultOrError.getError(),
+            name: 'INVALID_ARGUMENT',
+            metadata,
+          },
+          null,
+        )
+      }
 
-      return callback(
+      const response = new SessionValidationResponse()
+      response.setCrossServiceToken(resultOrError.getValue())
+
+      this.logger.debug('[SessionsServer] Session validated via gRPC')
+
+      callback(null, response)
+    } catch (error) {
+      this.logger.error(`[SessionsServer] Error validating session via gRPC: ${(error as Error).message}`)
+
+      callback(
         {
-          code: Status.INVALID_ARGUMENT,
-          message: resultOrError.getError(),
-          name: 'INVALID_ARGUMENT',
-          metadata,
+          code: Status.UNKNOWN,
+          message: 'An error occurred while validating session',
+          name: 'UNKNOWN',
         },
         null,
       )
     }
-
-    const response = new SessionValidationResponse()
-    response.setCrossServiceToken(resultOrError.getValue())
-
-    this.logger.debug('[SessionsServer] Session validated via gRPC')
-
-    callback(null, response)
   }
 }

+ 78 - 63
packages/syncing-server/src/Infra/gRPC/SyncingServer.ts

@@ -22,38 +22,82 @@ export class SyncingServer implements ISyncingServer {
     call: grpc.ServerUnaryCall<SyncRequest, SyncResponse>,
     callback: grpc.sendUnaryData<SyncResponse>,
   ): Promise<void> {
-    this.logger.debug('[SyncingServer] Syncing items via gRPC')
+    try {
+      this.logger.debug('[SyncingServer] Syncing items via gRPC')
 
-    const itemHashesRPC = call.request.getItemsList()
-    const itemHashes: ItemHash[] = []
-    for (const itemHash of itemHashesRPC) {
-      const itemHashOrError = ItemHash.create({
-        uuid: itemHash.getUuid(),
-        content: itemHash.hasContent() ? itemHash.getContent() : undefined,
-        content_type: itemHash.hasContentType() ? (itemHash.getContentType() as string) : null,
-        deleted: itemHash.hasDeleted() ? itemHash.getDeleted() : undefined,
-        duplicate_of: itemHash.hasDuplicateOf() ? itemHash.getDuplicateOf() : undefined,
-        auth_hash: itemHash.hasAuthHash() ? itemHash.getAuthHash() : undefined,
-        enc_item_key: itemHash.hasEncItemKey() ? itemHash.getEncItemKey() : undefined,
-        items_key_id: itemHash.hasItemsKeyId() ? itemHash.getItemsKeyId() : undefined,
-        created_at: itemHash.hasCreatedAt() ? itemHash.getCreatedAt() : undefined,
-        created_at_timestamp: itemHash.hasCreatedAtTimestamp() ? itemHash.getCreatedAtTimestamp() : undefined,
-        updated_at: itemHash.hasUpdatedAt() ? itemHash.getUpdatedAt() : undefined,
-        updated_at_timestamp: itemHash.hasUpdatedAtTimestamp() ? itemHash.getUpdatedAtTimestamp() : undefined,
-        user_uuid: call.metadata.get('userUuid').pop() as string,
-        key_system_identifier: itemHash.hasKeySystemIdentifier() ? (itemHash.getKeySystemIdentifier() as string) : null,
-        shared_vault_uuid: itemHash.hasSharedVaultUuid() ? (itemHash.getSharedVaultUuid() as string) : null,
-      })
+      const itemHashesRPC = call.request.getItemsList()
+      const itemHashes: ItemHash[] = []
+      for (const itemHash of itemHashesRPC) {
+        const itemHashOrError = ItemHash.create({
+          uuid: itemHash.getUuid(),
+          content: itemHash.hasContent() ? itemHash.getContent() : undefined,
+          content_type: itemHash.hasContentType() ? (itemHash.getContentType() as string) : null,
+          deleted: itemHash.hasDeleted() ? itemHash.getDeleted() : undefined,
+          duplicate_of: itemHash.hasDuplicateOf() ? itemHash.getDuplicateOf() : undefined,
+          auth_hash: itemHash.hasAuthHash() ? itemHash.getAuthHash() : undefined,
+          enc_item_key: itemHash.hasEncItemKey() ? itemHash.getEncItemKey() : undefined,
+          items_key_id: itemHash.hasItemsKeyId() ? itemHash.getItemsKeyId() : undefined,
+          created_at: itemHash.hasCreatedAt() ? itemHash.getCreatedAt() : undefined,
+          created_at_timestamp: itemHash.hasCreatedAtTimestamp() ? itemHash.getCreatedAtTimestamp() : undefined,
+          updated_at: itemHash.hasUpdatedAt() ? itemHash.getUpdatedAt() : undefined,
+          updated_at_timestamp: itemHash.hasUpdatedAtTimestamp() ? itemHash.getUpdatedAtTimestamp() : undefined,
+          user_uuid: call.metadata.get('userUuid').pop() as string,
+          key_system_identifier: itemHash.hasKeySystemIdentifier()
+            ? (itemHash.getKeySystemIdentifier() as string)
+            : null,
+          shared_vault_uuid: itemHash.hasSharedVaultUuid() ? (itemHash.getSharedVaultUuid() as string) : null,
+        })
+
+        if (itemHashOrError.isFailed()) {
+          const metadata = new grpc.Metadata()
+          metadata.set('x-sync-error-message', itemHashOrError.getError())
+          metadata.set('x-sync-error-response-code', '400')
+
+          return callback(
+            {
+              code: Status.INVALID_ARGUMENT,
+              message: itemHashOrError.getError(),
+              name: 'INVALID_ARGUMENT',
+              metadata,
+            },
+            null,
+          )
+        }
+
+        itemHashes.push(itemHashOrError.getValue())
+      }
+
+      let sharedVaultUuids: string[] | undefined = undefined
+      const sharedVaultUuidsList = call.request.getSharedVaultUuidsList()
+      if (sharedVaultUuidsList.length > 0) {
+        sharedVaultUuids = sharedVaultUuidsList
+      }
+
+      const apiVersion = call.request.hasApiVersion() ? (call.request.getApiVersion() as string) : ApiVersion.v20161215
 
-      if (itemHashOrError.isFailed()) {
+      const syncResult = await this.syncItemsUseCase.execute({
+        userUuid: call.metadata.get('x-user-uuid').pop() as string,
+        itemHashes,
+        computeIntegrityHash: call.request.hasComputeIntegrity() ? call.request.getComputeIntegrity() === true : false,
+        syncToken: call.request.hasSyncToken() ? call.request.getSyncToken() : undefined,
+        cursorToken: call.request.getCursorToken() ? call.request.getCursorToken() : undefined,
+        limit: call.request.hasLimit() ? call.request.getLimit() : undefined,
+        contentType: call.request.hasContentType() ? call.request.getContentType() : undefined,
+        apiVersion,
+        snjsVersion: call.metadata.get('x-snjs-version').pop() as string,
+        readOnlyAccess: call.metadata.get('x-read-only-access').pop() === 'true',
+        sessionUuid: call.metadata.get('x-session-uuid').pop() as string,
+        sharedVaultUuids,
+      })
+      if (syncResult.isFailed()) {
         const metadata = new grpc.Metadata()
-        metadata.set('x-sync-error-message', itemHashOrError.getError())
+        metadata.set('x-sync-error-message', syncResult.getError())
         metadata.set('x-sync-error-response-code', '400')
 
         return callback(
           {
             code: Status.INVALID_ARGUMENT,
-            message: itemHashOrError.getError(),
+            message: syncResult.getError(),
             name: 'INVALID_ARGUMENT',
             metadata,
           },
@@ -61,53 +105,24 @@ export class SyncingServer implements ISyncingServer {
         )
       }
 
-      itemHashes.push(itemHashOrError.getValue())
-    }
-
-    let sharedVaultUuids: string[] | undefined = undefined
-    const sharedVaultUuidsList = call.request.getSharedVaultUuidsList()
-    if (sharedVaultUuidsList.length > 0) {
-      sharedVaultUuids = sharedVaultUuidsList
-    }
+      const syncResponse = await this.syncResponseFactoryResolver
+        .resolveSyncResponseFactoryVersion(apiVersion)
+        .createResponse(syncResult.getValue())
 
-    const apiVersion = call.request.hasApiVersion() ? (call.request.getApiVersion() as string) : ApiVersion.v20161215
+      const projection = this.mapper.toProjection(syncResponse as SyncResponse20200115)
 
-    const syncResult = await this.syncItemsUseCase.execute({
-      userUuid: call.metadata.get('x-user-uuid').pop() as string,
-      itemHashes,
-      computeIntegrityHash: call.request.hasComputeIntegrity() ? call.request.getComputeIntegrity() === true : false,
-      syncToken: call.request.hasSyncToken() ? call.request.getSyncToken() : undefined,
-      cursorToken: call.request.getCursorToken() ? call.request.getCursorToken() : undefined,
-      limit: call.request.hasLimit() ? call.request.getLimit() : undefined,
-      contentType: call.request.hasContentType() ? call.request.getContentType() : undefined,
-      apiVersion,
-      snjsVersion: call.metadata.get('x-snjs-version').pop() as string,
-      readOnlyAccess: call.metadata.get('x-read-only-access').pop() === 'true',
-      sessionUuid: call.metadata.get('x-session-uuid').pop() as string,
-      sharedVaultUuids,
-    })
-    if (syncResult.isFailed()) {
-      const metadata = new grpc.Metadata()
-      metadata.set('x-sync-error-message', syncResult.getError())
-      metadata.set('x-sync-error-response-code', '400')
+      callback(null, projection)
+    } catch (error) {
+      this.logger.error(`[SyncingServer] Error syncing items via gRPC: ${(error as Error).message}`)
 
       return callback(
         {
-          code: Status.INVALID_ARGUMENT,
-          message: syncResult.getError(),
-          name: 'INVALID_ARGUMENT',
-          metadata,
+          code: Status.UNKNOWN,
+          message: 'An error occurred while syncing items',
+          name: 'UNKNOWN',
         },
         null,
       )
     }
-
-    const syncResponse = await this.syncResponseFactoryResolver
-      .resolveSyncResponseFactoryVersion(apiVersion)
-      .createResponse(syncResult.getValue())
-
-    const projection = this.mapper.toProjection(syncResponse as SyncResponse20200115)
-
-    callback(null, projection)
   }
 }