Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: restricted api support #511

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions src/modules/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import type { Ky } from '../types'
import { http } from '../utils/http'
import { BeeError, BeeUnauthorizedError } from '../utils/error'

const AUTH_ENDPOINT = 'auth'
const REFRESH_ENDPOINT = 'refresh'

/**
* Authenticate with Bee node retrieving Bearer token that needs to be used for all requests.
*
* @param ky Ky instance
* @param password Admin password configured in Bee node configuration
* @param role Role of the generated Bearer token
* @param expiry Time in seconds
* @returns string Bearer token that can be used for future requests
*/
export async function authenticate(ky: Ky, password: string, role: string, expiry: number): Promise<string> {
try {
const response = await http<{ key: string }>(ky, {
path: AUTH_ENDPOINT,
method: 'post',
responseType: 'json',
json: {
role,
expiry,
},
headers: {
// There is no user in the authorization in Bee so we are passing only "_" as placeholder
Authorization: `Basic ${Buffer.from('_:' + password).toString('base64')}`,
},
})

return response.data.key
} catch (e) {
if (e instanceof BeeUnauthorizedError) {
throw new BeeError('Incorrect password')
}

throw e
}
}

/**
* Authenticate with Bee node retrieving Bearer token that needs to be used for all requests.
*
* @param ky Ky instance
* @param password Admin password configured in Bee node configuration
* @param role Role of the generated Bearer token
* @param expiry Time in seconds
* @returns string Bearer token that can be used for future requests
*/
export async function refresh(ky: Ky, password: string, role: string, expiry: number): Promise<string> {
try {
const response = await http<{ key: string }>(ky, {
path: REFRESH_ENDPOINT,
method: 'post',
responseType: 'json',
json: {
role,
expiry,
},
headers: {
// There is no user in the authorization in Bee so we are passing only "_" as placeholder
Authorization: `Basic ${Buffer.from('_:' + password).toString('base64')}`,
},
})

return response.data.key
} catch (e) {
if (e instanceof BeeUnauthorizedError) {
throw new BeeError('Incorrect password')
}

throw e
}
}
6 changes: 6 additions & 0 deletions src/utils/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,9 @@ export class BeeResponseError extends BeeError {
super(message)
}
}

export class BeeUnauthorizedError extends BeeError {
public constructor() {
super("Bee is in restricted mode and there was no token passed or token's role is insufficient for the operation.")
}
}
6 changes: 5 additions & 1 deletion src/utils/http.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BeeError, BeeRequestError, BeeResponseError } from './error'
import { BeeError, BeeRequestError, BeeResponseError, BeeUnauthorizedError } from './error'
import type { BeeRequest, BeeResponse, HookCallback, HttpMethod, Ky } from '../types'
import kyFactory, { Options as KyOptions } from 'ky-universal'
import { normalizeToReadableStream } from './stream'
Expand Down Expand Up @@ -121,6 +121,10 @@ export async function http<T>(ky: Ky, config: HttpOptions): Promise<KyResponse<T
return response
} catch (e) {
if (e.response) {
if (e.response.status === 401) {
throw new BeeUnauthorizedError()
}

const message = (await e.response.json()).message

if (message) {
Expand Down