@eduzz/miau-client 1.2.0 → 1.2.1-rc.133

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.
@@ -1,4 +1,4 @@
1
1
 
2
- > @eduzz/miau-client@1.2.0 build:types /home/runner/work/eduzz-miau/eduzz-miau/packages/client
2
+ > @eduzz/miau-client@1.2.1 build:types /home/runner/work/eduzz-miau/eduzz-miau/packages/client
3
3
  > tsc --emitDeclarationOnly --outDir dist
4
4
 
@@ -1,5 +1,6 @@
1
- import { type RequestHandler } from 'express';
2
- import { type SecretEnv, type Permission, type Resource } from '@eduzz/miau-types';
1
+ import { type Request, type RequestHandler } from 'express';
2
+ import { type FastifyReply, type FastifyRequest } from 'fastify';
3
+ import { type SecretEnv, type Permission, type Resource, type MiauClientToken } from '@eduzz/miau-types';
3
4
  import { type RequestAugmentation } from './middleware';
4
5
  type MiauClientConfig = {
5
6
  apiUrl: string;
@@ -14,12 +15,18 @@ export declare class MiauClient {
14
15
  getEnvironment(): SecretEnv;
15
16
  getPublicKey(kid: string): Promise<string>;
16
17
  getToken(): Promise<string | undefined>;
18
+ getTokenData: () => Promise<MiauClientToken>;
17
19
  middleware<T = Record<string, string>>(config?: {
18
- requestAugmentation?: RequestAugmentation<T>;
20
+ requestAugmentation?: RequestAugmentation<T, Request>;
19
21
  fallbackMiddleware?: RequestHandler;
20
22
  }): RequestHandler;
23
+ hook<T = Record<string, string>>(config?: {
24
+ requestAugmentation?: RequestAugmentation<T, FastifyRequest>;
25
+ fallbackMiddleware?: (request: FastifyRequest, reply: FastifyReply) => void;
26
+ }): (request: FastifyRequest, reply: FastifyReply) => void;
21
27
  getResources(): Promise<Resource[]>;
22
28
  getPermissions(targetAppId: string): Promise<Permission>;
29
+ verify(token: string, publicKey: string): Promise<MiauClientToken>;
23
30
  private getApiJwtUrl;
24
31
  private getPermissionsUrl;
25
32
  private getResourcesUrl;
package/dist/index.js CHANGED
@@ -11816,9 +11816,7 @@ var expirationOptions = {
11816
11816
  "Twelve hours": "twelveHours",
11817
11817
  "One day": "oneDay",
11818
11818
  "One week": "sevenDays",
11819
- "One month": "oneMonth",
11820
- "Six months": "sixMonths",
11821
- "One year": "oneYear"
11819
+ "One month": "oneMonth"
11822
11820
  };
11823
11821
  var expirationOptionsValues = Object.values(expirationOptions);
11824
11822
  var conversionMap = {
@@ -11909,63 +11907,79 @@ var isResourceAllowed = (resource, resources, permittedResources) => {
11909
11907
 
11910
11908
  // src/middleware.ts
11911
11909
  var HttpError = class _HttpError extends Error {
11912
- constructor(status, name, message) {
11913
- super(message);
11910
+ constructor(status, name, message, code) {
11911
+ super(`${message} (${code})`);
11914
11912
  this.name = name;
11915
11913
  this.status = status;
11916
11914
  Object.setPrototypeOf(this, _HttpError.prototype);
11917
11915
  }
11918
11916
  };
11917
+ var auth = async (token, method, path, miauClient) => {
11918
+ if (!token) {
11919
+ throw new HttpError(400, "Invalid Token", "Token not provided", "MIAU_TKN_A");
11920
+ }
11921
+ const decodedToken = import_jsonwebtoken.default.decode(token, { complete: true });
11922
+ if (!decodedToken) {
11923
+ throw new HttpError(400, "Invalid Token", "Token could not be decoded", "MIAU_TKN_B");
11924
+ }
11925
+ if (!decodedToken.header?.kid) {
11926
+ throw new HttpError(400, "Invalid Token", "Missing kid in token header", "MIAU_TKN_C");
11927
+ }
11928
+ if (decodedToken.payload.iss !== issuers["production"]) {
11929
+ throw new HttpError(400, "Invalid Token", "Token issuer is invalid", "MIAU_TKN_D");
11930
+ }
11931
+ const publicKey = await miauClient.getPublicKey(decodedToken.header.kid);
11932
+ const clientTokenData = await miauClient.verify(token, publicKey);
11933
+ const serverTokenData = await miauClient.getTokenData();
11934
+ if (!clientTokenData || !clientTokenData.application || !clientTokenData.secret || !clientTokenData.application.id || !clientTokenData.secret.id || !clientTokenData.secret.environment) {
11935
+ throw new HttpError(401, "Invalid Token", "Token invalid or expired", "MIAU_TKN_E");
11936
+ }
11937
+ const { application: clientApplication, secret: clientSecret } = clientTokenData;
11938
+ const { application: serverApplication, secret: serverSecret } = serverTokenData;
11939
+ if (clientSecret.environment != serverSecret.environment) {
11940
+ throw new HttpError(
11941
+ 401,
11942
+ "Invalid Environment",
11943
+ `Secret environment ${clientSecret.environment} does not match Server environment ${serverSecret.environment}`,
11944
+ "MIAU_ENV_A"
11945
+ );
11946
+ }
11947
+ const resources = await miauClient.getResources();
11948
+ if (!resources) {
11949
+ throw new HttpError(401, "Unauthorized", `No resources configured in ${serverApplication.name}`, "MIAU_RES_A");
11950
+ }
11951
+ const permission = await miauClient.getPermissions(clientApplication.id);
11952
+ if (!permission) {
11953
+ throw new HttpError(
11954
+ 401,
11955
+ "Unauthorized",
11956
+ `No permissions found for ${clientApplication.name} in ${serverApplication.name}`,
11957
+ "MIAU_PERM_A"
11958
+ );
11959
+ }
11960
+ const permittedResources = permission?.resources || [];
11961
+ const resource = { protocol: "http", method, path };
11962
+ const isAllowed = isResourceAllowed(resource, resources, permittedResources);
11963
+ if (!isAllowed) {
11964
+ throw new HttpError(
11965
+ 403,
11966
+ "Forbidden",
11967
+ `${clientApplication.name} does not have permission to ${method} ${path} on ${serverApplication.name}`,
11968
+ "MIAU_PERM_B"
11969
+ );
11970
+ }
11971
+ const miauApplication = { id: clientApplication.id, name: clientApplication.name };
11972
+ const environment = miauClient.getEnvironment();
11973
+ const miauMetadata = permission?.metadata?.[environment] || {};
11974
+ return [miauApplication, miauMetadata];
11975
+ };
11919
11976
  var miauMiddleware = (miauClient, requestAugmentation, fallbackMiddleware) => {
11920
11977
  return async (req, res, next) => {
11921
11978
  try {
11922
- const token = req.headers.authorization?.split(" ").pop();
11923
- if (!token) {
11924
- throw new HttpError(400, "Invalid Token", "Token not provided");
11925
- }
11926
- const decodedToken = import_jsonwebtoken.default.decode(token, { complete: true });
11927
- if (!decodedToken) {
11928
- throw new HttpError(400, "Invalid Token", "Token could not be decoded");
11929
- }
11930
- if (!decodedToken.header?.kid) {
11931
- throw new HttpError(400, "Invalid Token", "Missing kid in token header");
11932
- }
11933
- if (decodedToken.payload.iss !== issuers["production"]) {
11934
- throw new HttpError(400, "Invalid Token", "Token issuer is invalid");
11935
- }
11936
- const publicKey = await miauClient.getPublicKey(decodedToken.header.kid);
11937
- const clientToken = import_jsonwebtoken.default.verify(token, publicKey, { algorithms: ["RS256"] });
11938
- if (!clientToken || !clientToken.application || !clientToken.secret || !clientToken.application.id || !clientToken.secret.id || !clientToken.secret.environment) {
11939
- throw new HttpError(400, "Invalid Token", "Token verification failed");
11940
- }
11941
- const { application, secret } = clientToken;
11942
- if (secret.environment != miauClient.getEnvironment()) {
11943
- throw new HttpError(
11944
- 400,
11945
- "Invalid Environment",
11946
- `Secret environment ${secret.environment} does not match client environment ${miauClient.getEnvironment()}`
11947
- );
11948
- }
11949
- const resources = await miauClient.getResources();
11950
- if (!resources) {
11951
- throw new HttpError(401, "Unauthorized", "No resources found for this application");
11952
- }
11953
- const permission = await miauClient.getPermissions(application.id);
11954
- if (!permission) {
11955
- throw new HttpError(401, "Unauthorized", "No permissions found for this application");
11956
- }
11957
- const permittedResources = permission?.resources || [];
11958
- if (!permittedResources.length) {
11959
- throw new HttpError(403, "Forbidden", "No resources are permitted for this application");
11960
- }
11961
- const resource = { protocol: "http", method: req.method, path: req.path };
11962
- const isAllowed = isResourceAllowed(resource, resources, permittedResources);
11963
- if (!isAllowed) {
11964
- throw new HttpError(403, "Forbidden", `You do not have permission to access ${req.method} ${req.path}`);
11965
- }
11966
- req.miauApplication = { id: application.id, name: application.name };
11967
- const environment = miauClient.getEnvironment();
11968
- req.miauMetadata = permission?.metadata?.[environment] || {};
11979
+ const token = req.headers.authorization?.split(" ").pop() ?? "";
11980
+ const [miauApplication, miauMetadata] = await auth(token, req.method, req.path, miauClient);
11981
+ req.miauApplication = miauApplication;
11982
+ req.miauMetadata = miauMetadata;
11969
11983
  if (requestAugmentation) {
11970
11984
  requestAugmentation({ req, app: req.miauApplication, meta: req.miauMetadata });
11971
11985
  }
@@ -11980,6 +11994,28 @@ var miauMiddleware = (miauClient, requestAugmentation, fallbackMiddleware) => {
11980
11994
  }
11981
11995
  };
11982
11996
  };
11997
+ var miauHook = (miauClient, requestAugmentation, fallbackMiddleware) => {
11998
+ return async (request, reply) => {
11999
+ try {
12000
+ const token = request.headers.authorization?.split(" ").pop() ?? "";
12001
+ const path = request.routeOptions.url ?? "";
12002
+ const [miauApplication, miauMetadata] = await auth(token, request.method, path, miauClient);
12003
+ request.miauApplication = miauApplication;
12004
+ request.miauMetadata = miauMetadata;
12005
+ if (requestAugmentation) {
12006
+ requestAugmentation({ req: request, app: request.miauApplication, meta: request.miauMetadata });
12007
+ }
12008
+ } catch (err) {
12009
+ if (err instanceof HttpError && err.status == 400 && fallbackMiddleware) {
12010
+ await fallbackMiddleware(request, reply);
12011
+ return;
12012
+ }
12013
+ const errorStatus = err.status || 403;
12014
+ reply.status(errorStatus).send({ error: err.name, message: err.message });
12015
+ return;
12016
+ }
12017
+ };
12018
+ };
11983
12019
 
11984
12020
  // src/MiauClient.ts
11985
12021
  var requestsCache = /* @__PURE__ */ new Map();
@@ -12022,6 +12058,13 @@ var expiresHeaderToUnixtime = (expires) => {
12022
12058
  };
12023
12059
  var MiauClient = class {
12024
12060
  constructor(config) {
12061
+ this.getTokenData = async () => {
12062
+ const token = await this.getToken();
12063
+ if (!token) {
12064
+ throw new Error("Token is undefined");
12065
+ }
12066
+ return import_jsonwebtoken2.default.decode(token);
12067
+ };
12025
12068
  this.getApiJwtUrl = () => {
12026
12069
  return `${this.config.apiUrl}/v1/jwt`;
12027
12070
  };
@@ -12081,6 +12124,9 @@ var MiauClient = class {
12081
12124
  middleware(config) {
12082
12125
  return miauMiddleware(this, config?.requestAugmentation, config?.fallbackMiddleware);
12083
12126
  }
12127
+ hook(config) {
12128
+ return miauHook(this, config?.requestAugmentation, config?.fallbackMiddleware);
12129
+ }
12084
12130
  async getResources() {
12085
12131
  return cacheableFetch(this.getResourcesUrl(), {
12086
12132
  headers: { Authorization: `Basic ${this.basicAuthToken}` }
@@ -12091,6 +12137,9 @@ var MiauClient = class {
12091
12137
  headers: { Authorization: `Basic ${this.basicAuthToken}` }
12092
12138
  });
12093
12139
  }
12140
+ async verify(token, publicKey) {
12141
+ return import_jsonwebtoken2.default.verify(token, publicKey, { algorithms: ["RS256"] });
12142
+ }
12094
12143
  };
12095
12144
  // Annotate the CommonJS export names for ESM import in node:
12096
12145
  0 && (module.exports = {