Skip to content

Commit 1559517

Browse files
committed
freebuff: Block non-US/CA IPs
1 parent 9295e16 commit 1559517

File tree

7 files changed

+123
-35
lines changed

7 files changed

+123
-35
lines changed

bun.lock

Lines changed: 30 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,37 @@
11
import { afterEach, beforeEach, describe, expect, mock, test } from 'bun:test'
22

3+
import { useChatStore } from '../../state/chat-store'
4+
35
import type { RouterParams } from '../command-registry'
4-
import * as analytics from '../../utils/analytics'
56

6-
const setInputMode = mock(() => {})
7-
const setMessages = mock(() => {})
87
const saveToHistory = mock(() => {})
98
const setInputValue = mock(() => {})
9+
const setMessages = mock(() => {})
1010
const handleChatGptAuthCode = mock(async () => ({
1111
success: true,
1212
message: 'ok',
1313
}))
1414

15-
mock.module('../../state/chat-store', () => ({
16-
useChatStore: {
17-
getState: () => ({
18-
inputMode: 'connect:chatgpt',
19-
setInputMode,
20-
pendingAttachments: [],
21-
}),
22-
},
23-
}))
24-
2515
mock.module('../../components/chatgpt-connect-banner', () => ({
2616
handleChatGptAuthCode,
2717
}))
2818

29-
mock.module('../../utils/analytics', () => ({
30-
...analytics,
31-
trackEvent: () => {},
32-
}))
33-
3419
mock.module('@codebuff/common/constants/chatgpt-oauth', () => ({
3520
CHATGPT_OAUTH_ENABLED: true,
3621
}))
3722

3823
describe('routeUserPrompt connect:chatgpt mode', () => {
3924
beforeEach(() => {
40-
setInputMode.mockClear()
41-
setMessages.mockClear()
25+
useChatStore.getState().reset()
26+
useChatStore.getState().setInputMode('connect:chatgpt')
4227
saveToHistory.mockClear()
4328
setInputValue.mockClear()
29+
setMessages.mockClear()
4430
handleChatGptAuthCode.mockClear()
4531
})
4632

4733
afterEach(() => {
48-
setInputMode.mockClear()
49-
setMessages.mockClear()
50-
saveToHistory.mockClear()
51-
setInputValue.mockClear()
52-
handleChatGptAuthCode.mockClear()
34+
useChatStore.getState().reset()
5335
})
5436

5537
test('when in connect:chatgpt mode, it exchanges the auth code and updates messages', async () => {
@@ -82,6 +64,6 @@ describe('routeUserPrompt connect:chatgpt mode', () => {
8264

8365
expect(handleChatGptAuthCode).toHaveBeenCalledWith('auth-code-123')
8466
expect(setMessages).toHaveBeenCalled()
85-
expect(setInputMode).toHaveBeenCalledWith('default')
67+
expect(useChatStore.getState().inputMode).toBe('default')
8668
})
8769
})

cli/src/hooks/helpers/send-message.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import { processBashContext } from '../../utils/bash-context-processor'
66
import { markRunningAgentsAsCancelled } from '../../utils/block-operations'
77
import {
88
isOutOfCreditsError,
9+
isFreeModeUnavailableError,
910
OUT_OF_CREDITS_MESSAGE,
11+
FREE_MODE_UNAVAILABLE_MESSAGE,
1012
} from '../../utils/error-handling'
1113
import { formatElapsedTime } from '../../utils/format-elapsed-time'
1214
import { processImagesForMessage } from '../../utils/image-processor'
@@ -336,6 +338,12 @@ export const handleRunCompletion = (params: {
336338
return
337339
}
338340

341+
if (isFreeModeUnavailableError(output)) {
342+
updater.setError(FREE_MODE_UNAVAILABLE_MESSAGE)
343+
finalizeAfterError()
344+
return
345+
}
346+
339347
// Pass the raw error message to setError (displayed in UserErrorBanner without additional wrapper formatting)
340348
updater.setError(output.message ?? DEFAULT_RUN_OUTPUT_ERROR_MESSAGE)
341349

@@ -418,6 +426,11 @@ export const handleRunError = (params: {
418426
return
419427
}
420428

429+
if (isFreeModeUnavailableError(error)) {
430+
updater.setError(FREE_MODE_UNAVAILABLE_MESSAGE)
431+
return
432+
}
433+
421434
// Use setError for all errors so they display in UserErrorBanner consistently
422435
const errorMessage = errorInfo.message || 'An unexpected error occurred'
423436
updater.setError(errorMessage)

cli/src/utils/error-handling.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,29 @@ export const isOutOfCreditsError = (error: unknown): boolean => {
3737
return false
3838
}
3939

40+
/**
41+
* Check if an error indicates free mode is not available in the user's country.
42+
* Standardized on statusCode === 403 + error === 'free_mode_unavailable'.
43+
*/
44+
export const isFreeModeUnavailableError = (error: unknown): boolean => {
45+
if (
46+
error &&
47+
typeof error === 'object' &&
48+
'statusCode' in error &&
49+
(error as { statusCode: unknown }).statusCode === 403 &&
50+
'error' in error &&
51+
(error as { error: unknown }).error === 'free_mode_unavailable'
52+
) {
53+
return true
54+
}
55+
return false
56+
}
57+
4058
export const OUT_OF_CREDITS_MESSAGE = `Out of credits. Please add credits at ${defaultAppUrl}/usage`
4159

60+
export const FREE_MODE_UNAVAILABLE_MESSAGE =
61+
'Free mode is not available outside of the United States and Canada. Please upgrade to a paid plan to use Codebuff outside the US and Canada.'
62+
4263
export const createErrorMessage = (
4364
error: unknown,
4465
aiMessageId: string,

web/next.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ const nextConfig = {
3636
'encoding',
3737
'perf_hooks',
3838
'async_hooks',
39+
'geoip-lite',
3940
)
4041

4142
// Externalize code-map package to avoid bundling tree-sitter WASM files

0 commit comments

Comments
 (0)