1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | import { Call } from './call-stream';
|
19 | import { Channel } from './channel';
|
20 | import { BaseFilter, Filter, FilterFactory } from './filter';
|
21 | import { Metadata } from './metadata';
|
22 | import { Status } from './constants';
|
23 | import { splitHostPort } from './uri-parser';
|
24 | import { ServiceError } from './call';
|
25 |
|
26 | export class CallCredentialsFilter extends BaseFilter implements Filter {
|
27 | private serviceUrl: string;
|
28 | constructor(
|
29 | private readonly channel: Channel,
|
30 | private readonly stream: Call
|
31 | ) {
|
32 | super();
|
33 | this.channel = channel;
|
34 | this.stream = stream;
|
35 | const splitPath: string[] = stream.getMethod().split('/');
|
36 | let serviceName = '';
|
37 | |
38 |
|
39 |
|
40 | if (splitPath.length >= 2) {
|
41 | serviceName = splitPath[1];
|
42 | }
|
43 | const hostname = splitHostPort(stream.getHost())?.host ?? 'localhost';
|
44 | |
45 |
|
46 | this.serviceUrl = `https://${hostname}/${serviceName}`;
|
47 | }
|
48 |
|
49 | async sendMetadata(metadata: Promise<Metadata>): Promise<Metadata> {
|
50 | const credentials = this.stream.getCredentials();
|
51 | const credsMetadata = credentials.generateMetadata({
|
52 | service_url: this.serviceUrl,
|
53 | });
|
54 | const resultMetadata = await metadata;
|
55 | try {
|
56 | resultMetadata.merge(await credsMetadata);
|
57 | } catch (error) {
|
58 | this.stream.cancelWithStatus(
|
59 | Status.UNAUTHENTICATED,
|
60 | `Failed to retrieve auth metadata with error: ${error.message}`
|
61 | );
|
62 | return Promise.reject<Metadata>('Failed to retrieve auth metadata');
|
63 | }
|
64 | if (resultMetadata.get('authorization').length > 1) {
|
65 | this.stream.cancelWithStatus(
|
66 | Status.INTERNAL,
|
67 | '"authorization" metadata cannot have multiple values'
|
68 | );
|
69 | return Promise.reject<Metadata>(
|
70 | '"authorization" metadata cannot have multiple values'
|
71 | );
|
72 | }
|
73 | return resultMetadata;
|
74 | }
|
75 | }
|
76 |
|
77 | export class CallCredentialsFilterFactory
|
78 | implements FilterFactory<CallCredentialsFilter> {
|
79 | constructor(private readonly channel: Channel) {
|
80 | this.channel = channel;
|
81 | }
|
82 |
|
83 | createFilter(callStream: Call): CallCredentialsFilter {
|
84 | return new CallCredentialsFilter(this.channel, callStream);
|
85 | }
|
86 | }
|