3]); $request[2]['check_permissions'] = !$session->isTrusted() || $this->isCheckPermissions($request[2], 'check_permissions'); // ^^ Untrusted sessions MUST check perms. All sessions DEFAULT to checking perms. Trusted sessions MAY disable perms. switch ($this->apiError) { case 'array': return civicrm_api(...$request); case 'exception': return civicrm_api3(...$request); default: throw new \CRM_Core_Exception("Invalid API error-handling mode: $this->apiError"); } } /** * Send a request to APIv4. * * @param \Civi\Pipe\PipeSession $session * @param array $request * Tuple: [$entity, $action, $params] * @return array|\Civi\Api4\Generic\Result|int */ public function api4(PipeSession $session, array $request) { $request[2] = array_merge($request[2] ?? [], ['version' => 4]); $request[2]['checkPermissions'] = !$session->isTrusted() || $this->isCheckPermissions($request[2], 'checkPermissions'); // ^^ Untrusted sessions MUST check perms. All sessions DEFAULT to checking perms. Trusted sessions MAY disable perms. switch ($this->apiError) { case 'array': return civicrm_api(...$request); case 'exception': return civicrm_api4(...$request); default: throw new \CRM_Core_Exception("Invalid API error-handling mode: $this->apiError"); } } /** * Simple test; send/receive a fragment of data. * * @param \Civi\Pipe\PipeSession $session * @param array $request * @return array */ public function echo(PipeSession $session, array $request) { return $request; } /** * Set active user. * * @param \Civi\Pipe\PipeSession $session * @param array{contactId: int, userId: int, user: string, cred: string} $request * @return array|\Civi\Api4\Generic\Result|int */ public function login(PipeSession $session, array $request) { if (!function_exists('authx_login')) { throw new \CRM_Core_Exception('Cannot authenticate. Authx is not configured.'); } $redact = function(?array $authx) { return $authx ? \CRM_Utils_Array::subset($authx, ['contactId', 'userId']) : FALSE; }; $principal = \CRM_Utils_Array::subset($request, ['contactId', 'userId', 'user']); if ($principal && $session->isTrusted()) { return $redact(authx_login(['flow' => 'script', 'principal' => $principal])); } elseif ($principal && !$session->isTrusted()) { throw new AuthxException('Session is not trusted.'); } elseif (isset($request['cred'])) { $authn = new \Civi\Authx\Authenticator(); $authn->setRejectMode('exception'); if ($authn->auth(NULL, ['flow' => 'pipe', 'cred' => $request['cred']])) { return $redact(\CRM_Core_Session::singleton()->get('authx')); } } throw new AuthxException('Cannot authenticate. Must specify principal/credentials.'); } /** * Set ephemeral session options. * * @param \Civi\Pipe\PipeSession $session * @param array{bufferSize: int, responsePrefix: int} $request * Any updates to perform. May be empty/omitted. * @return array{bufferSize: int, responsePrefix: int} * List of updated options. * If the list of updates was empty, then return all options. */ public function options(PipeSession $session, array $request) { $storageMap = [ 'apiCheckPermissions' => $this, 'apiError' => $this, 'bufferSize' => $session, 'responsePrefix' => $session, ]; if (!$session->isTrusted() && array_key_exists('apiCheckPermissions', $request)) { unset($request['apiCheckPermissions']); } $get = function($storage, $name) { if (method_exists($storage, 'get' . ucfirst($name))) { return $storage->{'get' . ucfirst($name)}(); } else { return $storage->{$name}; } }; $set = function($storage, $name, $value) use ($get) { if (method_exists($storage, 'set' . ucfirst($name))) { $storage->{'set' . ucfirst($name)}($value); } else { $storage->{$name} = $value; } return $get($storage, $name); }; $result = []; if (!empty($request)) { foreach ($request as $name => $value) { if (isset($storageMap[$name])) { $result[$name] = $set($storageMap[$name], $name, $value); } } } else { foreach ($storageMap as $name => $storage) { $result[$name] = $get($storage, $name); } } return $result; } private function isCheckPermissions(array $params, string $field) { return isset($params[$field]) ? $params[$field] : $this->apiCheckPermissions; } }