-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(lastpass): add integrations for lastpass
- Loading branch information
Hassan Wari
authored and
Hassan Wari
committed
Dec 17, 2024
1 parent
8096410
commit 665f158
Showing
14 changed files
with
585 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
<!-- BEGIN GENERATED CONTENT --> | ||
# Create User | ||
|
||
## General Information | ||
|
||
- **Description:** Creates a user in Lastpass. | ||
- **Version:** 0.0.1 | ||
- **Group:** Others | ||
- **Scopes:** _None_ | ||
- **Endpoint Type:** Action | ||
- **Code:** [github.com](https://github.com/NangoHQ/integration-templates/tree/main/integrations/lastpass/actions/create-user.ts) | ||
|
||
|
||
## Endpoint Reference | ||
|
||
### Request Endpoint | ||
|
||
`POST /users` | ||
|
||
### Request Query Parameters | ||
|
||
_No request parameters_ | ||
|
||
### Request Body | ||
|
||
```json | ||
{ | ||
"firstName": "<string>", | ||
"lastName": "<string>", | ||
"email": "<string>", | ||
"groups?": [ | ||
"<string>" | ||
], | ||
"duousername?": "<string>", | ||
"securidusername?": "<string>", | ||
"password?": "<string>", | ||
"password_reset_required?": "<boolean>" | ||
} | ||
``` | ||
|
||
### Request Response | ||
|
||
```json | ||
{ | ||
"id": "<string>", | ||
"firstName": "<string>", | ||
"lastName": "<string>", | ||
"email": "<string>" | ||
} | ||
``` | ||
|
||
## Changelog | ||
|
||
- [Script History](https://github.com/NangoHQ/integration-templates/commits/main/integrations/lastpass/actions/create-user.ts) | ||
- [Documentation History](https://github.com/NangoHQ/integration-templates/commits/main/integrations/lastpass/actions/create-user.md) | ||
|
||
<!-- END GENERATED CONTENT --> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import type { NangoAction, User, LastPassCreateUser, ProxyConfiguration, ActionResponseError } from '../../models'; | ||
import type { LastPassBody, LastPassCreateNewUser, LastPassResponse } from '../types'; | ||
import { getCredentials } from '../helpers/get-credentials.js'; | ||
import { lastPassCreateUserSchema } from '../../schema.zod.js'; | ||
|
||
export default async function runAction(nango: NangoAction, input: LastPassCreateUser): Promise<User> { | ||
const parsedInput = lastPassCreateUserSchema.safeParse(input); | ||
if (!parsedInput.success) { | ||
for (const error of parsedInput.error.errors) { | ||
await nango.log(`Invalid input provided to create a user: ${error.message} at path ${error.path.join('.')}`, { level: 'error' }); | ||
} | ||
throw new nango.ActionError<ActionResponseError>({ | ||
message: 'Invalid input provided to create a user' | ||
}); | ||
} | ||
|
||
const createUser: LastPassCreateNewUser = { | ||
username: input.email, | ||
fullname: `${input.firstName} ${input.lastName}`, | ||
...(input.groups && { groups: input.groups }), | ||
...(input.duousername && { duousername: input.duousername }), | ||
...(input.securidusername && { securidusername: input.securidusername }), | ||
...(input.password && { password: input.password }), | ||
...(input.password_reset_required !== undefined && { | ||
password_reset_required: input.password_reset_required | ||
}) | ||
}; | ||
|
||
const credentials = await getCredentials(nango); | ||
const lastPassInput: LastPassBody = { | ||
cid: credentials.cid, | ||
provhash: credentials.provhash, | ||
cmd: 'batchadd', | ||
data: [createUser] | ||
}; | ||
|
||
const config: ProxyConfiguration = { | ||
// https://support.lastpass.com/s/document-item?language=en_US&bundleId=lastpass&topicId=LastPass/api_add_users.html&_LANG=enus | ||
endpoint: `/enterpriseapi.php`, | ||
data: lastPassInput, | ||
retries: 10 | ||
}; | ||
const response = await nango.post<LastPassResponse>(config); | ||
|
||
const isSuccess = response?.data?.status === 'OK'; | ||
|
||
// we dont have an Id present in the user's object, so we will use the email as the id | ||
const user: User = { | ||
id: input.email, | ||
firstName: input.firstName, | ||
lastName: input.lastName, | ||
email: input.email | ||
}; | ||
|
||
if (isSuccess) { | ||
return user; | ||
} else { | ||
const errorMessages = response?.data?.error?.join(', ') || 'Unknown error'; | ||
throw new nango.ActionError<ActionResponseError>({ | ||
message: `Failed to create user in LastPass: ${errorMessages}` | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<!-- BEGIN GENERATED CONTENT --> | ||
# Delete User | ||
|
||
## General Information | ||
|
||
- **Description:** Deletes a user in Lastpass. | ||
- **Version:** 0.0.1 | ||
- **Group:** Others | ||
- **Scopes:** _None_ | ||
- **Endpoint Type:** Action | ||
- **Code:** [github.com](https://github.com/NangoHQ/integration-templates/tree/main/integrations/lastpass/actions/delete-user.ts) | ||
|
||
|
||
## Endpoint Reference | ||
|
||
### Request Endpoint | ||
|
||
`DELETE /users` | ||
|
||
### Request Query Parameters | ||
|
||
_No request parameters_ | ||
|
||
### Request Body | ||
|
||
```json | ||
{ | ||
"email": "<string>" | ||
} | ||
``` | ||
|
||
### Request Response | ||
|
||
```json | ||
{ | ||
"success": "<boolean>" | ||
} | ||
``` | ||
|
||
## Changelog | ||
|
||
- [Script History](https://github.com/NangoHQ/integration-templates/commits/main/integrations/lastpass/actions/delete-user.ts) | ||
- [Documentation History](https://github.com/NangoHQ/integration-templates/commits/main/integrations/lastpass/actions/delete-user.md) | ||
|
||
<!-- END GENERATED CONTENT --> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import type { NangoAction, ProxyConfiguration, SuccessResponse, EmailEntity } from '../../models'; | ||
import type { LastPassBody } from '../types'; | ||
import { getCredentials } from '../helpers/get-credentials.js'; | ||
|
||
export default async function runAction(nango: NangoAction, input: EmailEntity): Promise<SuccessResponse> { | ||
if (!input.email) { | ||
throw new nango.ActionError({ | ||
message: 'Email is required to delete a user' | ||
}); | ||
} | ||
const credentials = await getCredentials(nango); | ||
const data: LastPassBody = { | ||
cid: credentials.cid, | ||
provhash: credentials.provhash, | ||
cmd: 'deluser', | ||
data: { | ||
username: input.email, | ||
deleteaction: 2 // Delete user. Deletes the account entirely. | ||
} | ||
}; | ||
const config: ProxyConfiguration = { | ||
// https://support.lastpass.com/s/document-item?language=en_US&bundleId=lastpass&topicId=LastPass/api_delete_user.html&_LANG=enus | ||
endpoint: `/enterpriseapi.php`, | ||
retries: 10, | ||
data: data | ||
}; | ||
|
||
const res = await nango.post(config); | ||
|
||
const isSuccess = res?.data?.status === 'OK'; | ||
|
||
return { | ||
success: isSuccess | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import type { NangoSync, NangoAction } from '../../models'; | ||
|
||
export async function getCredentials(nango: NangoSync | NangoAction): Promise<{ cid: number; provhash: string }> { | ||
const connection = await nango.getConnection(); | ||
|
||
if ('username' in connection.credentials && 'password' in connection.credentials) { | ||
const cid = connection.credentials['username']; | ||
const provhash = connection.credentials['password']; | ||
|
||
return { | ||
cid, | ||
provhash | ||
}; | ||
} else { | ||
throw new nango.ActionError({ | ||
message: `Credentials (username, password) are incomplete` | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import type { NangoSync, ProxyConfiguration } from '../../models'; | ||
|
||
export interface LastPassPaginationParams { | ||
endpoint: string; | ||
cid: number; | ||
provhash: string; | ||
cmd: string; | ||
pageSize?: number; | ||
} | ||
|
||
export interface LastPassPaginationResponse<T> { | ||
results: T[]; | ||
} | ||
|
||
export async function* paginate<T>( | ||
nango: NangoSync, | ||
{ endpoint, cid, provhash, cmd, pageSize = 100 }: LastPassPaginationParams | ||
): AsyncGenerator<LastPassPaginationResponse<T>, void, undefined> { | ||
let pageIndex = 0; | ||
|
||
while (true) { | ||
const body = { | ||
cid, | ||
provhash, | ||
cmd, | ||
data: { | ||
pagesize: pageSize, | ||
pageindex: pageIndex | ||
} | ||
}; | ||
|
||
const config: ProxyConfiguration = { | ||
// eslint-disable-next-line @nangohq/custom-integrations-linting/include-docs-for-endpoints | ||
endpoint, | ||
retries: 10, | ||
data: body | ||
}; | ||
const response = await nango.post<{ | ||
total: number; | ||
count: number; | ||
Users: Record<string, any>; | ||
invited: string[]; | ||
}>(config); | ||
|
||
const users = Object.values(response.data.Users ?? {}).map((user) => ({ | ||
username: user.username, | ||
fullname: user.fullname, | ||
mpstrength: user.mpstrength, | ||
created: user.created, | ||
last_pw_change: user.last_pw_change, | ||
last_login: user.last_login, | ||
neverloggedin: user.neverloggedin, | ||
disabled: user.disabled, | ||
admin: user.admin, | ||
totalscore: user.totalscore, | ||
legacytotalscore: user.legacytotalscore, | ||
hasSharingKeys: user.hasSharingKeys, | ||
duousername: user.duousername, | ||
sites: user.sites, | ||
notes: user.notes, | ||
formfills: user.formfills, | ||
applications: user.applications, | ||
attachments: user.attachments, | ||
password_reset_required: user.password_reset_required | ||
})); | ||
|
||
if (users.length === 0 || users.length < pageSize) { | ||
// eslint-disable-next-line @nangohq/custom-integrations-linting/no-object-casting | ||
yield { results: users as T[] }; | ||
break; | ||
} | ||
// eslint-disable-next-line @nangohq/custom-integrations-linting/no-object-casting | ||
yield { results: users as T[] }; | ||
|
||
pageIndex += 1; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import type { ReturnedUser } from '../types'; | ||
import type { User } from '../../models'; | ||
|
||
export function toUser(users: ReturnedUser[]): User[] { | ||
return users.map((user) => ({ | ||
id: user.username, | ||
firstName: user.fullname?.split(' ')[0] || '', | ||
lastName: user.fullname?.split(' ')[1] || '', | ||
email: user.username | ||
})); | ||
} |
Oops, something went wrong.