Skip to content

Commit

Permalink
- fix: added safe url join to avoid double slash in api calls (#104)
Browse files Browse the repository at this point in the history
  • Loading branch information
agallardol authored Dec 6, 2023
1 parent 0e7ad83 commit 389ec47
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 14 deletions.
5 changes: 4 additions & 1 deletion libs/shinkai-message-ts/src/api/api_config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { urlJoin } from "../utils/url-join";

export class ApiConfig {
private static instance: ApiConfig;
private API_ENDPOINT: string;
Expand All @@ -14,7 +16,8 @@ export class ApiConfig {
}

public setEndpoint(endpoint: string) {
this.API_ENDPOINT = endpoint;
// hack to sanitize/remove '/' at the end
this.API_ENDPOINT = urlJoin(endpoint);
}

public getEndpoint() {
Expand Down
27 changes: 14 additions & 13 deletions libs/shinkai-message-ts/src/api/methods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { APIUseRegistrationCodeSuccessResponse } from '../models/Payloads';
import { SerializedAgent } from '../models/SchemaTypes';
import { InboxNameWrapper } from '../pkg/shinkai_message_wasm';
import { calculateMessageHash } from '../utils';
import { urlJoin } from '../utils/url-join';
import { FileUploader } from '../wasm/FileUploaderUsingSymmetricKeyManager';
import { SerializedAgentWrapper } from '../wasm/SerializedAgentWrapper';
import { ShinkaiMessageBuilderWrapper } from '../wasm/ShinkaiMessageBuilderWrapper';
Expand Down Expand Up @@ -87,7 +88,7 @@ export const createChatWithMessage = async (
const message: ShinkaiMessage = JSON.parse(messageStr);

const apiEndpoint = ApiConfig.getInstance().getEndpoint();
const response = await fetch(`${apiEndpoint}/v1/send`, {
const response = await fetch(urlJoin(apiEndpoint, '/v1/send'), {
method: 'POST',
body: JSON.stringify(message),
headers: { 'Content-Type': 'application/json' },
Expand Down Expand Up @@ -132,7 +133,7 @@ export const sendTextMessageWithInbox = async (
const message: ShinkaiMessage = JSON.parse(messageStr);

const apiEndpoint = ApiConfig.getInstance().getEndpoint();
const response = await fetch(`${apiEndpoint}/v1/send`, {
const response = await fetch(urlJoin(apiEndpoint, '/v1/send'), {
method: 'POST',
body: JSON.stringify(message),
headers: { 'Content-Type': 'application/json' },
Expand Down Expand Up @@ -215,7 +216,7 @@ export const getAllInboxesForProfile = async (

const apiEndpoint = ApiConfig.getInstance().getEndpoint();
const response = await fetch(
`${apiEndpoint}/v1/get_all_smart_inboxes_for_profile`,
urlJoin(apiEndpoint, '/v1/get_all_smart_inboxes_for_profile'),
{
method: 'POST',
body: JSON.stringify(message),
Expand Down Expand Up @@ -256,7 +257,7 @@ export const updateInboxName = async (
const message = JSON.parse(messageString);

const apiEndpoint = ApiConfig.getInstance().getEndpoint();
const response = await fetch(`${apiEndpoint}/v1/update_smart_inbox_name`, {
const response = await fetch(urlJoin(apiEndpoint, '/v1/update_smart_inbox_name'), {
method: 'POST',
body: JSON.stringify(message),
headers: { 'Content-Type': 'application/json' },
Expand Down Expand Up @@ -293,7 +294,7 @@ export const getLastMessagesFromInbox = async (
const message = JSON.parse(messageStr);

const apiEndpoint = ApiConfig.getInstance().getEndpoint();
const response = await fetch(`${apiEndpoint}/v1/last_messages_from_inbox`, {
const response = await fetch(urlJoin(apiEndpoint, '/v1/last_messages_from_inbox'), {
method: 'POST',
body: JSON.stringify(message),
headers: { 'Content-Type': 'application/json' },
Expand Down Expand Up @@ -333,7 +334,7 @@ export const submitRequestRegistrationCode = async (
const message = JSON.parse(messageStr);

const apiEndpoint = ApiConfig.getInstance().getEndpoint();
const response = await fetch(`${apiEndpoint}/v1/create_registration_code`, {
const response = await fetch(urlJoin(apiEndpoint, '/v1/create_registration_code'), {
method: 'POST',
body: JSON.stringify(message),
headers: { 'Content-Type': 'application/json' },
Expand Down Expand Up @@ -373,7 +374,7 @@ export const submitRegistrationCode = async (

// Use node_address from setupData for API endpoint
const response = await fetch(
`${setupData.node_address}/v1/use_registration_code`,
urlJoin(setupData.node_address, '/v1/use_registration_code'),
{
method: 'POST',
body: JSON.stringify(message),
Expand Down Expand Up @@ -415,7 +416,7 @@ export const submitInitialRegistrationNoCode = async (

// Use node_address from setupData for API endpoint
const response = await fetch(
`${setupData.node_address}/v1/use_registration_code`,
urlJoin(setupData.node_address, '/v1/use_registration_code'),
{
method: 'POST',
body: JSON.stringify(message),
Expand Down Expand Up @@ -471,7 +472,7 @@ export const createJob = async (
const message = JSON.parse(messageStr);

const apiEndpoint = ApiConfig.getInstance().getEndpoint();
const response = await fetch(`${apiEndpoint}/v1/create_job`, {
const response = await fetch(urlJoin(apiEndpoint, '/v1/create_job'), {
method: 'POST',
body: JSON.stringify(message),
headers: { 'Content-Type': 'application/json' },
Expand Down Expand Up @@ -512,7 +513,7 @@ export const sendMessageToJob = async (
const message = JSON.parse(messageStr);

const apiEndpoint = ApiConfig.getInstance().getEndpoint();
const response = await fetch(`${apiEndpoint}/v1/job_message`, {
const response = await fetch(urlJoin(apiEndpoint, '/v1/job_message'), {
method: 'POST',
body: JSON.stringify(message),
headers: { 'Content-Type': 'application/json' },
Expand Down Expand Up @@ -548,7 +549,7 @@ export const getProfileAgents = async (
console.log('Get Profile Agents Message Hash:', messageHash);

const apiEndpoint = ApiConfig.getInstance().getEndpoint();
const response = await fetch(`${apiEndpoint}/v1/available_agents`, {
const response = await fetch(urlJoin(apiEndpoint, '/v1/available_agents'), {
method: 'POST',
body: JSON.stringify(message),
headers: { 'Content-Type': 'application/json' },
Expand Down Expand Up @@ -583,7 +584,7 @@ export const addAgent = async (
const message = JSON.parse(messageStr);

const apiEndpoint = ApiConfig.getInstance().getEndpoint();
const response = await fetch(`${apiEndpoint}/v1/add_agent`, {
const response = await fetch(urlJoin(apiEndpoint, '/v1/add_agent'), {
method: 'POST',
body: JSON.stringify(message),
headers: { 'Content-Type': 'application/json' },
Expand Down Expand Up @@ -627,7 +628,7 @@ export const getFileNames = async (

const apiEndpoint = ApiConfig.getInstance().getEndpoint();
const response = await fetch(
`${apiEndpoint}/v1/get_filenames_for_file_inbox`,
urlJoin(apiEndpoint, '/v1/get_filenames_for_file_inbox'),
{
method: 'POST',
body: JSON.stringify(message),
Expand Down
19 changes: 19 additions & 0 deletions libs/shinkai-message-ts/src/utils/url-join.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { urlJoin } from './url-join';

describe('url join', () => {
const sharedExpectedValue = 'localhost:5555/api/v1/send';
const cases = [
{ data: ['localhost:5555', 'api', 'v1/send'], expectedValue: sharedExpectedValue },
{ data: ['localhost:5555/', '/api/', 'v1/send/'], expectedValue: sharedExpectedValue },
{ data: ['localhost:5555///', 'api//', '/v1/send'], expectedValue: sharedExpectedValue },
{ data: ['localhost:5555', 'api//', '//v1/send/'], expectedValue: sharedExpectedValue },
{ data: ['localhost:5555', 'api//', '//v1/send?foo=bar/bar2'], expectedValue: `${sharedExpectedValue}?foo=bar/bar2` },
{ data: ['localhost:5555', '/', ''], expectedValue: 'localhost:5555' },
{ data: ['localhost:5555'], expectedValue: 'localhost:5555' },
{ data: ['https://google.com/', 'auth/', 'foo'], expectedValue: 'https://google.com/auth/foo' },
];
test.each(cases)('should generate a valid url', async ({ data, expectedValue }) => {
const url = urlJoin(...data);
expect(url).toBe(expectedValue);
});
});
5 changes: 5 additions & 0 deletions libs/shinkai-message-ts/src/utils/url-join.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// It safe join url chunks avoiding double '/' between paths
// Warning: It doesn't supports all cases but it's enough for join shinkai-node api urls
export const urlJoin = (...chunks: string[]): string => {
return chunks.map(chunk => chunk.replace(/(^\/+|\/+$)/mg, '')).filter(chunk => !!chunk).join('/')
};

0 comments on commit 389ec47

Please sign in to comment.