Skip to content

Commit

Permalink
chore: modify client for oauth
Browse files Browse the repository at this point in the history
  • Loading branch information
tiwarishubham635 committed Dec 4, 2024
1 parent 4916098 commit 54b5178
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 20 deletions.
76 changes: 58 additions & 18 deletions src/base/BaseTwilio.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import RequestClient from "./RequestClient"; /* jshint ignore:line */
import { HttpMethod } from "../interfaces"; /* jshint ignore:line */
import { Headers } from "../http/request"; /* jshint ignore:line */
import AuthStrategy from "../auth_strategy/AuthStrategy"; /* jshint ignore:line */
import CredentialProvider from "../credential_provider/CredentialProvider"; /* jshint ignore:line */

const os = require("os"); /* jshint ignore:line */
const url = require("url"); /* jshint ignore:line */
Expand Down Expand Up @@ -40,6 +42,7 @@ namespace Twilio {
uri?: string;
username?: string;
password?: string;
authStrategy?: AuthStrategy;
headers?: Headers;
params?: object;
data?: object;
Expand All @@ -56,9 +59,10 @@ namespace Twilio {
/* jshint ignore:end */

export class Client {
username: string;
password: string;
username?: string;
password?: string;
accountSid: string;
credentialProvider?: CredentialProvider;
opts?: ClientOpts;
env?: NodeJS.ProcessEnv;
edge?: string;
Expand Down Expand Up @@ -101,23 +105,23 @@ namespace Twilio {
/* jshint ignore:end */

constructor(username?: string, password?: string, opts?: ClientOpts) {
this.opts = opts || {};
this.env = this.opts.env || {};
this.setOpts(opts);
this.username =
username ??
this.env.TWILIO_ACCOUNT_SID ??
process.env.TWILIO_ACCOUNT_SID ??
(() => {
throw new Error("username is required");
})();
this.env?.TWILIO_ACCOUNT_SID ??
process.env.TWILIO_ACCOUNT_SID;
this.password =
password ??
this.env.TWILIO_AUTH_TOKEN ??
process.env.TWILIO_AUTH_TOKEN ??
(() => {
throw new Error("password is required");
})();
this.accountSid = this.opts.accountSid || this.username;
this.env?.TWILIO_AUTH_TOKEN ??
process.env.TWILIO_AUTH_TOKEN;
this.accountSid = "";
this.setAccountSid(this.opts?.accountSid || this.username);
this.invalidateOAuth();
}

setOpts(opts?: ClientOpts) {
this.opts = opts || {};
this.env = this.opts.env || {};
this.edge =
this.opts.edge ?? this.env.TWILIO_EDGE ?? process.env.TWILIO_EDGE;
this.region =
Expand All @@ -144,16 +148,35 @@ namespace Twilio {
if (this.opts.lazyLoading === false) {
this._httpClient = this.httpClient;
}
}

if (!this.accountSid.startsWith("AC")) {
const apiKeyMsg = this.accountSid.startsWith("SK")
setAccountSid(accountSid?: string) {
this.accountSid = accountSid || "";

if (this.accountSid && !this.accountSid?.startsWith("AC")) {
const apiKeyMsg = this.accountSid?.startsWith("SK")
? ". The given SID indicates an API Key which requires the accountSid to be passed as an additional option"
: "";

throw new Error("accountSid must start with AC" + apiKeyMsg);
}
}

setCredentialProvider(credentialProvider: CredentialProvider) {
this.credentialProvider = credentialProvider;
this.accountSid = "";
this.invalidateBasicAuth();
}

invalidateBasicAuth() {
this.username = undefined;
this.password = undefined;
}

invalidateOAuth() {
this.credentialProvider = undefined;
}

get httpClient() {
if (!this._httpClient) {
this._httpClient = new RequestClient({
Expand Down Expand Up @@ -196,6 +219,22 @@ namespace Twilio {

const username = opts.username || this.username;
const password = opts.password || this.password;
const authStrategy =
opts.authStrategy || this.credentialProvider?.toAuthStrategy();

if (!authStrategy) {
if (!username) {
(() => {
throw new Error("username is required");
})();
}

if (!password) {
(() => {
throw new Error("password is required");
})();
}
}

const headers = opts.headers || {};

Expand Down Expand Up @@ -223,7 +262,7 @@ namespace Twilio {
headers["Content-Type"] = "application/x-www-form-urlencoded";
}

if (!headers["Accept"]) {
if (opts.method !== "delete" && !headers["Accept"]) {
headers["Accept"] = "application/json";
}

Expand All @@ -235,6 +274,7 @@ namespace Twilio {
uri: uri.href,
username: username,
password: password,
authStrategy: authStrategy,
headers: headers,
params: opts.params,
data: opts.data,
Expand Down
2 changes: 2 additions & 0 deletions src/base/Page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@ export default class Page<
if (keys.length === 1) {
return payload[keys[0]];
}
for (const key of keys)
if (Array.isArray(payload[key])) return payload[key];

throw new Error("Page Records cannot be deserialized");
}
Expand Down
12 changes: 10 additions & 2 deletions src/base/RequestClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import qs from "qs";
import * as https from "https";
import Response from "../http/response";
import Request, {
RequestOptions as LastRequestOptions,
Headers,
RequestOptions as LastRequestOptions,
} from "../http/request";
import AuthStrategy from "../auth_strategy/AuthStrategy";

const DEFAULT_CONTENT_TYPE = "application/x-www-form-urlencoded";
const DEFAULT_TIMEOUT = 30000;
Expand Down Expand Up @@ -149,6 +150,7 @@ class RequestClient {
* @param opts.uri - The request uri
* @param opts.username - The username used for auth
* @param opts.password - The password used for auth
* @param opts.authStrategy - The authStrategy for API call
* @param opts.headers - The request headers
* @param opts.params - The request params
* @param opts.data - The request data
Expand All @@ -157,7 +159,7 @@ class RequestClient {
* @param opts.forever - Set to true to use the forever-agent
* @param opts.logLevel - Show debug logs
*/
request<TData>(
async request<TData>(
opts: RequestClient.RequestOptions<TData>
): Promise<Response<TData>> {
if (!opts.method) {
Expand All @@ -180,6 +182,8 @@ class RequestClient {
"base64"
);
headers.Authorization = "Basic " + auth;
} else if (opts.authStrategy) {
headers.Authorization = await opts.authStrategy.getAuthString();
}

const options: AxiosRequestConfig = {
Expand Down Expand Up @@ -296,6 +300,10 @@ namespace RequestClient {
* The password used for auth
*/
password?: string;
/**
* The AuthStrategy for API Call
*/
authStrategy?: AuthStrategy;
/**
* The request headers
*/
Expand Down
13 changes: 13 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import * as taskRouterUtil from "./jwt/taskrouter/util";
import IVoiceResponse from "./twiml/VoiceResponse";
import IMessagingResponse from "./twiml/MessagingResponse";
import IFaxResponse from "./twiml/FaxResponse";
import IClientCredentialProvider from "./credential_provider/ClientCredentialProvider";
import INoAuthCredentialProvider from "./credential_provider/NoAuthCredentialProvider";

// Shorthand to automatically create a RestClient
function TwilioSDK(
Expand Down Expand Up @@ -44,6 +46,17 @@ namespace TwilioSDK {
}
export type RequestClient = IRequestClient;
export const RequestClient = IRequestClient;

export type ClientCredentialProviderBuilder =
IClientCredentialProvider.ClientCredentialProviderBuilder;
export const ClientCredentialProviderBuilder =
IClientCredentialProvider.ClientCredentialProviderBuilder;

export type NoAuthCredentialProvider =
INoAuthCredentialProvider.NoAuthCredentialProvider;
export const NoAuthCredentialProvider =
INoAuthCredentialProvider.NoAuthCredentialProvider;

// Setup webhook helper functionality
export type validateBody = typeof webhooks.validateBody;
export const validateBody = webhooks.validateBody;
Expand Down

0 comments on commit 54b5178

Please sign in to comment.