codekingpro/portable-devtools
114k
1/////////////////////////////////////////////////////////////2//3// pgAdmin 4 - PostgreSQL Tools4//5// Copyright (C) 2013 - 2024, The pgAdmin Development Team6// This software is released under the PostgreSQL Licence7//8//////////////////////////////////////////////////////////////9 10import gettext from 'sources/gettext';11import _ from 'lodash';12import BaseUISchema from 'sources/SchemaView/base_schema.ui';13import pgAdmin from 'sources/pgadmin';14import {default as supportedServers} from 'pgadmin.server.supported_servers';15import current_user from 'pgadmin.user_management.current_user';16import { isEmptyString } from 'sources/validators';17import VariableSchema from './variable.ui';18 19export default class ServerSchema extends BaseUISchema {20 constructor(serverGroupOptions=[], userId=0, initValues={}) {21 super({22 gid: undefined,23 id: undefined,24 name: '',25 bgcolor: '',26 fgcolor: '',27 host: '',28 port: 5432,29 db: 'postgres',30 username: current_user.name,31 role: null,32 connect_now: true,33 password: undefined,34 save_password: false,35 db_res: [],36 passexec: undefined,37 passexec_expiration: undefined,38 service: undefined,39 shared_username: '',40 use_ssh_tunnel: false,41 tunnel_host: undefined,42 tunnel_port: 22,43 tunnel_username: undefined,44 tunnel_identity_file: undefined,45 tunnel_password: undefined,46 tunnel_authentication: false,47 tunnel_keep_alive: 0,48 save_tunnel_password: false,49 connection_string: undefined,50 connection_params: [51 {'name': 'sslmode', 'value': 'prefer', 'keyword': 'sslmode'},52 {'name': 'connect_timeout', 'value': 10, 'keyword': 'connect_timeout'}],53 ...initValues,54 });55 56 this.serverGroupOptions = serverGroupOptions;57 this.paramSchema = new VariableSchema(this.getConnectionParameters(), null, null, ['name', 'keyword', 'value']);58 this.userId = userId;59 _.bindAll(this, 'isShared');60 }61 62 initialise(state) {63 this.paramSchema.setAllReadOnly(this.isConnected(state));64 }65 66 isShared(state) {67 return !this.isNew(state) && this.userId != current_user.id && state.shared;68 }69 70 isConnected(state) {71 return Boolean(state.connected);72 }73 74 get baseFields() {75 let obj = this;76 return [77 {78 id: 'id', label: gettext('ID'), type: 'int', group: null,79 mode: ['properties'],80 },{81 id: 'name', label: gettext('Name'), type: 'text', group: null,82 mode: ['properties', 'edit', 'create'], noEmpty: true,83 disabled: obj.isShared,84 },{85 id: 'gid', label: gettext('Server group'), type: 'select',86 options: obj.serverGroupOptions,87 mode: ['create', 'edit'],88 controlProps: { allowClear: false },89 disabled: obj.isShared,90 },91 {92 id: 'server_owner', label: gettext('Shared Server Owner'), type: 'text', mode: ['properties'],93 visible: function(state) {94 let serverOwner = obj.userId;95 return state.shared && serverOwner != current_user.id && pgAdmin.server_mode == 'True';96 },97 },98 {99 id: 'server_type', label: gettext('Server type'), type: 'select',100 mode: ['properties'], visible: obj.isConnected,101 options: supportedServers,102 }, {103 id: 'connected', label: gettext('Connected?'), type: 'switch',104 mode: ['properties'], group: gettext('Connection'),105 }, {106 id: 'version', label: gettext('Version'), type: 'text', group: null,107 mode: ['properties'], visible: obj.isConnected,108 },109 {110 id: 'bgcolor', label: gettext('Background'), type: 'color',111 group: null, mode: ['edit', 'create'],112 disabled: obj.isConnected, deps: ['fgcolor'], depChange: (state)=>{113 if(!state.bgcolor && state.fgcolor) {114 return {'bgcolor': '#ffffff'};115 }116 }117 },{118 id: 'fgcolor', label: gettext('Foreground'), type: 'color',119 group: null, mode: ['edit', 'create'], disabled: obj.isConnected,120 },121 {122 id: 'connect_now', label: gettext('Connect now?'), type: 'switch',123 group: null, mode: ['create'],124 },125 {126 id: 'shared', label: gettext('Shared?'), type: 'switch',127 mode: ['properties', 'create', 'edit'],128 readonly: function(state){129 let serverOwner = obj.userId;130 return !obj.isNew(state) && serverOwner != current_user.id;131 }, visible: function(){132 return current_user.is_admin && pgAdmin.server_mode == 'True';133 },134 },135 {136 id: 'shared_username', label: gettext('Shared Username'), type: 'text',137 controlProps: { maxLength: 64},138 mode: ['properties', 'create', 'edit'], deps: ['shared', 'username'],139 readonly: (s)=>{140 return !(!this.origData.shared && s.shared);141 }, visible: ()=>{142 return current_user.is_admin && pgAdmin.server_mode == 'True';143 },144 depChange: (state, source, _topState, actionObj)=>{145 let ret = {};146 if(this.origData.shared) {147 return ret;148 }149 if(source == 'username' && actionObj.oldState.username == state.shared_username) {150 ret['shared_username'] = state.username;151 }152 if(source == 'shared') {153 if(state.shared) {154 ret['shared_username'] = state.username;155 } else {156 ret['shared_username'] = '';157 }158 }159 return ret;160 },161 },162 {163 id: 'comment', label: gettext('Comments'), type: 'multiline', group: null,164 mode: ['properties', 'edit', 'create'],165 }, {166 id: 'connection_string', label: gettext('Connection String'), type: 'multiline',167 group: gettext('Connection'), mode: ['properties'], readonly: true,168 }, {169 id: 'host', label: gettext('Host name/address'), type: 'text', group: gettext('Connection'),170 mode: ['properties', 'edit', 'create'], disabled: obj.isShared,171 depChange: (state)=>{172 if(obj.origData.host != state.host && !obj.isNew(state) && state.connected){173 obj.informText = gettext(174 'To apply changes to the connection configuration, please disconnect from the server and then reconnect.'175 );176 } else {177 obj.informText = undefined;178 }179 }180 },181 {182 id: 'port', label: gettext('Port'), type: 'int', group: gettext('Connection'),183 mode: ['properties', 'edit', 'create'], min: 1, max: 65535, disabled: obj.isShared,184 depChange: (state)=>{185 if(obj.origData.port != state.port && !obj.isNew(state) && state.connected){186 obj.informText = gettext(187 'To apply changes to the connection configuration, please disconnect from the server and then reconnect.'188 );189 } else {190 obj.informText = undefined;191 }192 }193 },{194 id: 'db', label: gettext('Maintenance database'), type: 'text', group: gettext('Connection'),195 mode: ['properties', 'edit', 'create'], readonly: obj.isConnected, disabled: obj.isShared,196 noEmpty: true,197 },{198 id: 'username', label: gettext('Username'), type: 'text', group: gettext('Connection'),199 mode: ['properties', 'edit', 'create'],200 depChange: (state)=>{201 if(obj.origData.username != state.username && !obj.isNew(state) && state.connected){202 obj.informText = gettext(203 'To apply changes to the connection configuration, please disconnect from the server and then reconnect.'204 );205 } else {206 obj.informText = undefined;207 }208 }209 },{210 id: 'kerberos_conn', label: gettext('Kerberos authentication?'), type: 'switch',211 group: gettext('Connection'),212 },{213 id: 'gss_authenticated', label: gettext('GSS authenticated?'), type: 'switch',214 group: gettext('Connection'), mode: ['properties'], visible: obj.isConnected,215 },{216 id: 'gss_encrypted', label: gettext('GSS encrypted?'), type: 'switch',217 group: gettext('Connection'), mode: ['properties'], visible: obj.isConnected,218 },{219 id: 'password', label: gettext('Password'), type: 'password',220 group: gettext('Connection'),221 mode: ['create'],222 deps: ['connect_now', 'kerberos_conn'],223 visible: function(state) {224 return state.connect_now && obj.isNew(state);225 },226 controlProps: {227 maxLength: null,228 autoComplete: 'new-password'229 },230 disabled: function(state) {return state.kerberos_conn;},231 },{232 id: 'save_password', label: gettext('Save password?'),233 type: 'switch', group: gettext('Connection'), mode: ['create'],234 deps: ['connect_now', 'kerberos_conn'],235 visible: function(state) {236 return state.connect_now && obj.isNew(state);237 },238 disabled: function(state) {239 return !current_user.allow_save_password || state.kerberos_conn;240 },241 },{242 id: 'role', label: gettext('Role'), type: 'text', group: gettext('Connection'),243 mode: ['properties', 'edit', 'create'], readonly: obj.isConnected,244 },{245 id: 'service', label: gettext('Service'), type: 'text',246 mode: ['properties', 'edit', 'create'], readonly: obj.isConnected,247 group: gettext('Connection'),248 }, {249 id: 'connection_params', label: gettext('Connection Parameters'),250 type: 'collection', group: gettext('Parameters'),251 schema: this.paramSchema, mode: ['edit', 'create'], uniqueCol: ['name'],252 canAdd: (state)=> !obj.isConnected(state), canEdit: false,253 canDelete: (state)=> !obj.isConnected(state),254 }, {255 id: 'use_ssh_tunnel', label: gettext('Use SSH tunneling'), type: 'switch',256 mode: ['properties', 'edit', 'create'], group: gettext('SSH Tunnel'),257 disabled: function() {258 return !pgAdmin.Browser.utils.support_ssh_tunnel;259 },260 readonly: obj.isConnected,261 },{262 id: 'tunnel_host', label: gettext('Tunnel host'), type: 'text', group: gettext('SSH Tunnel'),263 mode: ['properties', 'edit', 'create'], deps: ['use_ssh_tunnel'],264 disabled: function(state) {265 return !state.use_ssh_tunnel;266 },267 readonly: obj.isConnected,268 },{269 id: 'tunnel_port', label: gettext('Tunnel port'), type: 'int', group: gettext('SSH Tunnel'),270 mode: ['properties', 'edit', 'create'], deps: ['use_ssh_tunnel'], max: 65535,271 disabled: function(state) {272 return !state.use_ssh_tunnel;273 },274 readonly: obj.isConnected,275 },{276 id: 'tunnel_username', label: gettext('Username'), type: 'text', group: gettext('SSH Tunnel'),277 mode: ['properties', 'edit', 'create'], deps: ['use_ssh_tunnel'],278 disabled: function(state) {279 return !state.use_ssh_tunnel;280 },281 readonly: obj.isConnected,282 },{283 id: 'tunnel_authentication', label: gettext('Authentication'), type: 'toggle',284 mode: ['properties', 'edit', 'create'], group: gettext('SSH Tunnel'),285 options: [286 {'label': gettext('Password'), value: false},287 {'label': gettext('Identity file'), value: true},288 ],289 disabled: function(state) {290 return !state.use_ssh_tunnel;291 },292 readonly: obj.isConnected,293 },294 {295 id: 'tunnel_identity_file', label: gettext('Identity file'), type: 'file',296 group: gettext('SSH Tunnel'), mode: ['properties', 'edit', 'create'],297 controlProps: {298 dialogType: 'select_file', supportedTypes: ['*'],299 },300 deps: ['tunnel_authentication', 'use_ssh_tunnel'],301 depChange: (state)=>{302 if (!state.tunnel_authentication && state.tunnel_identity_file) {303 return {tunnel_identity_file: null};304 }305 },306 disabled: function(state) {307 return !state.tunnel_authentication || !state.use_ssh_tunnel;308 },309 },310 {311 id: 'tunnel_password', label: gettext('Password'), type: 'password',312 group: gettext('SSH Tunnel'), mode: ['create'],313 deps: ['use_ssh_tunnel'],314 disabled: function(state) {315 return !state.use_ssh_tunnel;316 },317 controlProps: {318 maxLength: null319 },320 readonly: obj.isConnected,321 }, {322 id: 'save_tunnel_password', label: gettext('Save password?'),323 type: 'switch', group: gettext('SSH Tunnel'), mode: ['create'],324 deps: ['connect_now', 'use_ssh_tunnel'],325 visible: function(state) {326 return state.connect_now && obj.isNew(state);327 },328 disabled: function(state) {329 return (!current_user.allow_save_tunnel_password || !state.use_ssh_tunnel);330 },331 },332 {333 id: 'tunnel_keep_alive', label: gettext('Keep alive (seconds)'),334 type: 'int', group: gettext('SSH Tunnel'), min: 0,335 mode: ['properties', 'edit', 'create'], deps: ['use_ssh_tunnel'],336 disabled: function(state) {337 return !state.use_ssh_tunnel;338 },339 readonly: obj.isConnected,340 },341 {342 id: 'db_res', label: gettext('DB restriction'), type: 'select', group: gettext('Advanced'),343 options: [],344 mode: ['properties', 'edit', 'create'], readonly: obj.isConnected, controlProps: {345 multiple: true, allowClear: false, creatable: true, noDropdown: true, placeholder: 'Specify the databases to be restrict...'},346 },347 {348 id: 'passexec_cmd', label: gettext('Password exec command'), type: 'text',349 group: gettext('Advanced'), controlProps: {maxLength: null},350 mode: ['properties', 'edit', 'create'],351 disabled: pgAdmin.server_mode == 'True' && pgAdmin.enable_server_passexec_cmd == 'False',352 },353 {354 id: 'passexec_expiration', label: gettext('Password exec expiration (seconds)'), type: 'int',355 group: gettext('Advanced'),356 mode: ['properties', 'edit', 'create'],357 disabled: function(state) {358 return isEmptyString(state.passexec_cmd);359 },360 },361 {362 id: 'prepare_threshold', label: gettext('Prepare threshold'), type: 'int',363 group: gettext('Advanced'),364 mode: ['properties', 'edit', 'create'],365 helpMessageMode: ['edit', 'create'],366 helpMessage: gettext('If it is set to 0, every query is prepared the first time it is executed. If it is set to blank, prepared statements are disabled on the connection.')367 }368 ];369 }370 371 validate(state, setError) {372 let errmsg = null;373 374 if(isEmptyString(state.gid)) {375 errmsg = gettext('Server group must be specified.');376 setError('gid', errmsg);377 return true;378 } else {379 setError('gid', null);380 }381 382 if (isEmptyString(state.service)) {383 errmsg = gettext('Either Host name or Service must be specified.');384 if(isEmptyString(state.host)) {385 setError('host', errmsg);386 return true;387 } else {388 setError('host', null);389 }390 391 /* Hostname, IP address validate */392 if (state.host) {393 // Check for leading and trailing spaces.394 if (/(^\s)|(\s$)/.test(state.host)){395 errmsg = gettext('Host name must be valid hostname or IPv4 or IPv6 address.');396 setError('host', errmsg);397 return true;398 } else {399 setError('host', null);400 }401 }402 403 if(isEmptyString(state.username)) {404 errmsg = gettext('Username must be specified.');405 setError('username', errmsg);406 return true;407 } else {408 setError('username', null);409 }410 411 if(isEmptyString(state.port)) {412 errmsg = gettext('Port must be specified.');413 setError('port', errmsg);414 return true;415 } else {416 setError('port', null);417 }418 } else {419 _.each(['host', 'db', 'username', 'port'], (item) => {420 setError(item, null);421 });422 }423 424 if (state.use_ssh_tunnel) {425 if(isEmptyString(state.tunnel_host)) {426 errmsg = gettext('SSH Tunnel host must be specified.');427 setError('tunnel_host', errmsg);428 return true;429 } else {430 setError('tunnel_host', null);431 }432 433 if(isEmptyString(state.tunnel_port)) {434 errmsg = gettext('SSH Tunnel port must be specified.');435 setError('tunnel_port', errmsg);436 return true;437 } else {438 setError('tunnel_port', null);439 }440 441 if(isEmptyString(state.tunnel_username)) {442 errmsg = gettext('SSH Tunnel username must be specified.');443 setError('tunnel_username', errmsg);444 return true;445 } else {446 setError('tunnel_username', null);447 }448 449 if (state.tunnel_authentication) {450 if(isEmptyString(state.tunnel_identity_file)) {451 errmsg = gettext('SSH Tunnel identity file must be specified.');452 setError('tunnel_identity_file', errmsg);453 return true;454 } else {455 setError('tunnel_identity_file', null);456 }457 }458 459 if(isEmptyString(state.tunnel_keep_alive)) {460 errmsg = gettext('Keep alive must be specified. Specify 0 for no keep alive.');461 setError('tunnel_keep_alive', errmsg);462 return true;463 } else {464 setError('tunnel_keep_alive', null);465 }466 }467 return false;468 }469 470 getConnectionParameters() {471 return [{472 'value': 'hostaddr', 'label': gettext('Host address'), 'vartype': 'string'473 }, {474 'value': 'passfile', 'label': gettext('Password file'), 'vartype': 'file'475 }, {476 'value': 'channel_binding', 'label': gettext('Channel binding'), 'vartype': 'enum',477 'enumvals': [gettext('prefer'), gettext('require'), gettext('disable')],478 'min_server_version': '13'479 }, {480 'value': 'connect_timeout', 'label': gettext('Connection timeout (seconds)'), 'vartype': 'integer'481 }, {482 'value': 'client_encoding', 'label': gettext('Client encoding'), 'vartype': 'string'483 }, {484 'value': 'options', 'label': gettext('Options'), 'vartype': 'string'485 }, {486 'value': 'application_name', 'label': gettext('Application name'), 'vartype': 'string'487 }, {488 'value': 'fallback_application_name', 'label': gettext('Fallback application name'), 'vartype': 'string'489 }, {490 'value': 'keepalives', 'label': gettext('Keepalives'), 'vartype': 'integer'491 }, {492 'value': 'keepalives_idle', 'label': gettext('Keepalives idle (seconds)'), 'vartype': 'integer'493 }, {494 'value': 'keepalives_interval', 'label': gettext('Keepalives interval (seconds)'), 'vartype': 'integer'495 }, {496 'value': 'keepalives_count', 'label': gettext('Keepalives count'), 'vartype': 'integer'497 }, {498 'value': 'tcp_user_timeout', 'label': gettext('TCP user timeout (milliseconds)'), 'vartype': 'integer',499 'min_server_version': '12'500 }, {501 'value': 'tty', 'label': gettext('TTY'), 'vartype': 'string',502 'max_server_version': '13'503 }, {504 'value': 'replication', 'label': gettext('Replication'), 'vartype': 'enum',505 'enumvals': [gettext('on'), gettext('off'), gettext('database')],506 'min_server_version': '11'507 }, {508 'value': 'gssencmode', 'label': gettext('GSS encmode'), 'vartype': 'enum',509 'enumvals': [gettext('prefer'), gettext('require'), gettext('disable')],510 'min_server_version': '12'511 }, {512 'value': 'sslmode', 'label': gettext('SSL mode'), 'vartype': 'enum',513 'enumvals': [gettext('allow'), gettext('prefer'), gettext('require'),514 gettext('disable'), gettext('verify-ca'), gettext('verify-full')]515 }, {516 'value': 'sslcompression', 'label': gettext('SSL compression?'), 'vartype': 'bool',517 }, {518 'value': 'sslcert', 'label': gettext('Client certificate'), 'vartype': 'file'519 }, {520 'value': 'sslkey', 'label': gettext('Client certificate key'), 'vartype': 'file'521 }, {522 'value': 'sslpassword', 'label': gettext('SSL password'), 'vartype': 'string',523 'min_server_version': '13'524 }, {525 'value': 'sslrootcert', 'label': gettext('Root certificate'), 'vartype': 'file'526 }, {527 'value': 'sslcrl', 'label': gettext('Certificate revocation list'), 'vartype': 'file',528 }, {529 'value': 'sslcrldir', 'label': gettext('Certificate revocation list directory'), 'vartype': 'file',530 'min_server_version': '14'531 }, {532 'value': 'sslsni', 'label': gettext('Server name indication'), 'vartype': 'bool',533 'min_server_version': '14'534 }, {535 'value': 'requirepeer', 'label': gettext('Require peer'), 'vartype': 'string',536 }, {537 'value': 'ssl_min_protocol_version', 'label': gettext('SSL min protocol version'),538 'vartype': 'enum', 'min_server_version': '13',539 'enumvals': [gettext('TLSv1'), gettext('TLSv1.1'), gettext('TLSv1.2'),540 gettext('TLSv1.3')]541 }, {542 'value': 'ssl_max_protocol_version', 'label': gettext('SSL max protocol version'),543 'vartype': 'enum', 'min_server_version': '13',544 'enumvals': [gettext('TLSv1'), gettext('TLSv1.1'), gettext('TLSv1.2'),545 gettext('TLSv1.3')]546 }, {547 'value': 'krbsrvname', 'label': gettext('Kerberos service name'), 'vartype': 'string',548 }, {549 'value': 'gsslib', 'label': gettext('GSS library'), 'vartype': 'string',550 }, {551 'value': 'target_session_attrs', 'label': gettext('Target session attribute'),552 'vartype': 'enum',553 'enumvals': [gettext('any'), gettext('read-write'), gettext('read-only'),554 gettext('primary'), gettext('standby'), gettext('prefer-standby')]555 }, {556 'value': 'load_balance_hosts', 'label': gettext('Load balance hosts'),557 'vartype': 'enum', 'min_server_version': '16',558 'enumvals': [gettext('disable'), gettext('random')]559 }];560 }561}562 