UNPKG

oracledb

Version:

A Node.js module for Oracle Database access from JavaScript and TypeScript

439 lines (365 loc) 12.1 kB
// Copyright (c) 2022, 2025, Oracle and/or its affiliates. //----------------------------------------------------------------------------- // // This software is dual-licensed to you under the Universal Permissive License // (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License // 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose // either license. // // If you elect to accept the software under the Apache License, Version 2.0, // the following applies: // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //----------------------------------------------------------------------------- 'use strict'; const errors = require("../../errors.js"); const constants = require("./constants.js"); const AUTHENTICATION = 1; const ENCRYPTION = 2; const DATAINTEGRITY = 3; const SUPERVISOR = 4; const MAGIC = 0xdeadbeef; const NO_ERROR = 0; const SUPERVISOR_OK = 0x1f; const AUTHENTICATION_OK = 0xfaff; const AUTHENTICATION_DONT_USE_AUTH = 0xfbff; const HEADER_SIZE = 4 + 2 + 4 + 2 + 1; /* magic + length + version + services + flag */ const SERVICE_HEADER_SIZE = 2 + 2 + 4; /* service type + no of subpackets + error */ const ARRAY_PACKET_SIZE = 4 + 2 + 4; /* magic + ub2 + ub4 */ const SUBPACKET_SIZE = 4; const VERSION_LENGTH = 4; const VERSION = 0x17700000 ; /* Version 23.7.0.0.0 */ const STRING_TYPE = 0; const RAW_TYPE = 1; const UB1_TYPE = 2; const UB2_TYPE = 3; const VERSION_TYPE = 5; const STATUS_TYPE = 6; const CID_SIZE = 8; const CLIENT_SERVER = 0xe0e1; /* cli/svr connection */ const AUTH_NOT_REQUIRED = 0xfcff; /* Auth. not required */ const AUTH_TCPS_ID = 2; const AUTH_TCPS_NAME = "tcps"; const serviceMap = [-1, 0, 1, 2, 3]; class NetworkService { constructor(sAtts) { this.flags = constants.NSINAWANTED; this.sAtts = sAtts; } getDataSize() { return SERVICE_HEADER_SIZE + SUBPACKET_SIZE + VERSION_LENGTH + SUBPACKET_SIZE; } sendHeader(buf, pos) { pos = buf.writeUInt16BE(this.service, pos); pos = buf.writeUInt16BE(this.numSubPackets, pos); pos = buf.writeUInt32BE(0, pos); return pos; } sendVersion(buf, pos) { pos = buf.writeUInt16BE(4, pos); pos = buf.writeUInt16BE(VERSION_TYPE, pos); pos = buf.writeUInt32BE(VERSION, pos); return pos; } sendRaw(buf, rawData, length, pos) { pos = buf.writeUInt16BE(length, pos); pos = buf.writeUInt16BE(RAW_TYPE, pos); pos += rawData.copy(buf, pos, 0, length); return pos; } sendArray(buf, array, pos) { pos = buf.writeUInt16BE(ARRAY_PACKET_SIZE + array.length * 2, pos); pos = buf.writeUInt16BE(RAW_TYPE, pos); pos = buf.writeUInt32BE(MAGIC, pos); pos = buf.writeUInt16BE(UB2_TYPE, pos); pos = buf.writeUInt32BE(array.length, pos); for (let i = 0; i < array.length; i++) { pos = buf.writeUInt16BE(array[i], pos); } return pos; } sendStatus(buf, status, pos) { pos = buf.writeUInt16BE(2, pos); pos = buf.writeUInt16BE(STATUS_TYPE, pos); pos = buf.writeUInt16BE(status, pos); return pos; } sendString(buf, string, pos) { pos = buf.writeUInt16BE(string.length, pos); pos = buf.writeUInt16BE(STRING_TYPE, pos); pos += buf.write(string, pos); return pos; } sendUB1(buf, data, pos) { pos = buf.writeUInt16BE(1, pos); pos = buf.writeUInt16BE(UB1_TYPE, pos); pos = buf.writeUInt8(data, pos); return pos; } sendUB2(buf, data, pos) { pos = buf.writeUInt16BE(2, pos); pos = buf.writeUInt16BE(UB2_TYPE, pos); pos = buf.writeUInt16BE(data, pos); return pos; } static receiveHeader(pkt, ret, pos) { ret[0] = pkt.readUInt16BE(pos); pos += 2; ret[1] = pkt.readUInt16BE(pos); pos += 2; ret[2] = pkt.readUInt32BE(pos); pos += 4; return pos; } receiveType(pkt, type, ret, pos) { const len = pkt.readUInt16BE(pos); pos += 2; const receivedType = pkt.readUInt16BE(pos); pos += 2; if (receivedType != type) { errors.throwErr(errors.ERR_ANO_PACKET); } let version, status; switch (type) { case VERSION_TYPE: version = pkt.readUInt32BE(pos); pos += 4; ret[0] = version; return pos; case STATUS_TYPE: status = pkt.readUInt16BE(pos); pos += 2; ret[0] = status; return pos; case RAW_TYPE: ret[0] = len; return pos; case STRING_TYPE: ret[0] = len; return pos; } } receiveUB2Array(pkt, ret, pos) { const ret1 = []; pos = this.receiveType(pkt, RAW_TYPE, ret1, pos); if (pkt.readUInt32BE(pos) != MAGIC) { errors.throwErr(errors.ERR_ANO_PACKET); } pos += 4; const type = pkt.readUInt16BE(pos); pos += 2; if (type != UB2_TYPE) { errors.throwErr(errors.ERR_ANO_PACKET); } const arrayLen = pkt.readUInt32BE(pos); pos += 4; for (let i = 0; i < arrayLen; i++) { ret[i] = pkt.readUInt16BE(pos); pos += 2; } return pos; } receiveString(pkt, ret, pos) { const ret1 = []; pos = this.receiveType(pkt, STRING_TYPE, ret1, pos); const string = pkt.toString('utf8', pos, pos + ret1[0]); pos += ret1[0]; ret[0] = string; return pos; } receiveServiceData(pkt, numSubPakcets, pos) { const ret = []; ret[0] = pkt.readUInt16BE(pos); pos += 2; ret[1] = pkt.readUInt16BE(pos); pos += 2; ret[2] = pkt.readUInt32BE(pos); pos += 4; ret[3] = pkt.readUInt16BE(pos); pos += 2; ret[4] = pkt.readUInt16BE(pos); pos += 2; ret [5] = pkt.readUInt8(pos); pos += 1; return pos; } } class SupervisorService extends NetworkService { constructor(sAtts) { super(sAtts); this.service = SUPERVISOR; this.serviceList = [AUTHENTICATION, ENCRYPTION, DATAINTEGRITY, SUPERVISOR]; this.numSubPackets = 3; /* version, raw, services array */ } getDataSize() { return SERVICE_HEADER_SIZE + SUBPACKET_SIZE + VERSION_LENGTH + SUBPACKET_SIZE + CID_SIZE + SUBPACKET_SIZE + ARRAY_PACKET_SIZE + this.serviceList.length * 2; } sendServiceData(buf, pos) { pos = this.sendHeader(buf, pos); pos = this.sendVersion(buf, pos); pos = this.sendRaw(buf, Buffer.from(this.sAtts.uuid, "base64"), 8, pos); pos = this.sendArray(buf, this.serviceList, pos); return pos; } receiveServiceData(pkt, numSubPackets, pos) { const serverServices = [], version = [], status = []; pos = this.receiveType(pkt, VERSION_TYPE, version, pos); pos = this.receiveType(pkt, STATUS_TYPE, status, pos); if (status[0] != SUPERVISOR_OK) { errors.throwErr(errors.ERR_ANO_STATUS, "Supervisor"); } pos = this.receiveUB2Array(pkt, serverServices, pos); return pos; } } class AuthenticationService extends NetworkService { constructor(sAtts) { super(sAtts); this.service = AUTHENTICATION; this.status = AUTH_NOT_REQUIRED; this.numSubPackets = 3 + 1 * 2; /* We support only tcps */ this.serviceList = [AUTH_TCPS_NAME]; this.authActivated = false; } getDataSize() { let len = SERVICE_HEADER_SIZE + SUBPACKET_SIZE + VERSION_LENGTH + SUBPACKET_SIZE + 2 + SUBPACKET_SIZE + 2; for (let i = 0; i < this.serviceList.length; i++) { len += SUBPACKET_SIZE + 1; len += SUBPACKET_SIZE + this.serviceList[i].length; } return len; } sendServiceData(buf, pos) { pos = this.sendHeader(buf, pos); pos = this.sendVersion(buf, pos); pos = this.sendUB2(buf, CLIENT_SERVER, pos); pos = this.sendStatus(buf, this.status, pos); /* send Auth drivers - we support only tcps */ pos = this.sendUB1(buf, AUTH_TCPS_ID, pos); pos = this.sendString(buf, AUTH_TCPS_NAME, pos); return pos; } receiveServiceData(pkt, numSubPackets, pos) { const version = [], status = [], service = []; pos = this.receiveType(pkt, VERSION_TYPE, version, pos); pos = this.receiveType(pkt, STATUS_TYPE, status, pos); if (status[0] == AUTHENTICATION_OK && numSubPackets > 2) { pos += 5; pos = this.receiveString(pkt, service, pos); this.authActivated = true; } else if (status[0] == AUTHENTICATION_DONT_USE_AUTH) { this.authActivated = false; } else { errors.throwErr(errors.ERR_ANO_STATUS, "Authentication"); } return pos; } } class EncryptionService extends NetworkService { constructor(sAtts) { super(sAtts); this.service = ENCRYPTION; this.numSubPackets = 2; } getDataSize() { return SERVICE_HEADER_SIZE + SUBPACKET_SIZE + VERSION_LENGTH + SUBPACKET_SIZE + 1; } sendServiceData(buf, pos) { pos = this.sendHeader(buf, pos); pos = this.sendVersion(buf, pos); const drivers = Buffer.from([0x00]); /* No encryption drivers supported */ pos = this.sendRaw(buf, drivers, 1, pos); return pos; } } class DataIntegrityService extends NetworkService { constructor(sAtts) { super(sAtts); this.service = DATAINTEGRITY; this.numSubPackets = 2; } getDataSize() { return SERVICE_HEADER_SIZE + SUBPACKET_SIZE + VERSION_LENGTH + SUBPACKET_SIZE + 1; } sendServiceData(buf, pos) { pos = this.sendHeader(buf, pos); pos = this.sendVersion(buf, pos); const drivers = Buffer.from([0x00]); /* No data integrity drivers supported */ pos = this.sendRaw(buf, drivers, 1, pos); return pos; } } /* Advanced Networking Options */ class ANO { constructor(sAtts) { this.serviceList = [new AuthenticationService(sAtts), new EncryptionService(sAtts), new DataIntegrityService(sAtts), new SupervisorService(sAtts)]; } sendPacket() { let bufSize = HEADER_SIZE; for (let i = 0; i < this.serviceList.length; i++) { bufSize += this.serviceList[i].getDataSize(); } const buf = Buffer.allocUnsafe(bufSize).fill(0); let pos = buf.writeUInt32BE(MAGIC); pos = buf.writeUInt16BE(bufSize, pos); pos = buf.writeUInt32BE(VERSION, pos); pos = buf.writeUInt16BE(this.serviceList.length, pos); pos = buf.writeUInt8(0, pos); /* Send in order of Supervisor, Auth, Encryption, Data Integrity */ pos = this.serviceList[3].sendServiceData(buf, pos); pos = this.serviceList[0].sendServiceData(buf, pos); pos = this.serviceList[1].sendServiceData(buf, pos); this.serviceList[2].sendServiceData(buf, pos); return buf; } processPacket(pkt) { let pos = 10; if (pkt.readUInt32BE(pos) != MAGIC) { errors.throwErr(errors.ERR_ANO_PACKET); } pos += 4; //const pktLen = pkt.readUInt16BE(pos); pos += 2; //const version = pkt.readUInt32BE(pos); pos += 4; const services = pkt.readUInt16BE(pos); pos += 2; //const error = pkt.readUInt8(pos); pos += 1; /* Receive service headers */ const ret = []; for (let i = 0; i < services; i++) { pos = NetworkService.receiveHeader(pkt, ret, pos); if (ret[2] != NO_ERROR) { errors.throwErrWithORAError(errors.ERR_ANO_NEGOTIATION, ret[2]); } const serviceId = serviceMap[ret[0]]; pos = this.serviceList[serviceId].receiveServiceData(pkt, ret[1], pos); } } } function getFlags(protocol, userConfig) { /* Do the NA negotiation only if external Auth and tpcs Authentication service is requested for a tcps connection */ if (protocol.toUpperCase() == 'TCPS' && userConfig.externalAuth && !userConfig.token) return constants.NSINAWANTED; else return constants.NSINANOSERVICES; } module.exports = { ANO, getFlags};