import { ITGlueClient } from '../client'; import { QueryUtilOptions, QueryParams, RequestBody, BaseListResponse, BaseItemResponse, PasswordResource } from '../types'; /** * Passwords resource module for IT Glue API * * Provides methods to interact with the /passwords endpoint and handle sensitive password data. * Passwords represent secure credentials stored in IT Glue, including login credentials, API keys, * and other sensitive authentication information. All password data is encrypted at rest and in transit. * * **Security Note:** Password data is highly sensitive. Ensure proper handling of responses * containing password information and avoid logging or storing password data insecurely. * The client automatically sanitizes password data to prevent accidental exposure in logs. * * ## Related Resources * Passwords are commonly used with: * - {@link Organizations} - Parent organizations that own passwords * - {@link PasswordCategories} - Classify passwords by type (admin, user, service account) * - {@link PasswordFolders} - Organize passwords into logical folders * - {@link Configurations} - IT assets that passwords provide access to * - {@link Contacts} - People associated with or responsible for passwords * - {@link Documents} - Documentation related to password policies and procedures * - {@link FlexibleAssets} - Custom password tracking and license management * - {@link RelatedItems} - Create relationships between passwords and other resources * - {@link Tags} - Categorize and label passwords for better organization * - {@link Attachments} - Store files and documents related to passwords * * @see {@link Organizations#list} for retrieving passwords by organization * @see {@link PasswordCategories#list} for retrieving available password categories * @see {@link PasswordCategories#list} for retrieving available password folders * @see {@link Configurations#list} for retrieving configurations associated with passwords * * @example * import { ITGlueClient } from '../client'; * import { Passwords } from './resources/passwords'; * * const client = new ITGlueClient({ apiKey: 'your-api-key' }); * const passwords = new Passwords(client); * * // List passwords * const list = await passwords.list(); * * // Get a single password * const pw = await passwords.get('789'); * * // Create a password (JSON:API format) * const created = await passwords.create({ * data: { * type: 'passwords', * attributes: { * name: 'Server Admin Login', * username: 'admin', * password: 'securePassword123' * } * } * }); * * // Update a password (JSON:API format) * const updated = await passwords.update('789', { * data: { * type: 'passwords', * attributes: { password: 'newSecurePassword456' } * } * }); * * // Delete a password * await passwords.delete('789'); * * // List passwords for an organization * const orgPws = await passwords.list({ organization_id: '123' }); * * @category Access Management */ export declare class Passwords { private client; private basePath; private paginationUtil; /** * Create a Passwords resource instance * @param {ITGlueClient} client - ITGlueClient instance */ constructor(client: ITGlueClient); /** * List all passwords * @param {QueryUtilOptions} [options] - Optional query parameters (filter, sort, page, etc.) * @param {boolean} [allPages=false] - If true, fetches all pages automatically * @returns {Promise>} List of passwords and pagination metadata * @example * // Basic usage - get first page of passwords * const results = await client.passwords.list(); * console.log(`Found ${results.data.length} passwords`); * console.log('Total pages:', results.meta.pagination.total_pages); * * @example * // Advanced usage with pagination and sorting * const results = await client.passwords.list({ * page: { number: 2, size: 50 }, * sort: '-updated_at', // Sort by most recently updated * include: ['password_category', 'organization'] // Include related data * }); * * @example * // Filtering passwords by organization and category * const filtered = await client.passwords.list({ * filter: { * organization_id: '123', * password_category_id: '456', * name: 'Admin' * }, * sort: 'name' * }); * * @example * // Get all passwords across multiple pages * const allPasswords = await client.passwords.list({}, true); // allPages = true * console.log(`Retrieved all ${allPasswords.data.length} passwords`); * * @example * // Manual pagination for password management * async function getAllPasswordsByCategory(categoryId) { * let page = 1; * let allPasswords = []; * let hasMore = true; * * while (hasMore) { * const response = await client.passwords.list({ * filter: { password_category_id: categoryId }, * page: { number: page, size: 100 }, * sort: 'name' * }); * * allPasswords = [...allPasswords, ...response.data]; * hasMore = response.meta.pagination.total_pages > page; * page++; * } * * return allPasswords; * } * * @example * // Error handling for list operations * try { * const results = await client.passwords.list({ * filter: { invalid_field: 'value' } * }); * } catch (error) { * if (error.response?.status === 400) { * console.log('Invalid filter parameters:', error.response.data.errors); * } else if (error.response?.status === 401) { * console.log('Authentication failed - check your API key'); * } else if (error.response?.status === 403) { * console.log('Access denied - insufficient permissions to list passwords'); * } else { * console.log('Request failed:', error.message); * } * } */ list(options?: QueryUtilOptions, allPages?: boolean): Promise>; /** * Get a single password by ID * @param {string} id - Password ID * @param {QueryParams} [params] - Optional query parameters * @returns {Promise>} Password resource * @example * // Basic usage - get password by ID * const password = await client.passwords.get('789'); * console.log('Password name:', password.data.attributes.name); * console.log('Username:', password.data.attributes.username); * console.log('URL:', password.data.attributes.url); * // Note: Actual password value is encrypted and handled securely * * @example * // Get password with related data included * const passwordWithRelated = await client.passwords.get('789', { * include: ['password_category', 'organization', 'resource'] * }); * * // Access included data * const included = passwordWithRelated.included || []; * const category = included.find(item => item.type === 'password_categories'); * const organization = included.find(item => item.type === 'organizations'); * * @example * // Error handling for get operations * try { * const password = await client.passwords.get('invalid-id'); * } catch (error) { * if (error.response?.status === 404) { * console.log('Password not found'); * } else if (error.response?.status === 403) { * console.log('Access denied - insufficient permissions'); * } else { * console.log('Error retrieving password:', error.message); * } * } * * @example * // Safe get with existence check * async function safeGetPassword(id) { * try { * const password = await client.passwords.get(id); * return password.data; * } catch (error) { * if (error.response?.status === 404) { * return null; // Password doesn't exist * } * throw error; // Re-throw other errors * } * } * @see * {@link Organizations#get} - Get specific organization details * {@link Organizations#list} - List organizations related to passwords * {@link PasswordCategories#get} - Get specific passwordcategorie details * {@link PasswordCategories#list} - List passwordcategories related to passwords */ get(id: string, params?: QueryParams): Promise>; /** * Create a new password * * Creates a new password entry in IT Glue. The password will be encrypted on the server. * All password data is automatically sanitized to prevent accidental exposure in logs. * * @param {RequestBody} data - Password data (must be formatted according to JSON:API spec) * @returns {Promise>} Created password resource * @throws {Error} When validation fails (422) or unauthorized (401) * @example * // Basic password creation * const newPassword = await client.passwords.create({ * data: { * type: 'passwords', * attributes: { * name: 'Server Admin Login', * username: 'admin', * password: 'securePassword123', * password_category_id: '456' * }, * relationships: { * organization: { * data: { type: 'organizations', id: '123' } * } * } * } * }); * * console.log('Created password with ID:', newPassword.data.id); * * @example * // Advanced password creation with all fields * const newPassword = await client.passwords.create({ * data: { * type: 'passwords', * attributes: { * name: 'Cloud Service API Key', * username: 'api-user@example.com', * password: 'sk-1234567890abcdef', * url: 'https://api.cloudservice.com', * notes: 'Production API key. Expires annually on Dec 31st.', * password_category_id: '456', * password_folder_id: '789' * }, * relationships: { * organization: { * data: { type: 'organizations', id: '123' } * }, * resource: { * data: { type: 'configurations', id: '101' } * } * } * } * }); * * @example * // Bulk password creation with error handling * async function createMultiplePasswords(passwordList) { * const results = []; * const errors = []; * * for (const passwordData of passwordList) { * try { * const created = await client.passwords.create({ * data: { * type: 'passwords', * attributes: passwordData, * relationships: { * organization: { * data: { type: 'organizations', id: passwordData.organizationId } * } * } * } * }); * results.push(created.data); * } catch (error) { * errors.push({ passwordData, error: error.message }); * } * } * * return { results, errors }; * } * * @example * // Error handling for password creation * try { * const created = await client.passwords.create({ * data: { * type: 'passwords', * attributes: { * name: 'Invalid Password' * // Missing required fields like username and password * } * } * }); * } catch (error) { * if (error.response?.status === 422) { * console.log('Validation errors:'); * error.response.data.errors.forEach(err => { * console.log(`- ${err.detail} (${err.source?.pointer})`); * }); * } else if (error.response?.status === 403) { * console.log('Permission denied - cannot create password'); * } else { * console.log('Creation failed:', error.message); * } * } * @see * {@link Organizations#create} - Create new organization * {@link Organizations#list} - List organizations related to passwords * {@link PasswordCategories#create} - Create new passwordcategorie * {@link PasswordCategories#list} - List passwordcategories related to passwords */ create(data: RequestBody): Promise>; /** * Update a password by ID * * Updates an existing password entry. Password data is automatically sanitized * to prevent accidental exposure in logs. Only provided fields will be updated. * * @param {string} id - Password ID * @param {RequestBody} data - Updated password data (must be formatted according to JSON:API spec) * @returns {Promise>} Updated password resource * @throws {Error} When password not found (404) or validation fails (422) * @example * // Basic update - change password value * const updatedPassword = await client.passwords.update('789', { * data: { * type: 'passwords', * attributes: { * password: 'newSecurePassword456' * } * } * }); * * console.log('Password updated successfully'); * * @example * // Update password details and metadata * const updatedPassword = await client.passwords.update('789', { * data: { * type: 'passwords', * attributes: { * name: 'Updated Server Login', * username: 'newadmin', * url: 'https://newserver.example.com', * notes: 'Updated after server migration on 2024-01-15' * } * } * }); * * @example * // Conditional update based on current state * async function conditionalUpdatePassword(id, updates) { * try { * // First, get current state * const current = await client.passwords.get(id); * * // Check if update is needed (excluding sensitive password field) * const needsUpdate = Object.keys(updates).some( * key => key !== 'password' && current.data.attributes[key] !== updates[key] * ) || updates.password; // Always update if password is provided * * if (!needsUpdate) { * console.log('Password is already up to date'); * return current; * } * * // Perform update * return await client.passwords.update(id, { * data: { * type: 'passwords', * attributes: updates * } * }); * } catch (error) { * console.error('Update failed:', error.message); * throw error; * } * } * * @example * // Error handling for password updates * try { * const updated = await client.passwords.update('789', { * data: { * type: 'passwords', * attributes: { * password: '' // Invalid empty password * } * } * }); * } catch (error) { * if (error.response?.status === 404) { * console.log('Password not found'); * } else if (error.response?.status === 422) { * console.log('Validation failed:', error.response.data.errors); * } else if (error.response?.status === 409) { * console.log('Conflict - password may have been modified by another user'); * } else { * console.log('Update failed:', error.message); * } * } * @see * {@link Organizations#update} - Update organization * {@link Organizations#get} - Get specific organization details * {@link PasswordCategories#update} - Update passwordcategorie * {@link PasswordCategories#get} - Get specific passwordcategorie details */ update(id: string, data: RequestBody): Promise>; /** * Delete a password by ID * @param {string} id - Password ID * @returns {Promise} * @example * // Basic deletion * await client.passwords.delete('789'); * console.log('Password deleted successfully'); * * @example * // Safe deletion with confirmation * async function safeDeletePassword(id) { * try { * // First verify the password exists * const password = await client.passwords.get(id); * console.log(`Deleting password: ${password.data.attributes.name}`); * * // Perform deletion * await client.passwords.delete(id); * console.log('Password deleted successfully'); * return true; * } catch (error) { * if (error.response?.status === 404) { * console.log('Password not found - may already be deleted'); * return false; * } * throw error; * } * } * * @example * // Bulk deletion with error handling * async function deleteMultiplePasswords(passwordIds) { * const results = []; * * for (const id of passwordIds) { * try { * await client.passwords.delete(id); * results.push({ id, status: 'deleted' }); * } catch (error) { * results.push({ * id, * status: 'error', * error: error.response?.status === 404 ? 'not_found' : error.message * }); * } * } * * return results; * } * * @example * // Error handling for delete operations * try { * await client.passwords.delete('789'); * } catch (error) { * if (error.response?.status === 404) { * console.log('Password not found - may already be deleted'); * } else if (error.response?.status === 403) { * console.log('Permission denied - cannot delete password'); * } else if (error.response?.status === 409) { * console.log('Cannot delete - password is referenced by other resources'); * } else { * console.log('Deletion failed:', error.message); * } * } * @see * {@link Organizations#list} - List organizations related to passwords * {@link Organizations#get} - Get specific organization details * {@link PasswordCategories#list} - List passwordcategories related to passwords * {@link PasswordCategories#get} - Get specific passwordcategorie details */ delete(id: string): Promise; /** * Sanitize sensitive password data before sending to the API * * This private method ensures that sensitive password data is not accidentally * exposed in logs or debug output while still allowing the data to be sent * to the API for processing. * * @param {RequestBody} data - Password data object * @returns {RequestBody} Sanitized data object * @private * @example * // This method is used internally to prevent accidental logging of sensitive fields * const sanitized = this._sanitizePasswordData(passwordData); */ private _sanitizePasswordData; }