fix: base_url port
feat: add types for reasoning_content and _metadata fix: key format incompatibility
This commit is contained in:
parent
c7601b2270
commit
76703e2e3e
5 changed files with 54 additions and 7 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -7,3 +7,4 @@ coverage/
|
|||
.nyc_output/
|
||||
build/
|
||||
*.node
|
||||
settings.json
|
||||
|
|
@ -13,7 +13,7 @@ export class SecureChatCompletion {
|
|||
|
||||
constructor(config: ChatCompletionConfig = {}) {
|
||||
const {
|
||||
baseUrl = 'https://api.nomyo.ai:12434',
|
||||
baseUrl = 'https://api.nomyo.ai:12435',
|
||||
allowHttp = false,
|
||||
apiKey,
|
||||
secureMemory = true,
|
||||
|
|
|
|||
|
|
@ -64,9 +64,9 @@ export class SecureCompletionClient {
|
|||
private secureMemoryImpl = createSecureMemory();
|
||||
private readonly keySize: 2048 | 4096;
|
||||
|
||||
constructor(config: ClientConfig = { routerUrl: 'https://api.nomyo.ai:12434' }) {
|
||||
constructor(config: ClientConfig = { routerUrl: 'https://api.nomyo.ai:12435' }) {
|
||||
const {
|
||||
routerUrl = 'https://api.nomyo.ai:12434',
|
||||
routerUrl = 'https://api.nomyo.ai:12435',
|
||||
allowHttp = false,
|
||||
secureMemory = true,
|
||||
keySize = 4096,
|
||||
|
|
@ -174,7 +174,7 @@ export class SecureCompletionClient {
|
|||
throw new SecurityError(
|
||||
'Server public key must be fetched over HTTPS to prevent MITM attacks. ' +
|
||||
'For local development, initialize with allowHttp=true: ' +
|
||||
'new SecureChatCompletion({ baseUrl: "http://localhost:12434", allowHttp: true })'
|
||||
'new SecureChatCompletion({ baseUrl: "http://localhost:12435", allowHttp: true })'
|
||||
);
|
||||
} else {
|
||||
console.warn('Fetching key over HTTP (local development mode)');
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
import { RSAOperations } from './rsa';
|
||||
import { getCrypto } from './utils';
|
||||
import { KeyGenOptions, KeyPaths } from '../../types/client';
|
||||
|
||||
export class KeyManager {
|
||||
|
|
@ -66,8 +67,25 @@ export class KeyManager {
|
|||
const path = require('path');
|
||||
|
||||
// Load private key
|
||||
const privateKeyPem = await fs.readFile(paths.privateKeyPath, 'utf-8');
|
||||
this.privateKey = await this.rsa.importPrivateKey(privateKeyPem, password);
|
||||
const privateKeyPem = await fs.readFile(paths.privateKeyPath, 'utf-8') as string;
|
||||
|
||||
if (password && privateKeyPem.includes('BEGIN ENCRYPTED PRIVATE KEY')) {
|
||||
// Standard PKCS#8 encrypted format (produced by Python/OpenSSL)
|
||||
const { createPrivateKey } = require('crypto') as typeof import('crypto');
|
||||
const keyObject = createPrivateKey({ key: privateKeyPem, format: 'pem', passphrase: password });
|
||||
const pkcs8Der = keyObject.export({ type: 'pkcs8', format: 'der' }) as Buffer;
|
||||
const subtle = getCrypto();
|
||||
this.privateKey = await subtle.importKey(
|
||||
'pkcs8',
|
||||
pkcs8Der,
|
||||
{ name: 'RSA-OAEP', hash: 'SHA-256' },
|
||||
true,
|
||||
['decrypt']
|
||||
);
|
||||
} else {
|
||||
// Unencrypted PKCS#8 or legacy JS custom-encrypted format
|
||||
this.privateKey = await this.rsa.importPrivateKey(privateKeyPem, password);
|
||||
}
|
||||
|
||||
// Validate private key size (minimum 2048 bits)
|
||||
const privAlgorithm = this.privateKey.algorithm as RsaHashedKeyAlgorithm;
|
||||
|
|
@ -120,7 +138,17 @@ export class KeyManager {
|
|||
await fs.mkdir(directory, { recursive: true });
|
||||
|
||||
// Export and save private key
|
||||
const privateKeyPem = await this.rsa.exportPrivateKey(this.privateKey, password);
|
||||
let privateKeyPem: string;
|
||||
if (password) {
|
||||
// Use standard PKCS#8 encrypted format (compatible with Python/OpenSSL)
|
||||
const { createPrivateKey } = require('crypto') as typeof import('crypto');
|
||||
const subtle = getCrypto();
|
||||
const pkcs8Der = await subtle.exportKey('pkcs8', this.privateKey);
|
||||
const keyObject = createPrivateKey({ key: Buffer.from(pkcs8Der), format: 'der', type: 'pkcs8' });
|
||||
privateKeyPem = keyObject.export({ type: 'pkcs8', format: 'pem', cipher: 'aes-256-cbc', passphrase: password }) as string;
|
||||
} else {
|
||||
privateKeyPem = await this.rsa.exportPrivateKey(this.privateKey);
|
||||
}
|
||||
const privateKeyPath = path.join(directory, 'private_key.pem');
|
||||
await fs.writeFile(privateKeyPath, privateKeyPem, 'utf-8');
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ export interface Message {
|
|||
name?: string;
|
||||
tool_calls?: ToolCall[];
|
||||
tool_call_id?: string;
|
||||
/** Thinking-model reasoning output (Qwen3, DeepSeek-R1, etc.) */
|
||||
reasoning_content?: string;
|
||||
}
|
||||
|
||||
export interface ToolCall {
|
||||
|
|
@ -70,12 +72,28 @@ export interface Choice {
|
|||
logprobs?: unknown;
|
||||
}
|
||||
|
||||
export interface MemoryProtectionInfo {
|
||||
enabled: boolean;
|
||||
platform: string;
|
||||
protection_level: string;
|
||||
has_memory_locking: boolean;
|
||||
has_secure_zeroing: boolean;
|
||||
supports_full_protection: boolean;
|
||||
page_size?: number;
|
||||
}
|
||||
|
||||
export interface ResponseMetadata {
|
||||
payload_id: string;
|
||||
processed_at: number;
|
||||
is_encrypted: boolean;
|
||||
encryption_algorithm: string;
|
||||
response_status: string;
|
||||
/** Hardware routing tier used for this request */
|
||||
security_tier?: string;
|
||||
/** Server-side memory protection details */
|
||||
memory_protection?: MemoryProtectionInfo;
|
||||
/** CUDA device ID used for inference (if applicable) */
|
||||
cuda_device?: string | number;
|
||||
}
|
||||
|
||||
export interface ChatCompletionResponse {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue