001/*
002 *   Copyright 2024 Vonage
003 *
004 *   Licensed under the Apache License, Version 2.0 (the "License");
005 *   you may not use this file except in compliance with the License.
006 *   You may obtain a copy of the License at
007 *
008 *        http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *   Unless required by applicable law or agreed to in writing, software
011 *   distributed under the License is distributed on an "AS IS" BASIS,
012 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *   See the License for the specific language governing permissions and
014 *   limitations under the License.
015 */
016package com.vonage.client;
017
018import com.vonage.client.account.AccountClient;
019import com.vonage.client.application.ApplicationClient;
020import com.vonage.client.auth.*;
021import com.vonage.client.auth.hashutils.HashUtil;
022import com.vonage.client.camara.numberverification.NumberVerificationClient;
023import com.vonage.client.camara.simswap.SimSwapClient;
024import com.vonage.client.conversations.ConversationsClient;
025import com.vonage.client.conversion.ConversionClient;
026import com.vonage.client.insight.InsightClient;
027import com.vonage.client.meetings.MeetingsClient;
028import com.vonage.client.messages.MessagesClient;
029import com.vonage.client.numberinsight2.NumberInsight2Client;
030import com.vonage.client.numbers.NumbersClient;
031import com.vonage.client.proactiveconnect.ProactiveConnectClient;
032import com.vonage.client.redact.RedactClient;
033import com.vonage.client.sms.SmsClient;
034import com.vonage.client.subaccounts.SubaccountsClient;
035import com.vonage.client.users.UsersClient;
036import com.vonage.client.verify.VerifyClient;
037import com.vonage.client.video.VideoClient;
038import com.vonage.client.verify2.Verify2Client;
039import com.vonage.client.voice.VoiceClient;
040import org.apache.http.client.HttpClient;
041import java.io.IOException;
042import java.nio.file.*;
043import java.util.UUID;
044
045/**
046 * Top-level Vonage API client object.
047 * <p>
048 * Construct an instance of this object with one or more {@link AuthMethod}s (providing all the authentication methods
049 * for the APIs you wish to use), and then call {@link #getVoiceClient()} to obtain a client for the Vonage Voice API.
050 * <p>.
051 */
052public class VonageClient {
053    /**
054     * The HTTP wrapper for this client and its sub-clients.
055     */
056    final HttpWrapper httpWrapper;
057
058    private final AccountClient account;
059    private final ApplicationClient application;
060    private final InsightClient insight;
061    private final NumbersClient numbers;
062    private final SmsClient sms;
063    private final VoiceClient voice;
064    private final VerifyClient verify;
065    private final ConversionClient conversion;
066    private final RedactClient redact;
067    private final MessagesClient messages;
068    private final Verify2Client verify2;
069    private final SubaccountsClient subaccounts;
070    private final ProactiveConnectClient proactiveConnect;
071    private final MeetingsClient meetings;
072    private final UsersClient users;
073    private final VideoClient video;
074    private final NumberInsight2Client numberInsight2;
075    private final ConversationsClient conversations;
076    private final SimSwapClient simSwap;
077    private final NumberVerificationClient numberVerification;
078
079    /**
080     * Constructor which uses the builder pattern for instantiation.
081     *
082     * @param builder The builder object to use for configuration.
083     */
084    private VonageClient(Builder builder) {
085        httpWrapper = new HttpWrapper(builder.httpConfig, builder.authCollection);
086        if (builder.httpClient != null) {
087            httpWrapper.setHttpClient(builder.httpClient);
088        }
089
090        account = new AccountClient(httpWrapper);
091        application = new ApplicationClient(httpWrapper);
092        insight = new InsightClient(httpWrapper);
093        numbers = new NumbersClient(httpWrapper);
094        verify = new VerifyClient(httpWrapper);
095        voice = new VoiceClient(httpWrapper);
096        sms = new SmsClient(httpWrapper);
097        conversion = new ConversionClient(httpWrapper);
098        redact = new RedactClient(httpWrapper);
099        messages = new MessagesClient(httpWrapper);
100        verify2 = new Verify2Client(httpWrapper);
101        subaccounts = new SubaccountsClient(httpWrapper);
102        proactiveConnect = new ProactiveConnectClient(httpWrapper);
103        meetings = new MeetingsClient(httpWrapper);
104        users = new UsersClient(httpWrapper);
105        video = new VideoClient(httpWrapper);
106        numberInsight2 = new NumberInsight2Client(httpWrapper);
107        conversations = new ConversationsClient(httpWrapper);
108        simSwap = new SimSwapClient(httpWrapper);
109        numberVerification = new NumberVerificationClient(httpWrapper);
110    }
111
112    /**
113     * Returns the Account API client.
114     *
115     * @return The {@linkplain AccountClient}.
116     */
117    public AccountClient getAccountClient() {
118        return account;
119    }
120
121    /**
122     * Returns the Application API client.
123     *
124     * @return The {@linkplain ApplicationClient}.
125     */
126    public ApplicationClient getApplicationClient() {
127        return application;
128    }
129
130    /**
131     * Returns the Number Insight API client.
132     *
133     * @return The {@linkplain InsightClient}.
134     */
135    public InsightClient getInsightClient() {
136        return insight;
137    }
138
139    /**
140     * Returns the Numbers API client.
141     *
142     * @return The {@linkplain NumbersClient}.
143     */
144    public NumbersClient getNumbersClient() {
145        return numbers;
146    }
147
148    /**
149     * Returns the SMS API client.
150     *
151     * @return The {@linkplain SmsClient}.
152     */
153    public SmsClient getSmsClient() {
154        return sms;
155    }
156
157    /**
158     * Returns the Verify v1 API client.
159     *
160     * @return The {@linkplain VerifyClient}.
161     */
162    public VerifyClient getVerifyClient() {
163        return verify;
164    }
165
166    /**
167     * Returns the Voice API client.
168     *
169     * @return The {@linkplain VoiceClient}.
170     */
171    public VoiceClient getVoiceClient() {
172        return voice;
173    }
174
175    /**
176     * Returns the Conversion API client.
177     *
178     * @return The {@linkplain ConversionClient}.
179     */
180    public ConversionClient getConversionClient() {
181        return conversion;
182    }
183
184    /**
185     * Returns the Redact API client.
186     *
187     * @return The {@linkplain RedactClient}.
188     */
189    public RedactClient getRedactClient() {
190        return redact;
191    }
192
193    /**
194     * Returns the Messages v1 API client.
195     *
196     * @return The {@linkplain MessagesClient}.
197     * @since 6.5.0
198     */
199    public MessagesClient getMessagesClient() {
200        return messages;
201    }
202
203    /**
204     * Returns the Proactive Connect API client.
205     *
206     * @return The {@linkplain ProactiveConnectClient}.
207     * @since 7.6.0
208     * @deprecated This API is sunset and will be removed in the next major release.
209     */
210    @Deprecated
211    public ProactiveConnectClient getProactiveConnectClient() {
212        return proactiveConnect;
213    }
214
215    /**
216     * Returns the Meetings API client.
217     *
218     * @return The {@linkplain MeetingsClient}.
219     * @since 7.6.0
220     * @deprecated Support for this API will be removed in the next major release.
221     */
222    @Deprecated
223    public MeetingsClient getMeetingsClient() {
224        return meetings;
225    }
226
227    /**
228     * Returns the Verify v2 API client.
229     *
230     * @return The {@linkplain Verify2Client}.
231     * @since 7.4.0
232     */
233    public Verify2Client getVerify2Client() {
234        return verify2;
235    }
236
237    /**
238     * Returns the Subaccounts API client.
239     *
240     * @return The {@linkplain SubaccountsClient}.
241     * @since 7.5.0
242     */
243    public SubaccountsClient getSubaccountsClient() {
244        return subaccounts;
245    }
246
247    /**
248     * Returns the Users API client.
249     *
250     * @return The {@linkplain UsersClient}.
251     * @since 7.7.0
252     */
253    public UsersClient getUsersClient() {
254        return users;
255    }
256
257    /**
258     * Returns the Video API client.
259     *
260     * @return The {@linkplain VideoClient}.
261     * @since 8.0.0-beta1
262     */
263    public VideoClient getVideoClient() {
264        return video;
265    }
266
267    /**
268     * Returns the Fraud Detection API client.
269     *
270     * @return The {@linkplain NumberInsight2Client}.
271     * @since 8.2.0
272     */
273    public NumberInsight2Client getNumberInsight2Client() {
274        return numberInsight2;
275    }
276
277    /**
278     * Returns the Conversations v1 client.
279     *
280     * @return The Conversation client.
281     * @since 8.4.0
282     */
283    public ConversationsClient getConversationsClient() {
284        return conversations;
285    }
286
287    /**
288     * Returns the CAMARA SIM Swap API client.
289     *
290     * @return The {@linkplain SimSwapClient}.
291     * @since 8.8.0
292     */
293    public SimSwapClient getSimSwapClient() {
294        return simSwap;
295    }
296
297    /**
298     * Returns the CAMARA Number Verification API client.
299     *
300     * @return The {@linkplain NumberVerificationClient}.
301     * @since 8.9.0
302     */
303    public NumberVerificationClient getNumberVerificationClient() {
304        return numberVerification;
305    }
306
307    /**
308     * Generate a JWT for the application the client has been configured with.
309     *
310     * @return A String containing the token data.
311     *
312     * @throws VonageUnacceptableAuthException if no {@link JWTAuthMethod} is available
313     */
314    public String generateJwt() throws VonageUnacceptableAuthException {
315        return httpWrapper.getAuthCollection().getAuth(JWTAuthMethod.class).generateToken();
316    }
317
318    /**
319     * Entry point for constructing an instance of this class.
320     *
321     * @return A new Builder with default initial configuration.
322     */
323    public static Builder builder() {
324        return new Builder();
325    }
326
327    /**
328     * Builder for specifying the properties of the client.
329     */
330    public static class Builder {
331        private AuthCollection authCollection;
332        private HttpConfig httpConfig = HttpConfig.defaultConfig();
333        private HttpClient httpClient;
334        private String apiKey, apiSecret, signatureSecret;
335        private UUID applicationId;
336        private byte[] privateKeyContents;
337        private HashUtil.HashType hashType = HashUtil.HashType.MD5;
338
339        /**
340         * Configure the HTTP client parameters.
341         *
342         * @param httpConfig Configuration options for the {@link HttpWrapper}.
343         *
344         * @return This builder.
345         */
346        public Builder httpConfig(HttpConfig httpConfig) {
347            this.httpConfig = httpConfig;
348            return this;
349        }
350
351        /**
352         * Set the underlying HTTP client instance.
353         *
354         * @param httpClient Custom implementation of {@link HttpClient}.
355         *
356         * @return This builder.
357         *
358         * @deprecated This method will be removed in the next major release.
359         */
360        @Deprecated
361        public Builder httpClient(HttpClient httpClient) {
362            this.httpClient = httpClient;
363            return this;
364        }
365
366        /**
367         * Set the application ID for this client. This will be used alongside your private key
368         * (se via {@link #privateKeyContents}) for authenticating requests.
369         *
370         * @param applicationId The application UUID.
371         *
372         * @return This builder.
373         *
374         * @since 7.11.0
375         */
376        public Builder applicationId(UUID applicationId) {
377            this.applicationId = applicationId;
378            return this;
379        }
380
381        /**
382         * When setting an applicationId, it is also expected that the {@link #privateKeyContents} will also be set.
383         *
384         * @param applicationId Used to identify each application.
385         *
386         * @return This builder.
387         */
388        public Builder applicationId(String applicationId) {
389            return applicationId(UUID.fromString(applicationId));
390        }
391
392        /**
393         * When setting an apiKey, it is also expected that {@link #apiSecret(String)} and/or {@link
394         * #signatureSecret(String)} will also be set.
395         *
396         * @param apiKey The API Key found in the dashboard for your account.
397         *
398         * @return This builder.
399         */
400        public Builder apiKey(String apiKey) {
401            this.apiKey = apiKey;
402            return this;
403        }
404
405        /**
406         * When setting an apiSecret, it is also expected that {@link #apiKey(String)} will also be set.
407         *
408         * @param apiSecret The API Secret found in the dashboard for your account.
409         *
410         * @return This builder.
411         */
412        public Builder apiSecret(String apiSecret) {
413            this.apiSecret = apiSecret;
414            return this;
415        }
416
417        /**
418         * When setting a signatureSecret, it is also expected that {@link #apiKey(String)} will also be set.
419         *
420         * @param signatureSecret The Signature Secret found in the dashboard for your account.
421         *
422         * @return This builder.
423         */
424        public Builder signatureSecret(String signatureSecret) {
425            this.signatureSecret = signatureSecret;
426            return this;
427        }
428
429        /**
430         * Sets the hash type to use for signing requests.
431         *
432         * @param hashType The hashing strategy for signature keys as an enum.
433         *
434         * @return This builder.
435         */
436        public Builder hashType(HashUtil.HashType hashType) {
437            this.hashType = hashType;
438            return this;
439        }
440
441        /**
442         * When setting the contents of your private key, it is also expected that {@link #applicationId(String)} will
443         * also be set.
444         *
445         * @param privateKeyContents The contents of your private key used for JWT generation.
446         *
447         * @return This builder.
448         */
449        public Builder privateKeyContents(byte[] privateKeyContents) {
450            this.privateKeyContents = privateKeyContents;
451            return this;
452        }
453
454        /**
455         * When setting the contents of your private key, it is also expected that {@link #applicationId(String)} will
456         * also be set.
457         *
458         * @param privateKeyContents The contents of your private key used for JWT generation.
459         *
460         * @return This builder.
461         */
462        public Builder privateKeyContents(String privateKeyContents) {
463            return privateKeyContents(privateKeyContents.getBytes());
464        }
465
466        /**
467         * When setting the path of your private key, it is also expected that {@link #applicationId(String)} will also
468         * be set.
469         *
470         * @param privateKeyPath The path to your private key used for JWT generation.
471         *
472         * @return This builder.
473         *
474         * @throws VonageUnableToReadPrivateKeyException if the private key could not be read from the file system.
475         */
476        public Builder privateKeyPath(Path privateKeyPath) throws VonageUnableToReadPrivateKeyException {
477            try {
478                return privateKeyContents(Files.readAllBytes(privateKeyPath));
479            } catch (IOException e) {
480                throw new VonageUnableToReadPrivateKeyException("Unable to read private key at " + privateKeyPath, e);
481            }
482        }
483
484        /**
485         * When setting the path of your private key, it is also expected that {@link #applicationId(String)} will also
486         * be set.
487         *
488         * @param privateKeyPath The path to your private key used for JWT generation.
489         *
490         * @return This builder.
491         *
492         * @throws VonageUnableToReadPrivateKeyException if the private key could not be read from the file system.
493         */
494        public Builder privateKeyPath(String privateKeyPath) throws VonageUnableToReadPrivateKeyException {
495            return privateKeyPath(Paths.get(privateKeyPath));
496        }
497
498        /**
499         * Builds the client with this builder's parameters.
500         *
501         * @return A new {@link VonageClient} from the stored builder options.
502         *
503         * @throws VonageClientCreationException if credentials aren't provided in a valid pairing or there were issues
504         *                                      generating an {@link JWTAuthMethod} with the provided credentials.
505         */
506        public VonageClient build() {
507            try {
508                authCollection = new AuthCollection(
509                        applicationId, privateKeyContents,
510                        apiKey, apiSecret,
511                        hashType, signatureSecret
512                );
513            }
514            catch (IllegalStateException ex) {
515                throw new VonageClientCreationException("Failed to generate authentication methods.", ex);
516            }
517          
518            return new VonageClient(this);
519        }
520    }
521}