mirror of
https://github.com/bitwarden/directory-connector
synced 2025-12-05 23:53:21 +00:00
Compare commits
347 Commits
AC-1743/up
...
9b2fc27946
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9b2fc27946 | ||
|
|
2ad35be82e | ||
|
|
bdfc8ae5eb | ||
|
|
7d218eac2f | ||
|
|
ccbb24d504 | ||
|
|
dd1f36e3d6 | ||
|
|
0780f9a931 | ||
|
|
62c8a64298 | ||
|
|
0d3bbc1db8 | ||
|
|
99655a0abf | ||
|
|
2883ff6068 | ||
|
|
f5abaf114a | ||
|
|
5792578946 | ||
|
|
6b3b29a1a0 | ||
|
|
02809be178 | ||
|
|
6abfdd8a88 | ||
|
|
b95f57c4e7 | ||
|
|
9ecfc29ae4 | ||
|
|
e32f29b8e7 | ||
|
|
e333db372d | ||
|
|
a44eb28be8 | ||
|
|
ab436551de | ||
|
|
10e17adfb2 | ||
|
|
c7db8376ec | ||
|
|
bc996d680f | ||
|
|
fe01b49df1 | ||
|
|
daeb96713f | ||
|
|
f6791dabef | ||
|
|
a3a5ed8531 | ||
|
|
d3d62c30aa | ||
|
|
f81155b6b3 | ||
|
|
57a3ef04cc | ||
|
|
4e21b28276 | ||
|
|
1c2a0c677b | ||
|
|
5666f09e89 | ||
|
|
b13895bdd6 | ||
|
|
29fc4ad61e | ||
|
|
f722196149 | ||
|
|
a4ec6df118 | ||
|
|
01e60bf090 | ||
|
|
7c27202dab | ||
|
|
77ea7a395d | ||
|
|
a259de8b26 | ||
|
|
06dbc14136 | ||
|
|
e74546e8c3 | ||
|
|
5ac0cc408e | ||
|
|
9044f94f43 | ||
|
|
1b2c854569 | ||
|
|
e5b3e58a02 | ||
|
|
32b29d2d34 | ||
|
|
a68744524c | ||
|
|
cee7700895 | ||
|
|
b2c60aab1e | ||
|
|
ab76a7eac4 | ||
|
|
d662c05b3e | ||
|
|
ec2c40a565 | ||
|
|
8dc2be7fab | ||
|
|
2879d9c38c | ||
|
|
71ca0772a9 | ||
|
|
6ff39dd207 | ||
|
|
489effb852 | ||
|
|
acb5bc4d25 | ||
|
|
cac411fb29 | ||
|
|
94881d0db0 | ||
|
|
a7c3c40570 | ||
|
|
88af7d6b12 | ||
|
|
3716e5ca57 | ||
|
|
3cc4f90688 | ||
|
|
afa6ced621 | ||
|
|
68efd0a86e | ||
|
|
7fb8732e1e | ||
|
|
48acb783fe | ||
|
|
3df63b8ddf | ||
|
|
ed40b17a80 | ||
|
|
460de6a075 | ||
|
|
4784d45d23 | ||
|
|
60d9a35239 | ||
|
|
5ffd761326 | ||
|
|
55fe14b744 | ||
|
|
c0cbf7651a | ||
|
|
926202f80a | ||
|
|
3013e5f06f | ||
|
|
6789a14527 | ||
|
|
66c38dc18f | ||
|
|
763497e160 | ||
|
|
c28a93bdbe | ||
|
|
3715df42d7 | ||
|
|
a643175a99 | ||
|
|
0c1d20aaa6 | ||
|
|
c51e37e77d | ||
|
|
eec7420826 | ||
|
|
284206b735 | ||
|
|
51042857c9 | ||
|
|
a462ae7457 | ||
|
|
5dfd60d25c | ||
|
|
19937fcbe9 | ||
|
|
46405ad75c | ||
|
|
04ee7533e4 | ||
|
|
02aa653a48 | ||
|
|
921466677e | ||
|
|
e8f0d17944 | ||
|
|
2cc2292ed6 | ||
|
|
c96e0bb147 | ||
|
|
6964a7db49 | ||
|
|
32e3327974 | ||
|
|
3a46e1781e | ||
|
|
dc64f7191e | ||
|
|
570bcf1581 | ||
|
|
fc06bf401a | ||
|
|
61d7c996c1 | ||
|
|
71a19fecaa | ||
|
|
ae37cea276 | ||
|
|
09f1f6981c | ||
|
|
ceff0559f2 | ||
|
|
4d55bf0527 | ||
|
|
7347c1992f | ||
|
|
46d2797d8c | ||
|
|
ed58d7c758 | ||
|
|
cd6bbd792a | ||
|
|
3b3ea8ac47 | ||
|
|
5f9adf9ab7 | ||
|
|
1deb22a446 | ||
|
|
115a60316d | ||
|
|
e11225b2ce | ||
|
|
4909d306ba | ||
|
|
caa8c4d070 | ||
|
|
ed1d941282 | ||
|
|
f6f874360f | ||
|
|
18b110e70d | ||
|
|
83c42cec73 | ||
|
|
2d80fceb8c | ||
|
|
0489f0cbe9 | ||
|
|
c5d4cb9fb6 | ||
|
|
16d6647090 | ||
|
|
a08673917b | ||
|
|
27e1ab9bcf | ||
|
|
3573e201a6 | ||
|
|
23d285a9f6 | ||
|
|
527d2cb75d | ||
|
|
42efd689e3 | ||
|
|
2fe980dea6 | ||
|
|
9446eedec7 | ||
|
|
41ee0d82d5 | ||
|
|
40a85bb875 | ||
|
|
50be1218e2 | ||
|
|
e4abb2c751 | ||
|
|
23c591f903 | ||
|
|
2ea2fd701c | ||
|
|
3b74be446e | ||
|
|
2651a53f27 | ||
|
|
09ed8326c3 | ||
|
|
c5a65a85ad | ||
|
|
3ae90cbb4c | ||
|
|
99dbb3162e | ||
|
|
f146d41b66 | ||
|
|
b35cf8e995 | ||
|
|
f7ee5dcd92 | ||
|
|
61bbff771e | ||
|
|
2047b6644e | ||
|
|
26dd9662cf | ||
|
|
70073fb570 | ||
|
|
8642b9d7aa | ||
|
|
d77b50c540 | ||
|
|
ed935d998a | ||
|
|
682da52040 | ||
|
|
531619af1d | ||
|
|
cf54858cc5 | ||
|
|
6cc022b135 | ||
|
|
a8a4390624 | ||
|
|
f9d817f0b1 | ||
|
|
112bda1137 | ||
|
|
23713d92fa | ||
|
|
6ebc9631aa | ||
|
|
e8579f11d3 | ||
|
|
6b2c7a5f00 | ||
|
|
2a1a5bf064 | ||
|
|
1464d72b27 | ||
|
|
f5cbd8f03d | ||
|
|
fdbbef68c1 | ||
|
|
efb412684d | ||
|
|
79f7a2b495 | ||
|
|
4342734412 | ||
|
|
62f14e5043 | ||
|
|
c2b22518fe | ||
|
|
37c992f16b | ||
|
|
69156677ac | ||
|
|
aaed7b13ea | ||
|
|
096d2a03ab | ||
|
|
bd5bcbebd9 | ||
|
|
bb9ece6078 | ||
|
|
40de47e6e3 | ||
|
|
094ed57e03 | ||
|
|
96a38e2d76 | ||
|
|
9e200c8705 | ||
|
|
ca945318ed | ||
|
|
04abed9251 | ||
|
|
9b08ca6db8 | ||
|
|
0cbe6e9d33 | ||
|
|
dda6dd99ed | ||
|
|
5492466276 | ||
|
|
ef571ec0c3 | ||
|
|
f2bea1b6d7 | ||
|
|
07a1ae6dea | ||
|
|
f23997dd72 | ||
|
|
18547d6eaa | ||
|
|
c3a4f25160 | ||
|
|
e57a52e483 | ||
|
|
ff1380ee67 | ||
|
|
2269b82e7e | ||
|
|
8ab3516377 | ||
|
|
91dfd7e0b7 | ||
|
|
6db28408e6 | ||
|
|
bdacf3d4e4 | ||
|
|
9c566f50a2 | ||
|
|
e3fbc4e731 | ||
|
|
3c5bafe39f | ||
|
|
d65f42684e | ||
|
|
743b4b44cb | ||
|
|
1931a7f065 | ||
|
|
7d01bf0c6c | ||
|
|
c28ce25381 | ||
|
|
74c152f142 | ||
|
|
d4e317d804 | ||
|
|
605facb464 | ||
|
|
5a6ae00a82 | ||
|
|
19344bf696 | ||
|
|
8d8b3ca13e | ||
|
|
4fee3298f8 | ||
|
|
493e819b1c | ||
|
|
df4eb139e4 | ||
|
|
6cdd07429c | ||
|
|
278ec1acf0 | ||
|
|
e3d3c856c5 | ||
|
|
37ac5fc936 | ||
|
|
15978f69b1 | ||
|
|
ee7d97b797 | ||
|
|
930d7cf224 | ||
|
|
cf106b148e | ||
|
|
cfd0722587 | ||
|
|
b462a78c18 | ||
|
|
4bb96f049c | ||
|
|
b991fea958 | ||
|
|
111b8bd646 | ||
|
|
42af888615 | ||
|
|
a28fad020b | ||
|
|
f190433348 | ||
|
|
1e211becc3 | ||
|
|
4652c6489f | ||
|
|
9dc497dd13 | ||
|
|
3d9465917d | ||
|
|
6b1b6bf1c4 | ||
|
|
f52af53dad | ||
|
|
6e6039d298 | ||
|
|
332d07eca6 | ||
|
|
c3ed541efd | ||
|
|
4ae4cba877 | ||
|
|
3ecca16f50 | ||
|
|
1f30ef165f | ||
|
|
dfd8fce231 | ||
|
|
0b7c0ec9c2 | ||
|
|
6d569e9319 | ||
|
|
3ed4e76f95 | ||
|
|
abf7e0400c | ||
|
|
5600f20760 | ||
|
|
bbc65d77e3 | ||
|
|
5d0cde9cfa | ||
|
|
eff7c848f8 | ||
|
|
46fb407c0c | ||
|
|
e2fe5ef9ad | ||
|
|
dd10538d0f | ||
|
|
6d355812e0 | ||
|
|
c973d5fea0 | ||
|
|
01a3f68480 | ||
|
|
d31f14cfe7 | ||
|
|
401daa0187 | ||
|
|
1951b9507d | ||
|
|
eae9cac931 | ||
|
|
21cecc3c0a | ||
|
|
21638f3fdc | ||
|
|
f47806ddd2 | ||
|
|
c304650a6a | ||
|
|
d01522bfc4 | ||
|
|
14314a3553 | ||
|
|
ffac82e865 | ||
|
|
decada8745 | ||
|
|
3a639bb8f2 | ||
|
|
a2b5dac108 | ||
|
|
6e76d8fcbd | ||
|
|
63b06f6950 | ||
|
|
f730aeba23 | ||
|
|
52a8a35f41 | ||
|
|
601a83ebfa | ||
|
|
0cdb12229e | ||
|
|
423a48ab2e | ||
|
|
9a2bf331bc | ||
|
|
0d211f351c | ||
|
|
d1d4f53866 | ||
|
|
dede587b78 | ||
|
|
d76a6e993d | ||
|
|
32d514ebcc | ||
|
|
1f08c7e5cc | ||
|
|
dd80dce657 | ||
|
|
ff6dff329a | ||
|
|
8c6f1aab90 | ||
|
|
9a3aae16a7 | ||
|
|
1480445d35 | ||
|
|
fc04964663 | ||
|
|
cc05bcb4a6 | ||
|
|
5ce3b01ff1 | ||
|
|
079c3ee840 | ||
|
|
f88ce25b59 | ||
|
|
599473f6e4 | ||
|
|
df389cbd08 | ||
|
|
051b6dc3cf | ||
|
|
5727dd75cc | ||
|
|
435f2d10b7 | ||
|
|
dab646675f | ||
|
|
8dc65ef371 | ||
|
|
9925fdea40 | ||
|
|
4c61498714 | ||
|
|
930f8c84d5 | ||
|
|
d20818ee49 | ||
|
|
6936c218d1 | ||
|
|
8ef5459801 | ||
|
|
cb615412aa | ||
|
|
2d69d2b791 | ||
|
|
0630b4f52e | ||
|
|
690c9cd5cb | ||
|
|
3f0454b1d8 | ||
|
|
1a84084b5d | ||
|
|
c5fb57576c | ||
|
|
165083a245 | ||
|
|
84f1f5b81f | ||
|
|
9599c66586 | ||
|
|
38b2a13df6 | ||
|
|
1fb4378046 | ||
|
|
8a661fbc5e | ||
|
|
cf56b5fb57 | ||
|
|
9c88e66a27 | ||
|
|
5b7b68f1cb | ||
|
|
a09473c632 | ||
|
|
71727dae7d | ||
|
|
3dbd34ebc3 | ||
|
|
6dd121acc6 | ||
|
|
d6ddb499f0 | ||
|
|
5b4e09be93 | ||
|
|
a48e0af042 |
203
.claude/CLAUDE.md
Normal file
203
.claude/CLAUDE.md
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
# Bitwarden Directory Connector
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
Directory Connector is a TypeScript application that synchronizes users and groups from directory services to Bitwarden organizations. It provides both a desktop GUI (built with Angular and Electron) and a CLI tool (bwdc).
|
||||||
|
|
||||||
|
**Supported Directory Services:**
|
||||||
|
|
||||||
|
- LDAP (Lightweight Directory Access Protocol) - includes Active Directory and general LDAP servers
|
||||||
|
- Microsoft Entra ID (formerly Azure Active Directory)
|
||||||
|
- Google Workspace
|
||||||
|
- Okta
|
||||||
|
- OneLogin
|
||||||
|
|
||||||
|
**Technologies:**
|
||||||
|
|
||||||
|
- TypeScript
|
||||||
|
- Angular (GUI)
|
||||||
|
- Electron (Desktop wrapper)
|
||||||
|
- Node
|
||||||
|
- Jest for testing
|
||||||
|
|
||||||
|
## Code Architecture & Structure
|
||||||
|
|
||||||
|
### Directory Organization
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── abstractions/ # Interface definitions (e.g., IDirectoryService)
|
||||||
|
├── services/ # Business logic implementations for directory services, sync, auth
|
||||||
|
├── models/ # Data models (UserEntry, GroupEntry, etc.)
|
||||||
|
├── commands/ # CLI command implementations
|
||||||
|
├── app/ # Angular GUI components
|
||||||
|
└── utils/ # Test utilities and fixtures
|
||||||
|
|
||||||
|
src-cli/ # CLI-specific code (imports common code from src/)
|
||||||
|
|
||||||
|
jslib/ # Legacy folder structure (mix of deprecated/unused and current code - new code should not be added here)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key Architectural Patterns
|
||||||
|
|
||||||
|
1. **Abstractions = Interfaces**: All interfaces are defined in `/abstractions`
|
||||||
|
2. **Services = Business Logic**: Implementations live in `/services`
|
||||||
|
3. **Directory Service Pattern**: Each directory provider implements `IDirectoryService` interface
|
||||||
|
4. **Separation of Concerns**: GUI (Angular app) and CLI (commands) share the same service layer
|
||||||
|
|
||||||
|
## Development Conventions
|
||||||
|
|
||||||
|
### Code Organization
|
||||||
|
|
||||||
|
**File Naming:**
|
||||||
|
|
||||||
|
- kebab-case for files: `ldap-directory.service.ts`
|
||||||
|
- Descriptive names that reflect purpose
|
||||||
|
|
||||||
|
**Class/Function Naming:**
|
||||||
|
|
||||||
|
- PascalCase for classes and interfaces
|
||||||
|
- camelCase for functions and variables
|
||||||
|
- Descriptive names that indicate purpose
|
||||||
|
|
||||||
|
**File Structure:**
|
||||||
|
|
||||||
|
- Keep files focused on single responsibility
|
||||||
|
- Create new service files for distinct directory integrations
|
||||||
|
- Separate models into individual files when complex
|
||||||
|
|
||||||
|
### TypeScript Conventions
|
||||||
|
|
||||||
|
**Import Patterns:**
|
||||||
|
|
||||||
|
- Use path aliases (`@/`) for project imports
|
||||||
|
- `@/` - project root
|
||||||
|
- `@/jslib/` - jslib folder
|
||||||
|
- ESLint enforces alphabetized import ordering with newlines between groups
|
||||||
|
|
||||||
|
**Type Safety:**
|
||||||
|
|
||||||
|
- Avoid `any` types - use proper typing or `unknown` with type guards
|
||||||
|
- Prefer interfaces for contracts, types for unions/intersections
|
||||||
|
- Use strict null checks - handle `null` and `undefined` explicitly
|
||||||
|
- Leverage TypeScript's type inference where appropriate
|
||||||
|
|
||||||
|
**Configuration:**
|
||||||
|
|
||||||
|
- Use configuration files or environment variables
|
||||||
|
- Never hardcode URLs or configuration values
|
||||||
|
|
||||||
|
## Security Best Practices
|
||||||
|
|
||||||
|
**Credential Handling:**
|
||||||
|
|
||||||
|
- Never log directory service credentials, API keys, or tokens
|
||||||
|
- Use secure storage mechanisms for sensitive data
|
||||||
|
- Credentials should never be hardcoded
|
||||||
|
- Store credentials encrypted, never in plain text
|
||||||
|
|
||||||
|
**Sensitive Data:**
|
||||||
|
|
||||||
|
- User and group data from directories should be handled securely
|
||||||
|
- Avoid exposing sensitive information in error messages
|
||||||
|
- Sanitize data before logging
|
||||||
|
- Be cautious with data persistence
|
||||||
|
|
||||||
|
**Input Validation:**
|
||||||
|
|
||||||
|
- Validate and sanitize data from external directory services
|
||||||
|
- Check for injection vulnerabilities (LDAP injection, etc.)
|
||||||
|
- Validate configuration inputs from users
|
||||||
|
|
||||||
|
**API Security:**
|
||||||
|
|
||||||
|
- Ensure authentication flows are implemented correctly
|
||||||
|
- Verify SSL/TLS is used for all external connections
|
||||||
|
- Check for secure token storage and refresh mechanisms
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
**Best Practices:**
|
||||||
|
|
||||||
|
1. **Try-catch for async operations** - Always wrap external API calls
|
||||||
|
2. **Meaningful error messages** - Provide context for debugging
|
||||||
|
3. **Error propagation** - Don't swallow errors silently
|
||||||
|
4. **User-facing errors** - Separate user messages from developer logs
|
||||||
|
|
||||||
|
## Performance Best Practices
|
||||||
|
|
||||||
|
**Large Dataset Handling:**
|
||||||
|
|
||||||
|
- Use pagination for large user/group lists
|
||||||
|
- Avoid loading entire datasets into memory at once
|
||||||
|
- Consider streaming or batch processing for large operations
|
||||||
|
|
||||||
|
**API Rate Limiting:**
|
||||||
|
|
||||||
|
- Respect rate limits for Microsoft Graph API, Google Admin SDK, etc.
|
||||||
|
- Consider batching large API calls where necessary
|
||||||
|
|
||||||
|
**Memory Management:**
|
||||||
|
|
||||||
|
- Close connections and clean up resources
|
||||||
|
- Remove event listeners when components are destroyed
|
||||||
|
- Be cautious with caching large datasets
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
**Framework:**
|
||||||
|
|
||||||
|
- Jest with jest-preset-angular
|
||||||
|
- jest-mock-extended for type-safe mocks with `mock<Type>()`
|
||||||
|
|
||||||
|
**Test Organization:**
|
||||||
|
|
||||||
|
- Tests colocated with source files
|
||||||
|
- `*.spec.ts` - Unit tests for individual components/services
|
||||||
|
- `*.integration.spec.ts` - Integration tests against live directory services
|
||||||
|
- Test helpers located in `utils/` directory
|
||||||
|
|
||||||
|
**Test Naming:**
|
||||||
|
|
||||||
|
- Descriptive, human-readable test names
|
||||||
|
- Example: `'should return empty array when no users exist in directory'`
|
||||||
|
|
||||||
|
**Test Coverage:**
|
||||||
|
|
||||||
|
- New features must include tests
|
||||||
|
- Bug fixes should include regression tests
|
||||||
|
- Changes to core sync logic or directory specific logic require integration tests
|
||||||
|
|
||||||
|
**Testing Approach:**
|
||||||
|
|
||||||
|
- **Unit tests**: Mock external API calls using jest-mock-extended
|
||||||
|
- **Integration tests**: Use live directory services (Docker containers or configured cloud services)
|
||||||
|
- Focus on critical paths (authentication, sync, data transformation)
|
||||||
|
- Test error scenarios and edge cases (empty results, malformed data, connection failures), not just happy paths
|
||||||
|
|
||||||
|
## Directory Service Patterns
|
||||||
|
|
||||||
|
### IDirectoryService Interface
|
||||||
|
|
||||||
|
All directory services implement this core interface with methods:
|
||||||
|
|
||||||
|
- `getUsers()` - Retrieve users from directory and transform them into standard objects
|
||||||
|
- `getGroups()` - Retrieve groups from directory and transform them into standard objects
|
||||||
|
- Connection and authentication handling
|
||||||
|
|
||||||
|
### Service-Specific Implementations
|
||||||
|
|
||||||
|
Each directory service has unique authentication and query patterns:
|
||||||
|
|
||||||
|
- **LDAP**: Direct LDAP queries, bind authentication
|
||||||
|
- **Microsoft Entra ID**: Microsoft Graph API, OAuth tokens
|
||||||
|
- **Google Workspace**: Google Admin SDK, service account credentials
|
||||||
|
- **Okta/OneLogin**: REST APIs with API tokens
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- [Architectural Decision Records (ADRs)](https://contributing.bitwarden.com/architecture/adr/)
|
||||||
|
- [Contributing Guidelines](https://contributing.bitwarden.com/contributing/)
|
||||||
|
- [Code Style](https://contributing.bitwarden.com/contributing/code-style/)
|
||||||
|
- [Security Whitepaper](https://bitwarden.com/help/bitwarden-security-white-paper/)
|
||||||
|
- [Security Definitions](https://contributing.bitwarden.com/architecture/security/definitions)
|
||||||
27
.claude/prompts/review-code.md
Normal file
27
.claude/prompts/review-code.md
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
Please review this pull request with a focus on:
|
||||||
|
|
||||||
|
- Code quality and best practices
|
||||||
|
- Potential bugs or issues
|
||||||
|
- Security implications
|
||||||
|
- Performance considerations
|
||||||
|
|
||||||
|
Note: The PR branch is already checked out in the current working directory.
|
||||||
|
|
||||||
|
Provide a comprehensive review including:
|
||||||
|
|
||||||
|
- Summary of changes since last review
|
||||||
|
- Critical issues found (be thorough)
|
||||||
|
- Suggested improvements (be thorough)
|
||||||
|
- Good practices observed (be concise - list only the most notable items without elaboration)
|
||||||
|
- Action items for the author
|
||||||
|
- Leverage collapsible <details> sections where appropriate for lengthy explanations or code
|
||||||
|
snippets to enhance human readability
|
||||||
|
|
||||||
|
When reviewing subsequent commits:
|
||||||
|
|
||||||
|
- Track status of previously identified issues (fixed/unfixed/reopened)
|
||||||
|
- Identify NEW problems introduced since last review
|
||||||
|
- Note if fixes introduced new issues
|
||||||
|
|
||||||
|
IMPORTANT: Be comprehensive about issues and improvements. For good practices, be brief - just note
|
||||||
|
what was done well without explaining why or praising excessively.
|
||||||
14
.github/CODEOWNERS
vendored
14
.github/CODEOWNERS
vendored
@@ -7,9 +7,13 @@
|
|||||||
# Default file owners.
|
# Default file owners.
|
||||||
* @bitwarden/team-admin-console-dev
|
* @bitwarden/team-admin-console-dev
|
||||||
|
|
||||||
# DevOps for Actions and other workflow changes.
|
# Docker-related files
|
||||||
.github/workflows @bitwarden/dept-devops
|
**/Dockerfile @bitwarden/team-appsec @bitwarden/dept-bre
|
||||||
.github/secrets @bitwarden/dept-devops
|
**/*.dockerignore @bitwarden/team-appsec @bitwarden/dept-bre
|
||||||
|
**/entrypoint.sh @bitwarden/team-appsec @bitwarden/dept-bre
|
||||||
|
**/docker-compose.yml @bitwarden/team-appsec @bitwarden/dept-bre
|
||||||
|
|
||||||
# Multiple Owners
|
# Claude related files
|
||||||
**/package.json
|
.claude/ @bitwarden/team-ai-sme
|
||||||
|
.github/workflows/respond.yml @bitwarden/team-ai-sme
|
||||||
|
.github/workflows/review-code.yml @bitwarden/team-ai-sme
|
||||||
|
|||||||
14
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
14
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: Feature Requests
|
||||||
|
url: https://community.bitwarden.com/c/feature-requests/
|
||||||
|
about: Request new features using the Community Forums. Please search existing feature requests before making a new one.
|
||||||
|
- name: Bitwarden Community Forums
|
||||||
|
url: https://community.bitwarden.com
|
||||||
|
about: Please visit the community forums for general community discussion, support and the development roadmap.
|
||||||
|
- name: Customer Support
|
||||||
|
url: https://bitwarden.com/contact/
|
||||||
|
about: Please contact our customer support for account issues and general customer support.
|
||||||
|
- name: Security Issues
|
||||||
|
url: https://hackerone.com/bitwarden
|
||||||
|
about: We use HackerOne to manage security disclosures.
|
||||||
111
.github/ISSUE_TEMPLATE/issue.yml
vendored
Normal file
111
.github/ISSUE_TEMPLATE/issue.yml
vendored
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
name: Directory Connector Bug Report
|
||||||
|
description: File a bug report
|
||||||
|
title: "[DC] "
|
||||||
|
labels: ["bug"]
|
||||||
|
type: bug
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Thanks for taking the time to fill out this bug report!
|
||||||
|
|
||||||
|
Please do not submit feature requests. The [Community Forums](https://community.bitwarden.com) has a section for submitting, voting for, and discussing product feature requests.
|
||||||
|
- type: textarea
|
||||||
|
id: reproduce
|
||||||
|
attributes:
|
||||||
|
label: Steps To Reproduce
|
||||||
|
description: How can we reproduce the behavior.
|
||||||
|
value: |
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. Click on '...'
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: expected
|
||||||
|
attributes:
|
||||||
|
label: Expected Result
|
||||||
|
description: A clear and concise description of what you expected to happen.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: actual
|
||||||
|
attributes:
|
||||||
|
label: Actual Result
|
||||||
|
description: A clear and concise description of what is happening.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: screenshots
|
||||||
|
attributes:
|
||||||
|
label: Screenshots or Videos
|
||||||
|
description: If applicable, add screenshots and/or a short video to help explain your problem.
|
||||||
|
- type: textarea
|
||||||
|
id: additional-context
|
||||||
|
attributes:
|
||||||
|
label: Additional Context
|
||||||
|
description: Add any other context about the problem here.
|
||||||
|
- type: dropdown
|
||||||
|
id: os
|
||||||
|
attributes:
|
||||||
|
label: Operating System
|
||||||
|
description: What operating system(s) are you seeing the problem on?
|
||||||
|
multiple: true
|
||||||
|
options:
|
||||||
|
- Windows
|
||||||
|
- macOS
|
||||||
|
- Linux
|
||||||
|
- Other operating system (please specify in "Additional Context" section)
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: os-version
|
||||||
|
attributes:
|
||||||
|
label: Operating System Version
|
||||||
|
description: What version of the operating system(s) are you seeing the problem on?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: directories
|
||||||
|
attributes:
|
||||||
|
label: Directory Service
|
||||||
|
description: What directory service(s) are you seeing the problem on?
|
||||||
|
multiple: true
|
||||||
|
options:
|
||||||
|
- LDAP - Active Directory
|
||||||
|
- Another LDAP implementation (please specify in "Additional Context" section)
|
||||||
|
- Microsoft Entra ID
|
||||||
|
- Google Workspace
|
||||||
|
- Okta Universal Directory
|
||||||
|
- OneLogin
|
||||||
|
- Other directory service (please specify in "Additional Context" section)
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: application-type
|
||||||
|
attributes:
|
||||||
|
label: Application Type
|
||||||
|
description: Which Directory Connector application(s) are you seeing the problem on?
|
||||||
|
multiple: true
|
||||||
|
options:
|
||||||
|
- GUI (the desktop application)
|
||||||
|
- CLI (the bwdc command line application)
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: version
|
||||||
|
attributes:
|
||||||
|
label: Build Version
|
||||||
|
description: What version of our software are you running?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: checkboxes
|
||||||
|
id: issue-tracking-info
|
||||||
|
attributes:
|
||||||
|
label: Issue Tracking Info
|
||||||
|
description: |
|
||||||
|
Make sure to acknowledge the following before submitting your report!
|
||||||
|
options:
|
||||||
|
- label: I understand that work is tracked outside of Github. A PR will be linked to this issue should one be opened to address it, but Bitwarden doesn't use fields like "assigned", "milestone", or "project" to track progress.
|
||||||
|
required: true
|
||||||
47
.github/PULL_REQUEST_TEMPLATE.md
vendored
47
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,33 +1,34 @@
|
|||||||
## Type of change
|
## 🎟️ Tracking
|
||||||
|
|
||||||
- [ ] Bug fix
|
<!-- Paste the link to the Jira or GitHub issue or otherwise describe / point to where this change is coming from. -->
|
||||||
- [ ] New feature development
|
|
||||||
- [ ] Tech debt (refactoring, code cleanup, dependency upgrades, etc)
|
|
||||||
- [ ] Build/deploy pipeline (DevOps)
|
|
||||||
- [ ] Other
|
|
||||||
|
|
||||||
## Objective
|
## 📔 Objective
|
||||||
|
|
||||||
<!--Describe what the purpose of this PR is. For example: what bug you're fixing or what new feature you're adding-->
|
<!-- Describe what the purpose of this PR is, for example what bug you're fixing or new feature you're adding. -->
|
||||||
|
|
||||||
## Code changes
|
## 📸 Screenshots
|
||||||
|
|
||||||
<!--Explain the changes you've made to each file or major component. This should help the reviewer understand your changes-->
|
<!-- Required for any UI changes; delete if not applicable. Use fixed width images for better display. -->
|
||||||
<!--Also refer to any related changes or PRs in other repositories-->
|
|
||||||
|
|
||||||
- **file.ext:** Description of what was changed and why
|
## ⏰ Reminders before review
|
||||||
|
|
||||||
## Screenshots
|
- Contributor guidelines followed
|
||||||
|
- All formatters and local linters executed and passed
|
||||||
|
- Written new unit and / or integration tests where applicable
|
||||||
|
- Used internationalization (i18n) for all UI strings
|
||||||
|
- CI builds passed
|
||||||
|
- Communicated to DevOps any deployment requirements
|
||||||
|
- Updated any necessary documentation (Confluence, contributing docs) or informed the documentation team
|
||||||
|
|
||||||
<!--Required for any UI changes. Delete if not applicable-->
|
## 🦮 Reviewer guidelines
|
||||||
|
|
||||||
## Testing requirements
|
<!-- Suggested interactions but feel free to use (or not) as you desire! -->
|
||||||
|
|
||||||
<!--What functionality requires testing by QA? This includes testing new behavior and regression testing-->
|
- 👍 (`:+1:`) or similar for great changes
|
||||||
|
- 📝 (`:memo:`) or ℹ️ (`:information_source:`) for notes or general info
|
||||||
## Before you submit
|
- ❓ (`:question:`) for questions
|
||||||
|
- 🤔 (`:thinking:`) or 💭 (`:thought_balloon:`) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion
|
||||||
- [ ] I have checked for **linting** errors (`npm run lint`) (required)
|
- 🎨 (`:art:`) for suggestions / improvements
|
||||||
- [ ] I have added **unit tests** where it makes sense to do so (encouraged but not required)
|
- ❌ (`:x:`) or ⚠️ (`:warning:`) for more significant problems or concerns needing attention
|
||||||
- [ ] This change requires a **documentation update** (notify the documentation team)
|
- 🌱 (`:seedling:`) or ♻️ (`:recycle:`) for future improvements or indications of technical debt
|
||||||
- [ ] This change has particular **deployment requirements** (notify the DevOps team)
|
- ⛏ (`:pick:`) for minor or nitpick changes
|
||||||
|
|||||||
31
.github/renovate.json
vendored
31
.github/renovate.json
vendored
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
|
||||||
"extends": [
|
|
||||||
"config:base",
|
|
||||||
"github>bitwarden/renovate-config:pin-actions",
|
|
||||||
":combinePatchMinorReleases",
|
|
||||||
":dependencyDashboard",
|
|
||||||
":maintainLockFilesWeekly",
|
|
||||||
":pinAllExceptPeerDependencies",
|
|
||||||
":prConcurrentLimit10",
|
|
||||||
":rebaseStalePrs",
|
|
||||||
":separateMajorReleases",
|
|
||||||
"group:monorepos",
|
|
||||||
"schedule:weekends"
|
|
||||||
],
|
|
||||||
"enabledManagers": ["github-actions", "npm"],
|
|
||||||
"commitMessagePrefix": "[deps]:",
|
|
||||||
"commitMessageTopic": "{{depName}}",
|
|
||||||
"packageRules": [
|
|
||||||
{
|
|
||||||
"groupName": "npm minor",
|
|
||||||
"matchManagers": ["npm"],
|
|
||||||
"matchUpdateTypes": ["minor", "patch"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"matchFileNames": ["package.json"],
|
|
||||||
"description": "Admin Console owns general dependencies",
|
|
||||||
"reviewers": ["team:team-admin-console-dev"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
24
.github/renovate.json5
vendored
Normal file
24
.github/renovate.json5
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
$schema: "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
|
extends: ["github>bitwarden/renovate-config"],
|
||||||
|
enabledManagers: ["github-actions", "npm"],
|
||||||
|
packageRules: [
|
||||||
|
{
|
||||||
|
groupName: "gh minor",
|
||||||
|
matchManagers: ["github-actions"],
|
||||||
|
matchUpdateTypes: ["minor", "patch"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ignoreDeps: [
|
||||||
|
// yao-pkg is used to create a single executable application bundle for the CLI.
|
||||||
|
// It is a third party build of node which carries a high supply chain risk.
|
||||||
|
// This must be manually vetted by our appsec team before upgrading.
|
||||||
|
// It is excluded from renovate to avoid accidentally upgrading to a non-vetted version.
|
||||||
|
"@yao-pkg/pkg",
|
||||||
|
// googleapis uses ESM after 149.0.0 so we are not upgrading it until we have ESM support.
|
||||||
|
// They release new versions every couple of weeks so ignoring it at the dependency dashboard
|
||||||
|
// level is not sufficient.
|
||||||
|
// FIXME: remove and upgrade when we have ESM support.
|
||||||
|
"googleapis",
|
||||||
|
],
|
||||||
|
}
|
||||||
BIN
.github/secrets/devid-app-cert.p12.gpg
vendored
BIN
.github/secrets/devid-app-cert.p12.gpg
vendored
Binary file not shown.
BIN
.github/secrets/devid-installer-cert.p12.gpg
vendored
BIN
.github/secrets/devid-installer-cert.p12.gpg
vendored
Binary file not shown.
BIN
.github/secrets/macdev-cert.p12.gpg
vendored
BIN
.github/secrets/macdev-cert.p12.gpg
vendored
Binary file not shown.
453
.github/workflows/build.yml
vendored
453
.github/workflows/build.yml
vendored
@@ -1,74 +1,71 @@
|
|||||||
---
|
|
||||||
name: Build
|
name: Build
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request: {}
|
pull_request: {}
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "main"
|
||||||
|
- "rc"
|
||||||
|
- "hotfix-rc"
|
||||||
workflow_dispatch: {}
|
workflow_dispatch: {}
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
cloc:
|
|
||||||
name: CLOC
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
steps:
|
|
||||||
- name: Checkout repo
|
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
|
||||||
|
|
||||||
- name: Set up CLOC
|
|
||||||
run: |
|
|
||||||
sudo apt update
|
|
||||||
sudo apt -y install cloc
|
|
||||||
|
|
||||||
- name: Print lines of code
|
|
||||||
run: cloc --include-lang TypeScript,JavaScript,HTML,Sass,CSS --vcs git
|
|
||||||
|
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
name: Setup
|
name: Setup
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-24.04
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
outputs:
|
outputs:
|
||||||
package_version: ${{ steps.retrieve-version.outputs.package_version }}
|
package_version: ${{ steps.retrieve-version.outputs.package_version }}
|
||||||
|
node_version: ${{ steps.retrieve-node-version.outputs.node_version }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Get Package Version
|
- name: Get Package Version
|
||||||
id: retrieve-version
|
id: retrieve-version
|
||||||
run: |
|
run: |
|
||||||
PKG_VERSION=$(jq -r .version package.json)
|
PKG_VERSION=$(jq -r .version package.json)
|
||||||
echo "package_version=$PKG_VERSION" >> $GITHUB_OUTPUT
|
echo "package_version=$PKG_VERSION" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Get Node Version
|
||||||
|
id: retrieve-node-version
|
||||||
|
run: |
|
||||||
|
NODE_NVMRC=$(cat .nvmrc)
|
||||||
|
NODE_VERSION=${NODE_NVMRC/v/''}
|
||||||
|
echo "node_version=$NODE_VERSION" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
linux-cli:
|
linux-cli:
|
||||||
name: Build Linux CLI
|
name: Build Linux CLI
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-24.04
|
||||||
needs: setup
|
needs: setup
|
||||||
env:
|
env:
|
||||||
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
|
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
|
||||||
_PKG_FETCH_NODE_VERSION: 18.5.0
|
_NODE_VERSION: ${{ needs.setup.outputs.node_version }}
|
||||||
_PKG_FETCH_VERSION: 3.4
|
permissions:
|
||||||
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
node-version: '18'
|
node-version: ${{ env._NODE_VERSION }}
|
||||||
|
|
||||||
- name: Update NPM
|
- name: Update NPM
|
||||||
run: |
|
run: |
|
||||||
npm install -g node-gyp
|
npm install -g node-gyp
|
||||||
node-gyp install $(node -v)
|
node-gyp install "$(node -v)"
|
||||||
|
|
||||||
- name: Get pkg-fetch
|
|
||||||
run: |
|
|
||||||
cd $HOME
|
|
||||||
fetchedUrl="https://github.com/vercel/pkg-fetch/releases/download/v$_PKG_FETCH_VERSION/node-v$_PKG_FETCH_NODE_VERSION-linux-x64"
|
|
||||||
|
|
||||||
mkdir -p .pkg-cache/v$_PKG_FETCH_VERSION
|
|
||||||
wget $fetchedUrl -O "./.pkg-cache/v$_PKG_FETCH_VERSION/fetched-v$_PKG_FETCH_NODE_VERSION-linux-x64"
|
|
||||||
|
|
||||||
- name: Keytar
|
- name: Keytar
|
||||||
run: |
|
run: |
|
||||||
@@ -79,8 +76,8 @@ jobs:
|
|||||||
keytarUrl="https://github.com/atom/node-keytar/releases/download/v$keytarVersion/$keytarTarGz"
|
keytarUrl="https://github.com/atom/node-keytar/releases/download/v$keytarVersion/$keytarTarGz"
|
||||||
|
|
||||||
mkdir -p ./keytar/linux
|
mkdir -p ./keytar/linux
|
||||||
wget $keytarUrl -O ./keytar/linux/$keytarTarGz
|
wget "$keytarUrl" -O "./keytar/linux/$keytarTarGz"
|
||||||
tar -xvf ./keytar/linux/$keytarTarGz -C ./keytar/linux
|
tar -xvf "./keytar/linux/$keytarTarGz" -C ./keytar/linux
|
||||||
|
|
||||||
- name: Install
|
- name: Install
|
||||||
run: npm install
|
run: npm install
|
||||||
@@ -89,24 +86,19 @@ jobs:
|
|||||||
run: npm run dist:cli:lin
|
run: npm run dist:cli:lin
|
||||||
|
|
||||||
- name: Zip
|
- name: Zip
|
||||||
run: zip -j dist-cli/bwdc-linux-$_PACKAGE_VERSION.zip dist-cli/linux/bwdc keytar/linux/build/Release/keytar.node
|
run: zip -j "dist-cli/bwdc-linux-$_PACKAGE_VERSION.zip" "dist-cli/linux/bwdc" "keytar/linux/build/Release/keytar.node"
|
||||||
|
|
||||||
- name: Create checksums
|
|
||||||
run: |
|
|
||||||
shasum -a 256 dist-cli/bwdc-linux-$_PACKAGE_VERSION.zip | \
|
|
||||||
cut -d " " -f 1 > dist-cli/bwdc-linux-sha256-$_PACKAGE_VERSION.txt
|
|
||||||
|
|
||||||
- name: Version Test
|
- name: Version Test
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt install libsecret-1-0 dbus-x11 gnome-keyring
|
sudo apt install libsecret-1-0 dbus-x11 gnome-keyring
|
||||||
eval $(dbus-launch --sh-syntax)
|
eval "$(dbus-launch --sh-syntax)"
|
||||||
|
|
||||||
eval $(echo -n "" | /usr/bin/gnome-keyring-daemon --login)
|
eval "$(echo -n "" | /usr/bin/gnome-keyring-daemon --login)"
|
||||||
eval $(/usr/bin/gnome-keyring-daemon --components=secrets --start)
|
eval "$(/usr/bin/gnome-keyring-daemon --components=secrets --start)"
|
||||||
|
|
||||||
mkdir -p test/linux
|
mkdir -p test/linux
|
||||||
unzip ./dist-cli/bwdc-linux-$_PACKAGE_VERSION.zip -d ./test/linux
|
unzip "./dist-cli/bwdc-linux-$_PACKAGE_VERSION.zip" -d ./test/linux
|
||||||
|
|
||||||
testVersion=$(./test/linux/bwdc -v)
|
testVersion=$(./test/linux/bwdc -v)
|
||||||
|
|
||||||
@@ -119,51 +111,39 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Upload Linux Zip to GitHub
|
- name: Upload Linux Zip to GitHub
|
||||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||||
with:
|
with:
|
||||||
name: bwdc-linux-${{ env._PACKAGE_VERSION }}.zip
|
name: bwdc-linux-${{ env._PACKAGE_VERSION }}.zip
|
||||||
path: ./dist-cli/bwdc-linux-${{ env._PACKAGE_VERSION }}.zip
|
path: ./dist-cli/bwdc-linux-${{ env._PACKAGE_VERSION }}.zip
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Upload Linux checksum to GitHub
|
|
||||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
|
||||||
with:
|
|
||||||
name: bwdc-linux-sha256-${{ env._PACKAGE_VERSION }}.txt
|
|
||||||
path: ./dist-cli/bwdc-linux-sha256-${{ env._PACKAGE_VERSION }}.txt
|
|
||||||
if-no-files-found: error
|
|
||||||
|
|
||||||
|
|
||||||
macos-cli:
|
macos-cli:
|
||||||
name: Build Mac CLI
|
name: Build Mac CLI
|
||||||
runs-on: macos-12
|
runs-on: macos-15-intel
|
||||||
needs: setup
|
needs: setup
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
env:
|
env:
|
||||||
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
|
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
|
||||||
_PKG_FETCH_NODE_VERSION: 18.5.0
|
_NODE_VERSION: ${{ needs.setup.outputs.node_version }}
|
||||||
_PKG_FETCH_VERSION: 3.4
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
node-version: '18'
|
node-version: ${{ env._NODE_VERSION }}
|
||||||
|
|
||||||
- name: Update NPM
|
- name: Update NPM
|
||||||
run: |
|
run: |
|
||||||
npm install -g node-gyp
|
npm install -g node-gyp
|
||||||
node-gyp install $(node -v)
|
node-gyp install "$(node -v)"
|
||||||
|
|
||||||
- name: Get pkg-fetch
|
|
||||||
run: |
|
|
||||||
cd $HOME
|
|
||||||
fetchedUrl="https://github.com/vercel/pkg-fetch/releases/download/v$_PKG_FETCH_VERSION/node-v$_PKG_FETCH_NODE_VERSION-macos-x64"
|
|
||||||
|
|
||||||
mkdir -p .pkg-cache/v$_PKG_FETCH_VERSION
|
|
||||||
wget $fetchedUrl -O "./.pkg-cache/v$_PKG_FETCH_VERSION/fetched-v$_PKG_FETCH_NODE_VERSION-macos-x64"
|
|
||||||
|
|
||||||
- name: Keytar
|
- name: Keytar
|
||||||
run: |
|
run: |
|
||||||
@@ -174,8 +154,8 @@ jobs:
|
|||||||
keytarUrl="https://github.com/atom/node-keytar/releases/download/v$keytarVersion/$keytarTarGz"
|
keytarUrl="https://github.com/atom/node-keytar/releases/download/v$keytarVersion/$keytarTarGz"
|
||||||
|
|
||||||
mkdir -p ./keytar/macos
|
mkdir -p ./keytar/macos
|
||||||
wget $keytarUrl -O ./keytar/macos/$keytarTarGz
|
wget "$keytarUrl" -O "./keytar/macos/$keytarTarGz"
|
||||||
tar -xvf ./keytar/macos/$keytarTarGz -C ./keytar/macos
|
tar -xvf "./keytar/macos/$keytarTarGz" -C ./keytar/macos
|
||||||
|
|
||||||
- name: Install
|
- name: Install
|
||||||
run: npm install
|
run: npm install
|
||||||
@@ -184,17 +164,12 @@ jobs:
|
|||||||
run: npm run dist:cli:mac
|
run: npm run dist:cli:mac
|
||||||
|
|
||||||
- name: Zip
|
- name: Zip
|
||||||
run: zip -j dist-cli/bwdc-macos-$_PACKAGE_VERSION.zip dist-cli/macos/bwdc keytar/macos/build/Release/keytar.node
|
run: zip -j "dist-cli/bwdc-macos-$_PACKAGE_VERSION.zip" "dist-cli/macos/bwdc" "keytar/macos/build/Release/keytar.node"
|
||||||
|
|
||||||
- name: Create checksums
|
|
||||||
run: |
|
|
||||||
shasum -a 256 dist-cli/bwdc-macos-$_PACKAGE_VERSION.zip | \
|
|
||||||
cut -d " " -f 1 > dist-cli/bwdc-macos-sha256-$_PACKAGE_VERSION.txt
|
|
||||||
|
|
||||||
- name: Version Test
|
- name: Version Test
|
||||||
run: |
|
run: |
|
||||||
mkdir -p test/macos
|
mkdir -p test/macos
|
||||||
unzip ./dist-cli/bwdc-macos-$_PACKAGE_VERSION.zip -d ./test/macos
|
unzip "./dist-cli/bwdc-macos-$_PACKAGE_VERSION.zip" -d ./test/macos
|
||||||
|
|
||||||
testVersion=$(./test/macos/bwdc -v)
|
testVersion=$(./test/macos/bwdc -v)
|
||||||
|
|
||||||
@@ -207,59 +182,44 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Upload Mac Zip to GitHub
|
- name: Upload Mac Zip to GitHub
|
||||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||||
with:
|
with:
|
||||||
name: bwdc-macos-${{ env._PACKAGE_VERSION }}.zip
|
name: bwdc-macos-${{ env._PACKAGE_VERSION }}.zip
|
||||||
path: ./dist-cli/bwdc-macos-${{ env._PACKAGE_VERSION }}.zip
|
path: ./dist-cli/bwdc-macos-${{ env._PACKAGE_VERSION }}.zip
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Upload Mac checksum to GitHub
|
|
||||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
|
||||||
with:
|
|
||||||
name: bwdc-macos-sha256-${{ env._PACKAGE_VERSION }}.txt
|
|
||||||
path: ./dist-cli/bwdc-macos-sha256-${{ env._PACKAGE_VERSION }}.txt
|
|
||||||
if-no-files-found: error
|
|
||||||
|
|
||||||
windows-cli:
|
windows-cli:
|
||||||
name: Build Windows CLI
|
name: Build Windows CLI
|
||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
needs: setup
|
needs: setup
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
env:
|
env:
|
||||||
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
|
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
|
||||||
_WIN_PKG_FETCH_VERSION: 18.5.0
|
_NODE_VERSION: ${{ needs.setup.outputs.node_version }}
|
||||||
_WIN_PKG_VERSION: 3.4
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Setup Windows builder
|
- name: Setup Windows builder
|
||||||
run: |
|
run: |
|
||||||
choco install checksum --no-progress
|
choco install checksum --no-progress
|
||||||
choco install reshack --no-progress
|
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
node-version: '18'
|
node-version: ${{ env._NODE_VERSION }}
|
||||||
|
|
||||||
- name: Update NPM
|
- name: Update NPM
|
||||||
run: |
|
run: |
|
||||||
npm install -g node-gyp
|
npm install -g node-gyp
|
||||||
node-gyp install $(node -v)
|
node-gyp install $(node -v)
|
||||||
|
|
||||||
- name: Get pkg-fetch
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
cd $HOME
|
|
||||||
$fetchedUrl = "https://github.com/vercel/pkg-fetch/releases/download/v$env:_WIN_PKG_VERSION/node-v$env:_WIN_PKG_FETCH_VERSION-win-x64"
|
|
||||||
|
|
||||||
New-Item -ItemType directory -Path ./.pkg-cache
|
|
||||||
New-Item -ItemType directory -Path ./.pkg-cache/v$env:_WIN_PKG_VERSION
|
|
||||||
Invoke-RestMethod -Uri $fetchedUrl `
|
|
||||||
-OutFile "./.pkg-cache/v$env:_WIN_PKG_VERSION/fetched-v$env:_WIN_PKG_FETCH_VERSION-win-x64"
|
|
||||||
|
|
||||||
- name: Keytar
|
- name: Keytar
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
@@ -276,54 +236,6 @@ jobs:
|
|||||||
|
|
||||||
7z e "./keytar/windows/$($keytarTar -f "win32")" -o"./keytar/windows"
|
7z e "./keytar/windows/$($keytarTar -f "win32")" -o"./keytar/windows"
|
||||||
|
|
||||||
- name: Setup Version Info
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
$major, $minor, $patch = $env:_PACKAGE_VERSION.split('.')
|
|
||||||
|
|
||||||
$versionInfo = @"
|
|
||||||
|
|
||||||
1 VERSIONINFO
|
|
||||||
FILEVERSION $major,$minor,$patch,0
|
|
||||||
PRODUCTVERSION $major,$minor,$patch,0
|
|
||||||
FILEOS 0x40004
|
|
||||||
FILETYPE 0x1
|
|
||||||
{
|
|
||||||
BLOCK "StringFileInfo"
|
|
||||||
{
|
|
||||||
BLOCK "040904b0"
|
|
||||||
{
|
|
||||||
VALUE "CompanyName", "Bitwarden Inc."
|
|
||||||
VALUE "ProductName", "Bitwarden"
|
|
||||||
VALUE "FileDescription", "Bitwarden Directory Connector CLI"
|
|
||||||
VALUE "FileVersion", "$env:_PACKAGE_VERSION"
|
|
||||||
VALUE "ProductVersion", "$env:_PACKAGE_VERSION"
|
|
||||||
VALUE "OriginalFilename", "bwdc.exe"
|
|
||||||
VALUE "InternalName", "bwdc"
|
|
||||||
VALUE "LegalCopyright", "Copyright Bitwarden Inc."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BLOCK "VarFileInfo"
|
|
||||||
{
|
|
||||||
VALUE "Translation", 0x0409 0x04B0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"@
|
|
||||||
|
|
||||||
$versionInfo | Out-File ./version-info.rc
|
|
||||||
|
|
||||||
- name: Resource Hacker
|
|
||||||
shell: cmd
|
|
||||||
run: |
|
|
||||||
set PATH=%PATH%;C:\Program Files (x86)\Resource Hacker
|
|
||||||
set WIN_PKG=C:\Users\runneradmin\.pkg-cache\v%_WIN_PKG_VERSION%\fetched-v%_WIN_PKG_FETCH_VERSION%-win-x64
|
|
||||||
set WIN_PKG_BUILT=C:\Users\runneradmin\.pkg-cache\v%_WIN_PKG_VERSION%\built-v%_WIN_PKG_FETCH_VERSION%-win-x64
|
|
||||||
|
|
||||||
ResourceHacker -open %WIN_PKG% -save %WIN_PKG% -action delete -mask ICONGROUP,1,
|
|
||||||
ResourceHacker -open version-info.rc -save version-info.res -action compile
|
|
||||||
ResourceHacker -open %WIN_PKG% -save %WIN_PKG% -action addoverwrite -resource version-info.res
|
|
||||||
|
|
||||||
- name: Install
|
- name: Install
|
||||||
run: npm install
|
run: npm install
|
||||||
|
|
||||||
@@ -337,7 +249,7 @@ jobs:
|
|||||||
- name: Version Test
|
- name: Version Test
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
Expand-Archive -Path "dist-cli\bwdc-windows-${{ env._PACKAGE_VERSION }}.zip" -DestinationPath "test\windows"
|
Expand-Archive -Path "dist-cli\bwdc-windows-$env:_PACKAGE_VERSION.zip" -DestinationPath "test\windows"
|
||||||
$testVersion = Invoke-Expression '& .\test\windows\bwdc.exe -v'
|
$testVersion = Invoke-Expression '& .\test\windows\bwdc.exe -v'
|
||||||
echo "version: ${env:_PACKAGE_VERSION}"
|
echo "version: ${env:_PACKAGE_VERSION}"
|
||||||
echo "testVersion: $testVersion"
|
echo "testVersion: $testVersion"
|
||||||
@@ -345,44 +257,38 @@ jobs:
|
|||||||
Throw "Version test failed."
|
Throw "Version test failed."
|
||||||
}
|
}
|
||||||
|
|
||||||
- name: Create checksums
|
|
||||||
run: |
|
|
||||||
checksum -f="./dist-cli/bwdc-windows-${env:_PACKAGE_VERSION}.zip" `
|
|
||||||
-t sha256 | Out-File ./dist-cli/bwdc-windows-sha256-${env:_PACKAGE_VERSION}.txt
|
|
||||||
|
|
||||||
- name: Upload Windows Zip to GitHub
|
- name: Upload Windows Zip to GitHub
|
||||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||||
with:
|
with:
|
||||||
name: bwdc-windows-${{ env._PACKAGE_VERSION }}.zip
|
name: bwdc-windows-${{ env._PACKAGE_VERSION }}.zip
|
||||||
path: ./dist-cli/bwdc-windows-${{ env._PACKAGE_VERSION }}.zip
|
path: ./dist-cli/bwdc-windows-${{ env._PACKAGE_VERSION }}.zip
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Upload Windows checksum to GitHub
|
|
||||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
|
||||||
with:
|
|
||||||
name: bwdc-windows-sha256-${{ env._PACKAGE_VERSION }}.txt
|
|
||||||
path: ./dist-cli/bwdc-windows-sha256-${{ env._PACKAGE_VERSION }}.txt
|
|
||||||
if-no-files-found: error
|
|
||||||
|
|
||||||
|
|
||||||
windows-gui:
|
windows-gui:
|
||||||
name: Build Windows GUI
|
name: Build Windows GUI
|
||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
needs: setup
|
needs: setup
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
id-token: write
|
||||||
env:
|
env:
|
||||||
NODE_OPTIONS: --max_old_space_size=4096
|
NODE_OPTIONS: --max_old_space_size=4096
|
||||||
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
|
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
|
||||||
|
_NODE_VERSION: ${{ needs.setup.outputs.node_version }}
|
||||||
HUSKY: 0
|
HUSKY: 0
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
node-version: '18'
|
node-version: ${{ env._NODE_VERSION }}
|
||||||
|
|
||||||
- name: Update NPM
|
- name: Update NPM
|
||||||
run: |
|
run: |
|
||||||
@@ -400,39 +306,60 @@ jobs:
|
|||||||
- name: Install Node dependencies
|
- name: Install Node dependencies
|
||||||
run: npm install
|
run: npm install
|
||||||
|
|
||||||
|
- name: Log in to Azure
|
||||||
|
uses: bitwarden/gh-actions/azure-login@main
|
||||||
|
with:
|
||||||
|
subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
||||||
|
tenant_id: ${{ secrets.AZURE_TENANT_ID }}
|
||||||
|
client_id: ${{ secrets.AZURE_CLIENT_ID }}
|
||||||
|
|
||||||
|
- name: Retrieve secrets
|
||||||
|
id: retrieve-secrets
|
||||||
|
uses: bitwarden/gh-actions/get-keyvault-secrets@main
|
||||||
|
with:
|
||||||
|
keyvault: "bitwarden-ci"
|
||||||
|
secrets: "code-signing-vault-url,
|
||||||
|
code-signing-client-id,
|
||||||
|
code-signing-tenant-id,
|
||||||
|
code-signing-client-secret,
|
||||||
|
code-signing-cert-name"
|
||||||
|
|
||||||
|
- name: Log out from Azure
|
||||||
|
uses: bitwarden/gh-actions/azure-logout@main
|
||||||
|
|
||||||
- name: Build & Sign
|
- name: Build & Sign
|
||||||
run: npm run dist:win
|
run: npm run dist:win
|
||||||
env:
|
env:
|
||||||
ELECTRON_BUILDER_SIGN: 1
|
ELECTRON_BUILDER_SIGN: 1
|
||||||
SIGNING_VAULT_URL: ${{ secrets.SIGNING_VAULT_URL }}
|
SIGNING_VAULT_URL: ${{ steps.retrieve-secrets.outputs.code-signing-vault-url }}
|
||||||
SIGNING_CLIENT_ID: ${{ secrets.SIGNING_CLIENT_ID }}
|
SIGNING_CLIENT_ID: ${{ steps.retrieve-secrets.outputs.code-signing-client-id }}
|
||||||
SIGNING_TENANT_ID: ${{ secrets.SIGNING_TENANT_ID }}
|
SIGNING_TENANT_ID: ${{ steps.retrieve-secrets.outputs.code-signing-tenant-id }}
|
||||||
SIGNING_CLIENT_SECRET: ${{ secrets.SIGNING_CLIENT_SECRET }}
|
SIGNING_CLIENT_SECRET: ${{ steps.retrieve-secrets.outputs.code-signing-client-secret }}
|
||||||
SIGNING_CERT_NAME: ${{ secrets.SIGNING_CERT_NAME }}
|
SIGNING_CERT_NAME: ${{ steps.retrieve-secrets.outputs.code-signing-cert-name }}
|
||||||
|
|
||||||
- name: Upload Portable Executable to GitHub
|
- name: Upload Portable Executable to GitHub
|
||||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||||
with:
|
with:
|
||||||
name: Bitwarden-Connector-Portable-${{ env._PACKAGE_VERSION }}.exe
|
name: Bitwarden-Connector-Portable-${{ env._PACKAGE_VERSION }}.exe
|
||||||
path: ./dist/Bitwarden-Connector-Portable-${{ env._PACKAGE_VERSION }}.exe
|
path: ./dist/Bitwarden-Connector-Portable-${{ env._PACKAGE_VERSION }}.exe
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Upload Installer Executable to GitHub
|
- name: Upload Installer Executable to GitHub
|
||||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||||
with:
|
with:
|
||||||
name: Bitwarden-Connector-Installer-${{ env._PACKAGE_VERSION }}.exe
|
name: Bitwarden-Connector-Installer-${{ env._PACKAGE_VERSION }}.exe
|
||||||
path: ./dist/Bitwarden-Connector-Installer-${{ env._PACKAGE_VERSION }}.exe
|
path: ./dist/Bitwarden-Connector-Installer-${{ env._PACKAGE_VERSION }}.exe
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Upload Installer Executable Blockmap to GitHub
|
- name: Upload Installer Executable Blockmap to GitHub
|
||||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||||
with:
|
with:
|
||||||
name: Bitwarden-Connector-Installer-${{ env._PACKAGE_VERSION }}.exe.blockmap
|
name: Bitwarden-Connector-Installer-${{ env._PACKAGE_VERSION }}.exe.blockmap
|
||||||
path: ./dist/Bitwarden-Connector-Installer-${{ env._PACKAGE_VERSION }}.exe.blockmap
|
path: ./dist/Bitwarden-Connector-Installer-${{ env._PACKAGE_VERSION }}.exe.blockmap
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Upload latest auto-update artifact
|
- name: Upload latest auto-update artifact
|
||||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||||
with:
|
with:
|
||||||
name: latest.yml
|
name: latest.yml
|
||||||
path: ./dist/latest.yml
|
path: ./dist/latest.yml
|
||||||
@@ -441,27 +368,32 @@ jobs:
|
|||||||
|
|
||||||
linux-gui:
|
linux-gui:
|
||||||
name: Build Linux GUI
|
name: Build Linux GUI
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-24.04
|
||||||
needs: setup
|
needs: setup
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
env:
|
env:
|
||||||
NODE_OPTIONS: --max_old_space_size=4096
|
NODE_OPTIONS: --max_old_space_size=4096
|
||||||
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
|
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
|
||||||
|
_NODE_VERSION: ${{ needs.setup.outputs.node_version }}
|
||||||
HUSKY: 0
|
HUSKY: 0
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
node-version: '18'
|
node-version: ${{ env._NODE_VERSION }}
|
||||||
|
|
||||||
- name: Update NPM
|
- name: Update NPM
|
||||||
run: |
|
run: |
|
||||||
npm install -g node-gyp
|
npm install -g node-gyp
|
||||||
node-gyp install $(node -v)
|
node-gyp install "$(node -v)"
|
||||||
|
|
||||||
- name: Set up environment
|
- name: Set up environment
|
||||||
run: |
|
run: |
|
||||||
@@ -479,14 +411,14 @@ jobs:
|
|||||||
run: npm run dist:lin
|
run: npm run dist:lin
|
||||||
|
|
||||||
- name: Upload AppImage
|
- name: Upload AppImage
|
||||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||||
with:
|
with:
|
||||||
name: Bitwarden-Connector-${{ env._PACKAGE_VERSION }}-x86_64.AppImage
|
name: Bitwarden-Connector-${{ env._PACKAGE_VERSION }}-x86_64.AppImage
|
||||||
path: ./dist/Bitwarden-Connector-${{ env._PACKAGE_VERSION }}-x86_64.AppImage
|
path: ./dist/Bitwarden-Connector-${{ env._PACKAGE_VERSION }}-x86_64.AppImage
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Upload latest auto-update artifact
|
- name: Upload latest auto-update artifact
|
||||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||||
with:
|
with:
|
||||||
name: latest-linux.yml
|
name: latest-linux.yml
|
||||||
path: ./dist/latest-linux.yml
|
path: ./dist/latest-linux.yml
|
||||||
@@ -495,27 +427,33 @@ jobs:
|
|||||||
|
|
||||||
macos-gui:
|
macos-gui:
|
||||||
name: Build MacOS GUI
|
name: Build MacOS GUI
|
||||||
runs-on: macos-12
|
runs-on: macos-15-intel
|
||||||
needs: setup
|
needs: setup
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
id-token: write
|
||||||
env:
|
env:
|
||||||
NODE_OPTIONS: --max_old_space_size=4096
|
NODE_OPTIONS: --max_old_space_size=4096
|
||||||
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
|
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
|
||||||
|
_NODE_VERSION: ${{ needs.setup.outputs.node_version }}
|
||||||
HUSKY: 0
|
HUSKY: 0
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
node-version: '18'
|
node-version: ${{ env._NODE_VERSION }}
|
||||||
|
|
||||||
- name: Update NPM
|
- name: Update NPM
|
||||||
run: |
|
run: |
|
||||||
npm install -g node-gyp
|
npm install -g node-gyp
|
||||||
node-gyp install $(node -v)
|
node-gyp install "$(node -v)"
|
||||||
|
|
||||||
- name: Print environment
|
- name: Print environment
|
||||||
run: |
|
run: |
|
||||||
@@ -523,50 +461,61 @@ jobs:
|
|||||||
npm --version
|
npm --version
|
||||||
echo "GitHub ref: $GITHUB_REF"
|
echo "GitHub ref: $GITHUB_REF"
|
||||||
echo "GitHub event: $GITHUB_EVENT"
|
echo "GitHub event: $GITHUB_EVENT"
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Decrypt secrets
|
- name: Log in to Azure
|
||||||
env:
|
uses: bitwarden/gh-actions/azure-login@main
|
||||||
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }}
|
with:
|
||||||
shell: bash
|
subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
||||||
|
tenant_id: ${{ secrets.AZURE_TENANT_ID }}
|
||||||
|
client_id: ${{ secrets.AZURE_CLIENT_ID }}
|
||||||
|
|
||||||
|
- name: Get Azure Key Vault secrets
|
||||||
|
id: get-kv-secrets
|
||||||
|
uses: bitwarden/gh-actions/get-keyvault-secrets@main
|
||||||
|
with:
|
||||||
|
keyvault: gh-directory-connector
|
||||||
|
secrets: "KEYCHAIN-PASSWORD,APP-STORE-CONNECT-AUTH-KEY,APP-STORE-CONNECT-TEAM-ISSUER"
|
||||||
|
|
||||||
|
- name: Get certificates
|
||||||
run: |
|
run: |
|
||||||
mkdir -p $HOME/secrets
|
mkdir -p "$HOME/certificates"
|
||||||
|
|
||||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/devid-app-cert |
|
||||||
--output "$HOME/secrets/devid-app-cert.p12" \
|
jq -r .value | base64 -d > "$HOME/certificates/devid-app-cert.p12"
|
||||||
"$GITHUB_WORKSPACE/.github/secrets/devid-app-cert.p12.gpg"
|
|
||||||
|
|
||||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/devid-installer-cert |
|
||||||
--output "$HOME/secrets/devid-installer-cert.p12" \
|
jq -r .value | base64 -d > "$HOME/certificates/devid-installer-cert.p12"
|
||||||
"$GITHUB_WORKSPACE/.github/secrets/devid-installer-cert.p12.gpg"
|
|
||||||
|
|
||||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/macdev-cert |
|
||||||
--output "$HOME/secrets/macdev-cert.p12" \
|
jq -r .value | base64 -d > "$HOME/certificates/macdev-cert.p12"
|
||||||
"$GITHUB_WORKSPACE/.github/secrets/macdev-cert.p12.gpg"
|
|
||||||
|
- name: Log out from Azure
|
||||||
|
uses: bitwarden/gh-actions/azure-logout@main
|
||||||
|
|
||||||
- name: Set up keychain
|
- name: Set up keychain
|
||||||
env:
|
env:
|
||||||
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
KEYCHAIN_PASSWORD: ${{ steps.get-kv-secrets.outputs.KEYCHAIN-PASSWORD }}
|
||||||
DEVID_CERT_PASSWORD: ${{ secrets.DEVID_CERT_PASSWORD }}
|
|
||||||
MACDEV_CERT_PASSWORD: ${{ secrets.MACDEV_CERT_PASSWORD }}
|
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
security create-keychain -p $KEYCHAIN_PASSWORD build.keychain
|
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||||
security default-keychain -s build.keychain
|
security default-keychain -s build.keychain
|
||||||
security unlock-keychain -p $KEYCHAIN_PASSWORD build.keychain
|
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||||
security set-keychain-settings -lut 1200 build.keychain
|
security set-keychain-settings -lut 1200 build.keychain
|
||||||
security import "$HOME/secrets/devid-app-cert.p12" -k build.keychain -P $DEVID_CERT_PASSWORD \
|
|
||||||
|
security import "$HOME/certificates/devid-app-cert.p12" -k build.keychain -P "" \
|
||||||
-T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild
|
-T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild
|
||||||
security import "$HOME/secrets/devid-installer-cert.p12" -k build.keychain -P $DEVID_CERT_PASSWORD \
|
|
||||||
|
security import "$HOME/certificates/devid-installer-cert.p12" -k build.keychain -P "" \
|
||||||
-T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild
|
-T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild
|
||||||
security import "$HOME/secrets/macdev-cert.p12" -k build.keychain -P $MACDEV_CERT_PASSWORD \
|
|
||||||
|
security import "$HOME/certificates/macdev-cert.p12" -k build.keychain -P "" \
|
||||||
-T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild
|
-T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild
|
||||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD build.keychain
|
|
||||||
|
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain
|
||||||
|
|
||||||
- name: Load package version
|
- name: Load package version
|
||||||
run: |
|
run: |
|
||||||
$rootPath = $env:GITHUB_WORKSPACE;
|
$rootPath = $env:GITHUB_WORKSPACE;
|
||||||
$packageVersion = (Get-Content -Raw -Path $rootPath\package.json | ConvertFrom-Json).version;
|
$packageVersion = (Get-Content -Raw -Path "$rootPath\package.json" | ConvertFrom-Json).version;
|
||||||
|
|
||||||
Write-Output "Setting package version to $packageVersion";
|
Write-Output "Setting package version to $packageVersion";
|
||||||
Write-Output "PACKAGE_VERSION=$packageVersion" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append;
|
Write-Output "PACKAGE_VERSION=$packageVersion" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append;
|
||||||
@@ -575,36 +524,46 @@ jobs:
|
|||||||
- name: Install Node dependencies
|
- name: Install Node dependencies
|
||||||
run: npm install
|
run: npm install
|
||||||
|
|
||||||
|
- name: Set up private auth key
|
||||||
|
env:
|
||||||
|
_APP_STORE_CONNECT_AUTH_KEY: ${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-AUTH-KEY }}
|
||||||
|
run: |
|
||||||
|
mkdir ~/private_keys
|
||||||
|
cat << EOF > ~/private_keys/AuthKey_UFD296548T.p8
|
||||||
|
${_APP_STORE_CONNECT_AUTH_KEY}
|
||||||
|
EOF
|
||||||
|
|
||||||
- name: Build application
|
- name: Build application
|
||||||
run: npm run dist:mac
|
run: npm run dist:mac
|
||||||
env:
|
env:
|
||||||
APPLE_ID_USERNAME: ${{ secrets.APPLE_ID_USERNAME }}
|
APP_STORE_CONNECT_TEAM_ISSUER: ${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-TEAM-ISSUER }}
|
||||||
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
APP_STORE_CONNECT_AUTH_KEY: UFD296548T
|
||||||
|
APP_STORE_CONNECT_AUTH_KEY_PATH: ~/private_keys/AuthKey_UFD296548T.p8
|
||||||
CSC_FOR_PULL_REQUEST: true
|
CSC_FOR_PULL_REQUEST: true
|
||||||
|
|
||||||
- name: Upload .zip artifact
|
- name: Upload .zip artifact
|
||||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||||
with:
|
with:
|
||||||
name: Bitwarden-Connector-${{ env._PACKAGE_VERSION }}-mac.zip
|
name: Bitwarden-Connector-${{ env._PACKAGE_VERSION }}-mac.zip
|
||||||
path: ./dist/Bitwarden-Connector-${{ env._PACKAGE_VERSION }}-mac.zip
|
path: ./dist/Bitwarden-Connector-${{ env._PACKAGE_VERSION }}-mac.zip
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Upload .dmg artifact
|
- name: Upload .dmg artifact
|
||||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||||
with:
|
with:
|
||||||
name: Bitwarden-Connector-${{ env._PACKAGE_VERSION }}.dmg
|
name: Bitwarden-Connector-${{ env._PACKAGE_VERSION }}.dmg
|
||||||
path: ./dist/Bitwarden-Connector-${{ env._PACKAGE_VERSION }}.dmg
|
path: ./dist/Bitwarden-Connector-${{ env._PACKAGE_VERSION }}.dmg
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Upload .dmg Blockmap artifact
|
- name: Upload .dmg Blockmap artifact
|
||||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||||
with:
|
with:
|
||||||
name: Bitwarden-Connector-${{ env._PACKAGE_VERSION }}.dmg.blockmap
|
name: Bitwarden-Connector-${{ env._PACKAGE_VERSION }}.dmg.blockmap
|
||||||
path: ./dist/Bitwarden-Connector-${{ env._PACKAGE_VERSION }}.dmg.blockmap
|
path: ./dist/Bitwarden-Connector-${{ env._PACKAGE_VERSION }}.dmg.blockmap
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Upload latest auto-update artifact
|
- name: Upload latest auto-update artifact
|
||||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||||
with:
|
with:
|
||||||
name: latest-mac.yml
|
name: latest-mac.yml
|
||||||
path: ./dist/latest-mac.yml
|
path: ./dist/latest-mac.yml
|
||||||
@@ -613,9 +572,8 @@ jobs:
|
|||||||
|
|
||||||
check-failures:
|
check-failures:
|
||||||
name: Check for failures
|
name: Check for failures
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-24.04
|
||||||
needs:
|
needs:
|
||||||
- cloc
|
|
||||||
- setup
|
- setup
|
||||||
- linux-cli
|
- linux-cli
|
||||||
- macos-cli
|
- macos-cli
|
||||||
@@ -623,42 +581,24 @@ jobs:
|
|||||||
- windows-gui
|
- windows-gui
|
||||||
- linux-gui
|
- linux-gui
|
||||||
- macos-gui
|
- macos-gui
|
||||||
|
permissions:
|
||||||
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
- name: Check if any job failed
|
- name: Check if any job failed
|
||||||
if: ${{ (github.ref == 'refs/heads/main') || (github.ref == 'refs/heads/rc') }}
|
if: |
|
||||||
env:
|
(github.ref == 'refs/heads/main'
|
||||||
CLOC_STATUS: ${{ needs.cloc.result }}
|
|| github.ref == 'refs/heads/rc'
|
||||||
SETUP_STATUS: ${{ needs.setup.result }}
|
|| github.ref == 'refs/heads/hotfix-rc')
|
||||||
LINUX_CLI_STATUS: ${{ needs.linux-cli.result }}
|
&& contains(needs.*.result, 'failure')
|
||||||
MACOS_CLI_STATUS: ${{ needs.macos-cli.result }}
|
run: exit 1
|
||||||
WINDOWS_CLI_STATUS: ${{ needs.windows-cli.result }}
|
|
||||||
WINDOWS_GUI_STATUS: ${{ needs.windows-gui.result }}
|
|
||||||
LINUX_GUI_STATUS: ${{ needs.linux-gui.result }}
|
|
||||||
MACOS_GUI_STATUS: ${{ needs.macos-gui.result }}
|
|
||||||
run: |
|
|
||||||
if [ "$CLOC_STATUS" = "failure" ]; then
|
|
||||||
exit 1
|
|
||||||
elif [ "$SETUP_STATUS" = "failure" ]; then
|
|
||||||
exit 1
|
|
||||||
elif [ "$LINUX_CLI_STATUS" = "failure" ]; then
|
|
||||||
exit 1
|
|
||||||
elif [ "$MACOS_CLI_STATUS" = "failure" ]; then
|
|
||||||
exit 1
|
|
||||||
elif [ "$WINDOWS_CLI_STATUS" = "failure" ]; then
|
|
||||||
exit 1
|
|
||||||
elif [ "$WINDOWS_GUI_STATUS" = "failure" ]; then
|
|
||||||
exit 1
|
|
||||||
elif [ "$LINUX_GUI_STATUS" = "failure" ]; then
|
|
||||||
exit 1
|
|
||||||
elif [ "$MACOS_GUI_STATUS" = "failure" ]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Login to Azure - CI subscription
|
- name: Log in to Azure
|
||||||
uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.7
|
|
||||||
if: failure()
|
if: failure()
|
||||||
|
uses: bitwarden/gh-actions/azure-login@main
|
||||||
with:
|
with:
|
||||||
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
||||||
|
tenant_id: ${{ secrets.AZURE_TENANT_ID }}
|
||||||
|
client_id: ${{ secrets.AZURE_CLIENT_ID }}
|
||||||
|
|
||||||
- name: Retrieve secrets
|
- name: Retrieve secrets
|
||||||
id: retrieve-secrets
|
id: retrieve-secrets
|
||||||
@@ -668,8 +608,11 @@ jobs:
|
|||||||
keyvault: "bitwarden-ci"
|
keyvault: "bitwarden-ci"
|
||||||
secrets: "devops-alerts-slack-webhook-url"
|
secrets: "devops-alerts-slack-webhook-url"
|
||||||
|
|
||||||
|
- name: Log out from Azure
|
||||||
|
uses: bitwarden/gh-actions/azure-logout@main
|
||||||
|
|
||||||
- name: Notify Slack on failure
|
- name: Notify Slack on failure
|
||||||
uses: act10ns/slack@ed1309ab9862e57e9e583e51c7889486b9a00b0f # v2.0.0
|
uses: act10ns/slack@44541246747a30eb3102d87f7a4cc5471b0ffb7d # v2.1.0
|
||||||
if: failure()
|
if: failure()
|
||||||
env:
|
env:
|
||||||
SLACK_WEBHOOK_URL: ${{ steps.retrieve-secrets.outputs.devops-alerts-slack-webhook-url }}
|
SLACK_WEBHOOK_URL: ${{ steps.retrieve-secrets.outputs.devops-alerts-slack-webhook-url }}
|
||||||
|
|||||||
6
.github/workflows/enforce-labels.yml
vendored
6
.github/workflows/enforce-labels.yml
vendored
@@ -1,13 +1,15 @@
|
|||||||
---
|
|
||||||
name: Enforce PR labels
|
name: Enforce PR labels
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [labeled, unlabeled, opened, edited, synchronize]
|
types: [labeled, unlabeled, opened, edited, synchronize]
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: read
|
||||||
jobs:
|
jobs:
|
||||||
enforce-label:
|
enforce-label:
|
||||||
name: EnforceLabel
|
name: EnforceLabel
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- name: Enforce Label
|
- name: Enforce Label
|
||||||
uses: yogevbd/enforce-label-action@a3c219da6b8fa73f6ba62b68ff09c469b3a1c024 # 2.2.2
|
uses: yogevbd/enforce-label-action@a3c219da6b8fa73f6ba62b68ff09c469b3a1c024 # 2.2.2
|
||||||
|
|||||||
146
.github/workflows/integration-test.yml
vendored
Normal file
146
.github/workflows/integration-test.yml
vendored
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
name: Integration Testing
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
# Integration tests are slow, so only run them if relevant files have changed.
|
||||||
|
# This is done at the workflow level and at the job level.
|
||||||
|
# Make sure these triggers stay consistent with the 'changed-files' job.
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'main'
|
||||||
|
- 'rc'
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/integration-test.yml" # this file
|
||||||
|
- "docker-compose.yml" # any change to Docker configuration
|
||||||
|
- "package.json" # dependencies
|
||||||
|
- "utils/**" # any change to test fixtures
|
||||||
|
- "src/services/sync.service.ts" # core sync service used by all directory services
|
||||||
|
- "src/services/directory-services/ldap-directory.service*" # LDAP directory service
|
||||||
|
- "src/services/directory-services/gsuite-directory.service*" # Google Workspace directory service
|
||||||
|
# Add directory services here as we add test coverage
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/integration-test.yml" # this file
|
||||||
|
- "docker-compose.yml" # any change to Docker configuration
|
||||||
|
- "package.json" # dependencies
|
||||||
|
- "utils/**" # any change to test fixtures
|
||||||
|
- "src/services/sync.service.ts" # core sync service used by all directory services
|
||||||
|
- "src/services/directory-services/ldap-directory.service*" # LDAP directory service
|
||||||
|
- "src/services/directory-services/gsuite-directory.service*" # Google Workspace directory service
|
||||||
|
# Add directory services here as we add test coverage
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
checks: write # required by dorny/test-reporter to upload its results
|
||||||
|
id-token: write # required to use OIDC to login to Azure Key Vault
|
||||||
|
jobs:
|
||||||
|
testing:
|
||||||
|
name: Run tests
|
||||||
|
if: ${{ startsWith(github.head_ref, 'version_bump_') == false }}
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Check out repo
|
||||||
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Get Node version
|
||||||
|
id: retrieve-node-version
|
||||||
|
run: |
|
||||||
|
NODE_NVMRC=$(cat .nvmrc)
|
||||||
|
NODE_VERSION=${NODE_NVMRC/v/''}
|
||||||
|
echo "node_version=$NODE_VERSION" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Set up Node
|
||||||
|
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
|
with:
|
||||||
|
cache: 'npm'
|
||||||
|
cache-dependency-path: '**/package-lock.json'
|
||||||
|
node-version: ${{ steps.retrieve-node-version.outputs.node_version }}
|
||||||
|
|
||||||
|
- name: Install Node dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
# Get secrets from Azure Key Vault
|
||||||
|
- name: Azure Login
|
||||||
|
uses: bitwarden/gh-actions/azure-login@main
|
||||||
|
with:
|
||||||
|
subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
||||||
|
tenant_id: ${{ secrets.AZURE_TENANT_ID }}
|
||||||
|
client_id: ${{ secrets.AZURE_CLIENT_ID }}
|
||||||
|
|
||||||
|
- name: Get KV Secrets
|
||||||
|
id: get-kv-secrets
|
||||||
|
uses: bitwarden/gh-actions/get-keyvault-secrets@main
|
||||||
|
with:
|
||||||
|
keyvault: gh-directory-connector
|
||||||
|
secrets: "GOOGLE-ADMIN-USER,GOOGLE-CLIENT-EMAIL,GOOGLE-DOMAIN,GOOGLE-PRIVATE-KEY"
|
||||||
|
|
||||||
|
- name: Azure Logout
|
||||||
|
uses: bitwarden/gh-actions/azure-logout@main
|
||||||
|
|
||||||
|
# Only run relevant tests depending on what files have changed.
|
||||||
|
# This should be kept consistent with the workflow level triggers.
|
||||||
|
# Note: docker-compose.yml is only used for ldap for now
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
|
||||||
|
with:
|
||||||
|
list-files: shell
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
# Add directory services here as we add test coverage
|
||||||
|
filters: |
|
||||||
|
common:
|
||||||
|
- '.github/workflows/integration-test.yml'
|
||||||
|
- 'utils/**'
|
||||||
|
- 'package.json'
|
||||||
|
- 'src/services/sync.service.ts'
|
||||||
|
ldap:
|
||||||
|
- 'docker-compose.yml'
|
||||||
|
- 'src/services/directory-services/ldap-directory.service*'
|
||||||
|
google:
|
||||||
|
- 'src/services/directory-services/gsuite-directory.service*'
|
||||||
|
|
||||||
|
# LDAP
|
||||||
|
- name: Setup LDAP integration tests
|
||||||
|
if: steps.changed-files.outputs.common == 'true' || steps.changed-files.outputs.ldap == 'true'
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get -y install mkcert
|
||||||
|
npm run test:integration:setup
|
||||||
|
|
||||||
|
- name: Run LDAP integration tests
|
||||||
|
if: steps.changed-files.outputs.common == 'true' || steps.changed-files.outputs.ldap == 'true'
|
||||||
|
env:
|
||||||
|
JEST_JUNIT_UNIQUE_OUTPUT_NAME: "true" # avoids junit outputs from clashing
|
||||||
|
run: npx jest ldap-directory.service.integration.spec.ts --coverage --coverageDirectory=coverage-ldap
|
||||||
|
|
||||||
|
# Google Workspace
|
||||||
|
- name: Run Google Workspace integration tests
|
||||||
|
if: steps.changed-files.outputs.common == 'true' || steps.changed-files.outputs.google == 'true'
|
||||||
|
env:
|
||||||
|
GOOGLE_DOMAIN: ${{ steps.get-kv-secrets.outputs.GOOGLE-DOMAIN }}
|
||||||
|
GOOGLE_ADMIN_USER: ${{ steps.get-kv-secrets.outputs.GOOGLE-ADMIN-USER }}
|
||||||
|
GOOGLE_CLIENT_EMAIL: ${{ steps.get-kv-secrets.outputs.GOOGLE-CLIENT-EMAIL }}
|
||||||
|
GOOGLE_PRIVATE_KEY: ${{ steps.get-kv-secrets.outputs.GOOGLE-PRIVATE-KEY }}
|
||||||
|
JEST_JUNIT_UNIQUE_OUTPUT_NAME: "true" # avoids junit outputs from clashing
|
||||||
|
run: |
|
||||||
|
npx jest gsuite-directory.service.integration.spec.ts --coverage --coverageDirectory=coverage-google
|
||||||
|
|
||||||
|
- name: Report test results
|
||||||
|
id: report
|
||||||
|
uses: dorny/test-reporter@dc3a92680fcc15842eef52e8c4606ea7ce6bd3f3 # v2.1.1
|
||||||
|
# This will skip the job if it's a pull request from a fork, because that won't have permission to upload test results.
|
||||||
|
# PRs from the repository and all other events are OK.
|
||||||
|
if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || github.event.pull_request.head.repo.full_name == github.repository) && !cancelled()
|
||||||
|
with:
|
||||||
|
name: Test Results
|
||||||
|
path: "junit.xml*"
|
||||||
|
reporter: jest-junit
|
||||||
|
fail-on-error: true
|
||||||
|
|
||||||
|
- name: Upload coverage to codecov.io
|
||||||
|
uses: codecov/codecov-action@5a605bd92782ce0810fa3b8acc235c921b497052 # v5.2.0
|
||||||
|
|
||||||
|
- name: Upload results to codecov.io
|
||||||
|
uses: codecov/test-results-action@4e79e65778be1cecd5df25e14af1eafb6df80ea9 # v1.0.2
|
||||||
65
.github/workflows/release.yml
vendored
65
.github/workflows/release.yml
vendored
@@ -1,4 +1,3 @@
|
|||||||
---
|
|
||||||
name: Release
|
name: Release
|
||||||
|
|
||||||
on:
|
on:
|
||||||
@@ -14,18 +13,25 @@ on:
|
|||||||
- Redeploy
|
- Redeploy
|
||||||
- Dry Run
|
- Dry Run
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
setup:
|
setup:
|
||||||
name: Setup
|
name: Setup
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-24.04
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
outputs:
|
outputs:
|
||||||
release-version: ${{ steps.version.outputs.version }}
|
release_version: ${{ steps.version.outputs.version }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Branch check
|
- name: Branch check
|
||||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
if: ${{ inputs.release_type != 'Dry Run' }}
|
||||||
run: |
|
run: |
|
||||||
if [[ "$GITHUB_REF" != "refs/heads/rc" ]] && [[ "$GITHUB_REF" != "refs/heads/hotfix-rc" ]]; then
|
if [[ "$GITHUB_REF" != "refs/heads/rc" ]] && [[ "$GITHUB_REF" != "refs/heads/hotfix-rc" ]]; then
|
||||||
echo "==================================="
|
echo "==================================="
|
||||||
@@ -38,35 +44,29 @@ jobs:
|
|||||||
id: version
|
id: version
|
||||||
uses: bitwarden/gh-actions/release-version-check@main
|
uses: bitwarden/gh-actions/release-version-check@main
|
||||||
with:
|
with:
|
||||||
release-type: ${{ github.event.inputs.release_type }}
|
release-type: ${{ inputs.release_type }}
|
||||||
project-type: ts
|
project-type: ts
|
||||||
file: package.json
|
file: package.json
|
||||||
|
|
||||||
release:
|
release:
|
||||||
name: Release
|
name: Release
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-24.04
|
||||||
needs: setup
|
needs: setup
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
packages: read
|
||||||
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
- name: Create GitHub deployment
|
|
||||||
uses: chrnorm/deployment-action@d42cde7132fcec920de534fffc3be83794335c00 # v2.0.5
|
|
||||||
id: deployment
|
|
||||||
with:
|
|
||||||
token: '${{ secrets.GITHUB_TOKEN }}'
|
|
||||||
initial-status: 'in_progress'
|
|
||||||
environment: 'production'
|
|
||||||
description: 'Deployment ${{ needs.setup.outputs.release-version }} from branch ${{ github.ref_name }}'
|
|
||||||
task: release
|
|
||||||
|
|
||||||
- name: Download all artifacts
|
- name: Download all artifacts
|
||||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
if: ${{ inputs.release_type != 'Dry Run' }}
|
||||||
uses: bitwarden/gh-actions/download-artifacts@main
|
uses: bitwarden/gh-actions/download-artifacts@main
|
||||||
with:
|
with:
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
branch: ${{ github.ref_name }}
|
branch: ${{ github.ref_name }}
|
||||||
|
|
||||||
- name: Download all artifacts
|
- name: Dry Run - Download all artifacts
|
||||||
if: ${{ github.event.inputs.release_type == 'Dry Run' }}
|
if: ${{ inputs.release_type == 'Dry Run' }}
|
||||||
uses: bitwarden/gh-actions/download-artifacts@main
|
uses: bitwarden/gh-actions/download-artifacts@main
|
||||||
with:
|
with:
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
@@ -74,17 +74,14 @@ jobs:
|
|||||||
branch: main
|
branch: main
|
||||||
|
|
||||||
- name: Create release
|
- name: Create release
|
||||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
if: ${{ inputs.release_type != 'Dry Run' }}
|
||||||
uses: ncipollo/release-action@6c75be85e571768fa31b40abf38de58ba0397db5 # v1.13.0
|
uses: ncipollo/release-action@cdcc88a9acf3ca41c16c37bb7d21b9ad48560d87 # v1.15.0
|
||||||
env:
|
env:
|
||||||
PKG_VERSION: ${{ needs.setup.outputs.release-version }}
|
PKG_VERSION: ${{ needs.setup.outputs.release_version }}
|
||||||
with:
|
with:
|
||||||
artifacts: "./bwdc-windows-${{ env.PKG_VERSION }}.zip,
|
artifacts: "./bwdc-windows-${{ env.PKG_VERSION }}.zip,
|
||||||
./bwdc-macos-${{ env.PKG_VERSION }}.zip,
|
./bwdc-macos-${{ env.PKG_VERSION }}.zip,
|
||||||
./bwdc-linux-${{ env.PKG_VERSION }}.zip,
|
./bwdc-linux-${{ env.PKG_VERSION }}.zip,
|
||||||
./bwdc-windows-sha256-${{ env.PKG_VERSION }}.txt,
|
|
||||||
./bwdc-macos-sha256-${{ env.PKG_VERSION }}.txt,
|
|
||||||
./bwdc-linux-sha256-${{ env.PKG_VERSION }}.txt,
|
|
||||||
./Bitwarden-Connector-Portable-${{ env.PKG_VERSION }}.exe,
|
./Bitwarden-Connector-Portable-${{ env.PKG_VERSION }}.exe,
|
||||||
./Bitwarden-Connector-Installer-${{ env.PKG_VERSION }}.exe,
|
./Bitwarden-Connector-Installer-${{ env.PKG_VERSION }}.exe,
|
||||||
./Bitwarden-Connector-Installer-${{ env.PKG_VERSION }}.exe.blockmap,
|
./Bitwarden-Connector-Installer-${{ env.PKG_VERSION }}.exe.blockmap,
|
||||||
@@ -101,19 +98,3 @@ jobs:
|
|||||||
body: "<insert release notes here>"
|
body: "<insert release notes here>"
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
draft: true
|
draft: true
|
||||||
|
|
||||||
- name: Update deployment status to Success
|
|
||||||
if: ${{ success() }}
|
|
||||||
uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1
|
|
||||||
with:
|
|
||||||
token: '${{ secrets.GITHUB_TOKEN }}'
|
|
||||||
state: 'success'
|
|
||||||
deployment-id: ${{ steps.deployment.outputs.deployment_id }}
|
|
||||||
|
|
||||||
- name: Update deployment status to Failure
|
|
||||||
if: ${{ failure() }}
|
|
||||||
uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1
|
|
||||||
with:
|
|
||||||
token: '${{ secrets.GITHUB_TOKEN }}'
|
|
||||||
state: 'failure'
|
|
||||||
deployment-id: ${{ steps.deployment.outputs.deployment_id }}
|
|
||||||
|
|||||||
28
.github/workflows/respond.yml
vendored
Normal file
28
.github/workflows/respond.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
name: Respond
|
||||||
|
|
||||||
|
on:
|
||||||
|
issue_comment:
|
||||||
|
types: [created]
|
||||||
|
pull_request_review_comment:
|
||||||
|
types: [created]
|
||||||
|
issues:
|
||||||
|
types: [opened, assigned]
|
||||||
|
pull_request_review:
|
||||||
|
types: [submitted]
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
respond:
|
||||||
|
name: Respond
|
||||||
|
uses: bitwarden/gh-actions/.github/workflows/_respond.yml@main
|
||||||
|
secrets:
|
||||||
|
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
||||||
|
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
|
||||||
|
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: write
|
||||||
|
id-token: write
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
21
.github/workflows/review-code.yml
vendored
Normal file
21
.github/workflows/review-code.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
name: Code Review
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened, ready_for_review]
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
review:
|
||||||
|
name: Review
|
||||||
|
uses: bitwarden/gh-actions/.github/workflows/_review-code.yml@main
|
||||||
|
secrets:
|
||||||
|
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
||||||
|
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
|
||||||
|
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
id-token: write
|
||||||
|
pull-requests: write
|
||||||
52
.github/workflows/scan.yml
vendored
Normal file
52
.github/workflows/scan.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
name: Scan
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "main"
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
branches-ignore:
|
||||||
|
- "main"
|
||||||
|
pull_request_target:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
branches:
|
||||||
|
- "main"
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-run:
|
||||||
|
name: Check PR run
|
||||||
|
uses: bitwarden/gh-actions/.github/workflows/check-run.yml@main
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
sast:
|
||||||
|
name: Checkmarx
|
||||||
|
uses: bitwarden/gh-actions/.github/workflows/_checkmarx.yml@main
|
||||||
|
needs: check-run
|
||||||
|
secrets:
|
||||||
|
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
||||||
|
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
|
||||||
|
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
security-events: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
quality:
|
||||||
|
name: Sonar
|
||||||
|
uses: bitwarden/gh-actions/.github/workflows/_sonar.yml@main
|
||||||
|
needs: check-run
|
||||||
|
secrets:
|
||||||
|
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
||||||
|
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
|
||||||
|
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
54
.github/workflows/test.yml
vendored
54
.github/workflows/test.yml
vendored
@@ -1,5 +1,4 @@
|
|||||||
---
|
name: Testing
|
||||||
name: Run tests
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
@@ -7,40 +6,40 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- "main"
|
- "main"
|
||||||
- "rc"
|
- "rc"
|
||||||
- "hotfix-rc-*"
|
- "hotfix-rc"
|
||||||
pull_request: {}
|
pull_request:
|
||||||
|
|
||||||
defaults:
|
permissions:
|
||||||
run:
|
contents: read
|
||||||
shell: bash
|
checks: write # required by dorny/test-reporter to upload its results
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
|
||||||
|
testing:
|
||||||
name: Run tests
|
name: Run tests
|
||||||
runs-on: ubuntu-22.04
|
if: ${{ startsWith(github.head_ref, 'version_bump_') == false }}
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out repo
|
- name: Check out repo
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Get Node Version
|
- name: Get Node version
|
||||||
id: retrieve-node-version
|
id: retrieve-node-version
|
||||||
run: |
|
run: |
|
||||||
NODE_NVMRC=$(cat .nvmrc)
|
NODE_NVMRC=$(cat .nvmrc)
|
||||||
NODE_VERSION=${NODE_NVMRC/v/''}
|
NODE_VERSION=${NODE_NVMRC/v/''}
|
||||||
echo "node_version=$NODE_VERSION" >> $GITHUB_OUTPUT
|
echo "node_version=$NODE_VERSION" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0
|
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
cache-dependency-path: '**/package-lock.json'
|
cache-dependency-path: '**/package-lock.json'
|
||||||
node-version: ${{ steps.retrieve-node-version.outputs.node_version }}
|
node-version: ${{ steps.retrieve-node-version.outputs.node_version }}
|
||||||
|
|
||||||
- name: Print environment
|
|
||||||
run: |
|
|
||||||
node --version
|
|
||||||
npm --version
|
|
||||||
|
|
||||||
- name: Install Node dependencies
|
- name: Install Node dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
||||||
@@ -51,4 +50,21 @@ jobs:
|
|||||||
run: npm run test:types --coverage
|
run: npm run test:types --coverage
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: npm run test
|
run: npm run test --coverage
|
||||||
|
|
||||||
|
- name: Report test results
|
||||||
|
uses: dorny/test-reporter@dc3a92680fcc15842eef52e8c4606ea7ce6bd3f3 # v2.1.1
|
||||||
|
# This will skip the job if it's a pull request from a fork, because that won't have permission to upload test results.
|
||||||
|
# PRs from the repository and all other events are OK.
|
||||||
|
if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || github.event.pull_request.head.repo.full_name == github.repository) && !cancelled()
|
||||||
|
with:
|
||||||
|
name: Test Results
|
||||||
|
path: "junit.xml"
|
||||||
|
reporter: jest-junit
|
||||||
|
fail-on-error: true
|
||||||
|
|
||||||
|
- name: Upload coverage to codecov.io
|
||||||
|
uses: codecov/codecov-action@5a605bd92782ce0810fa3b8acc235c921b497052 # v5.2.0
|
||||||
|
|
||||||
|
- name: Upload results to codecov.io
|
||||||
|
uses: codecov/test-results-action@4e79e65778be1cecd5df25e14af1eafb6df80ea9 # v1.0.2
|
||||||
|
|||||||
203
.github/workflows/version-bump.yml
vendored
203
.github/workflows/version-bump.yml
vendored
@@ -1,65 +1,76 @@
|
|||||||
---
|
|
||||||
name: Version Bump
|
name: Version Bump
|
||||||
run-name: Version Bump - v${{ inputs.version_number }}
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
version_number:
|
version_number_override:
|
||||||
description: "New version (example: '2024.1.0')"
|
description: "New version override (leave blank for automatic calculation, example: '2024.1.0')"
|
||||||
required: true
|
required: false
|
||||||
type: string
|
type: string
|
||||||
cut_rc_branch:
|
|
||||||
description: "Cut RC branch?"
|
permissions: {}
|
||||||
default: true
|
|
||||||
type: boolean
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
bump_version:
|
bump_version:
|
||||||
name: "Bump Version to v${{ inputs.version_number }}"
|
name: Bump Version
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-24.04
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
- name: Login to Azure - CI Subscription
|
- name: Validate version input
|
||||||
uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.7
|
if: ${{ inputs.version_number_override != '' }}
|
||||||
|
uses: bitwarden/gh-actions/version-check@main
|
||||||
with:
|
with:
|
||||||
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
version: ${{ inputs.version_number_override }}
|
||||||
|
|
||||||
- name: Retrieve secrets
|
- name: Log in to Azure
|
||||||
id: retrieve-secrets
|
uses: bitwarden/gh-actions/azure-login@main
|
||||||
|
with:
|
||||||
|
subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
||||||
|
tenant_id: ${{ secrets.AZURE_TENANT_ID }}
|
||||||
|
client_id: ${{ secrets.AZURE_CLIENT_ID }}
|
||||||
|
|
||||||
|
- name: Get Azure Key Vault secrets
|
||||||
|
id: get-kv-secrets
|
||||||
uses: bitwarden/gh-actions/get-keyvault-secrets@main
|
uses: bitwarden/gh-actions/get-keyvault-secrets@main
|
||||||
with:
|
with:
|
||||||
keyvault: "bitwarden-ci"
|
keyvault: gh-org-bitwarden
|
||||||
secrets: "github-gpg-private-key,
|
secrets: "BW-GHAPP-ID,BW-GHAPP-KEY"
|
||||||
github-gpg-private-key-passphrase,
|
|
||||||
github-pat-bitwarden-devops-bot-repo-scope"
|
- name: Log out from Azure
|
||||||
|
uses: bitwarden/gh-actions/azure-logout@main
|
||||||
|
|
||||||
|
- name: Generate GH App token
|
||||||
|
uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
|
||||||
|
id: app-token
|
||||||
|
with:
|
||||||
|
app-id: ${{ steps.get-kv-secrets.outputs.BW-GHAPP-ID }}
|
||||||
|
private-key: ${{ steps.get-kv-secrets.outputs.BW-GHAPP-KEY }}
|
||||||
|
|
||||||
- name: Checkout Branch
|
- name: Checkout Branch
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
with:
|
with:
|
||||||
ref: main
|
token: ${{ steps.app-token.outputs.token }}
|
||||||
repository: bitwarden/directory-connector
|
persist-credentials: true
|
||||||
|
|
||||||
- name: Import GPG key
|
- name: Setup git
|
||||||
uses: crazy-max/ghaction-import-gpg@82a020f1f7f605c65dd2449b392a52c3fcfef7ef # v6.0.0
|
|
||||||
with:
|
|
||||||
gpg_private_key: ${{ steps.retrieve-secrets.outputs.github-gpg-private-key }}
|
|
||||||
passphrase: ${{ steps.retrieve-secrets.outputs.github-gpg-private-key-passphrase }}
|
|
||||||
git_user_signingkey: true
|
|
||||||
git_commit_gpgsign: true
|
|
||||||
|
|
||||||
- name: Create Version Branch
|
|
||||||
id: create-branch
|
|
||||||
run: |
|
run: |
|
||||||
NAME=version_bump_${{ github.ref_name }}_${{ inputs.version_number }}
|
git config user.name github-actions
|
||||||
git switch -c $NAME
|
git config user.email github-actions@github.com
|
||||||
echo "name=$NAME" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Verify input version
|
- name: Get current version
|
||||||
env:
|
id: current-version
|
||||||
NEW_VERSION: ${{ inputs.version_number }}
|
|
||||||
run: |
|
run: |
|
||||||
CURRENT_VERSION=$(cat package.json | jq -r '.version')
|
CURRENT_VERSION=$(cat package.json | jq -r '.version')
|
||||||
|
echo "version=$CURRENT_VERSION" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Verify input version
|
||||||
|
if: ${{ inputs.version_number_override != '' }}
|
||||||
|
env:
|
||||||
|
CURRENT_VERSION: ${{ steps.current-version.outputs.version }}
|
||||||
|
NEW_VERSION: ${{ inputs.version_number_override }}
|
||||||
|
run: |
|
||||||
# Error if version has not changed.
|
# Error if version has not changed.
|
||||||
if [[ "$NEW_VERSION" == "$CURRENT_VERSION" ]]; then
|
if [[ "$NEW_VERSION" == "$CURRENT_VERSION" ]]; then
|
||||||
echo "Version has not changed."
|
echo "Version has not changed."
|
||||||
@@ -67,103 +78,67 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if version is newer.
|
# Check if version is newer.
|
||||||
printf '%s\n' "${CURRENT_VERSION}" "${NEW_VERSION}" | sort -C -V
|
if printf '%s\n' "${CURRENT_VERSION}" "${NEW_VERSION}" | sort -C -V; then
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
echo "Version check successful."
|
echo "Version check successful."
|
||||||
else
|
else
|
||||||
echo "Version check failed."
|
echo "Version check failed."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Bump Version - Package
|
- name: Calculate next release version
|
||||||
|
if: ${{ inputs.version_number_override == '' }}
|
||||||
|
id: calculate-next-version
|
||||||
|
uses: bitwarden/gh-actions/version-next@main
|
||||||
|
with:
|
||||||
|
version: ${{ steps.current-version.outputs.version }}
|
||||||
|
|
||||||
|
- name: Bump Version - Package - Version Override
|
||||||
|
if: ${{ inputs.version_number_override != '' }}
|
||||||
|
id: bump-version-override
|
||||||
uses: bitwarden/gh-actions/version-bump@main
|
uses: bitwarden/gh-actions/version-bump@main
|
||||||
with:
|
with:
|
||||||
version: ${{ inputs.version_number }}
|
|
||||||
file_path: "./package.json"
|
file_path: "./package.json"
|
||||||
|
version: ${{ inputs.version_number_override }}
|
||||||
|
|
||||||
|
- name: Bump Version - Package - Automatic Calculation
|
||||||
|
if: ${{ inputs.version_number_override == '' }}
|
||||||
|
id: bump-version-automatic
|
||||||
|
uses: bitwarden/gh-actions/version-bump@main
|
||||||
|
with:
|
||||||
|
file_path: "./package.json"
|
||||||
|
version: ${{ steps.calculate-next-version.outputs.version }}
|
||||||
|
|
||||||
|
- name: Set final version output
|
||||||
|
id: set-final-version-output
|
||||||
|
env:
|
||||||
|
_BUMP_VERSION_OVERRIDE_OUTCOME: ${{ steps.bump-version-override.outcome }}
|
||||||
|
_INPUT_VERSION_NUMBER_OVERRIDE: ${{ inputs.version_number_override }}
|
||||||
|
_BUMP_VERSION_AUTOMATIC_OUTCOME: ${{ steps.bump-version-automatic.outcome }}
|
||||||
|
_CALCULATE_NEXT_VERSION: ${{ steps.calculate-next-version.outputs.version }}
|
||||||
|
|
||||||
- name: Setup git
|
|
||||||
run: |
|
run: |
|
||||||
git config --local user.email "106330231+bitwarden-devops-bot@users.noreply.github.com"
|
if [[ "$_BUMP_VERSION_OVERRIDE_OUTCOME" == "success" ]]; then
|
||||||
git config --local user.name "bitwarden-devops-bot"
|
echo "version=$_INPUT_VERSION_NUMBER_OVERRIDE" >> "$GITHUB_OUTPUT"
|
||||||
|
elif [[ "$_BUMP_VERSION_AUTOMATIC_OUTCOME" == "success" ]]; then
|
||||||
|
echo "version=$_CALCULATE_NEXT_VERSION" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Check if version changed
|
- name: Check if version changed
|
||||||
id: version-changed
|
id: version-changed
|
||||||
run: |
|
run: |
|
||||||
if [ -n "$(git status --porcelain)" ]; then
|
if [ -n "$(git status --porcelain)" ]; then
|
||||||
echo "changes_to_commit=TRUE" >> $GITHUB_OUTPUT
|
echo "changes_to_commit=TRUE" >> "$GITHUB_OUTPUT"
|
||||||
else
|
else
|
||||||
echo "changes_to_commit=FALSE" >> $GITHUB_OUTPUT
|
echo "changes_to_commit=FALSE" >> "$GITHUB_OUTPUT"
|
||||||
echo "No changes to commit!";
|
echo "No changes to commit!";
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Commit files
|
- name: Commit files
|
||||||
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
|
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
|
||||||
run: git commit -m "Bumped version to ${{ inputs.version_number }}" -a
|
env:
|
||||||
|
_VERSION: ${{ steps.set-final-version-output.outputs.version }}
|
||||||
|
run: git commit -m "Bumped version to $_VERSION" -a
|
||||||
|
|
||||||
- name: Push changes
|
- name: Push changes
|
||||||
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
|
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
|
||||||
env:
|
run: git push
|
||||||
PR_BRANCH: ${{ steps.create-branch.outputs.name }}
|
|
||||||
run: git push -u origin $PR_BRANCH
|
|
||||||
|
|
||||||
- name: Create Version PR
|
|
||||||
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
|
|
||||||
id: create-pr
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.retrieve-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
|
|
||||||
PR_BRANCH: ${{ steps.create-branch.outputs.name }}
|
|
||||||
TITLE: "Bump version to ${{ inputs.version_number }}"
|
|
||||||
run: |
|
|
||||||
PR_URL=$(gh pr create --title "$TITLE" \
|
|
||||||
--base "main" \
|
|
||||||
--head "$PR_BRANCH" \
|
|
||||||
--label "version update" \
|
|
||||||
--label "automated pr" \
|
|
||||||
--body "
|
|
||||||
## Type of change
|
|
||||||
- [ ] Bug fix
|
|
||||||
- [ ] New feature development
|
|
||||||
- [ ] Tech debt (refactoring, code cleanup, dependency upgrades, etc)
|
|
||||||
- [ ] Build/deploy pipeline (DevOps)
|
|
||||||
- [X] Other
|
|
||||||
|
|
||||||
## Objective
|
|
||||||
Automated version bump to ${{ inputs.version_number }}")
|
|
||||||
echo "pr_number=${PR_URL##*/}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Approve PR
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
PR_NUMBER: ${{ steps.create-pr.outputs.pr_number }}
|
|
||||||
run: gh pr review $PR_NUMBER --approve
|
|
||||||
|
|
||||||
- name: Merge PR
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.retrieve-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
|
|
||||||
PR_NUMBER: ${{ steps.create-pr.outputs.pr_number }}
|
|
||||||
run: gh pr merge $PR_NUMBER --squash --auto --delete-branch
|
|
||||||
|
|
||||||
cut_rc:
|
|
||||||
name: Cut RC branch
|
|
||||||
needs: bump_version
|
|
||||||
if: ${{ inputs.cut_rc_branch == true }}
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
steps:
|
|
||||||
- name: Checkout Branch
|
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
|
||||||
with:
|
|
||||||
ref: main
|
|
||||||
|
|
||||||
- name: Check if RC branch exists
|
|
||||||
run: |
|
|
||||||
remote_rc_branch_check=$(git ls-remote --heads origin rc | wc -l)
|
|
||||||
if [[ "${remote_rc_branch_check}" -gt 0 ]]; then
|
|
||||||
echo "Remote RC branch exists."
|
|
||||||
echo "Please delete current RC branch before running again."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Cut RC branch
|
|
||||||
run: |
|
|
||||||
git switch --quiet --create rc
|
|
||||||
git push --quiet --set-upstream origin rc
|
|
||||||
|
|||||||
11
.github/workflows/workflow-linter.yml
vendored
11
.github/workflows/workflow-linter.yml
vendored
@@ -1,11 +0,0 @@
|
|||||||
---
|
|
||||||
name: Workflow Linter
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- .github/workflows/**
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
call-workflow:
|
|
||||||
uses: bitwarden/gh-actions/.github/workflows/workflow-linter.yml@main
|
|
||||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -2,6 +2,9 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|
||||||
|
# Environment variables used for tests
|
||||||
|
.env
|
||||||
|
|
||||||
# IDEs and editors
|
# IDEs and editors
|
||||||
.idea/
|
.idea/
|
||||||
.project
|
.project
|
||||||
@@ -26,11 +29,12 @@ npm-debug.log
|
|||||||
# Build directories
|
# Build directories
|
||||||
dist
|
dist
|
||||||
build
|
build
|
||||||
|
build-cli
|
||||||
.angular/cache
|
.angular/cache
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
coverage
|
coverage*
|
||||||
junit.xml
|
junit.xml*
|
||||||
|
|
||||||
# Misc
|
# Misc
|
||||||
*.crx
|
*.crx
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
|
|
||||||
# Bitwarden Directory Connector
|
# Bitwarden Directory Connector
|
||||||
|
|
||||||
The Bitwarden Directory Connector is a a desktop application used to sync your Bitwarden enterprise organization to an existing directory of users and groups.
|
The Bitwarden Directory Connector is a desktop application used to sync your Bitwarden enterprise organization to an existing directory of users and groups.
|
||||||
|
|
||||||
Supported directories:
|
Supported directories:
|
||||||
|
|
||||||
- Active Directory
|
- Active Directory
|
||||||
- Any other LDAP-based directory
|
- Any other LDAP-based directory
|
||||||
- Azure Active Directory
|
- Microsoft Entra ID
|
||||||
- G Suite (Google)
|
- G Suite (Google)
|
||||||
- Okta
|
- Okta
|
||||||
|
|
||||||
|
|||||||
18
docker-compose.yml
Normal file
18
docker-compose.yml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
services:
|
||||||
|
open-ldap:
|
||||||
|
image: bitnamilegacy/openldap:latest
|
||||||
|
hostname: openldap
|
||||||
|
environment:
|
||||||
|
- LDAP_ADMIN_USERNAME=admin
|
||||||
|
- LDAP_ADMIN_PASSWORD=admin
|
||||||
|
- LDAP_ROOT=dc=bitwarden,dc=com
|
||||||
|
- LDAP_ENABLE_TLS=yes
|
||||||
|
- LDAP_TLS_CERT_FILE=/certs/openldap.pem
|
||||||
|
- LDAP_TLS_KEY_FILE=/certs/openldap-key.pem
|
||||||
|
- LDAP_TLS_CA_FILE=/certs/rootCA.pem
|
||||||
|
volumes:
|
||||||
|
- "./utils/openldap/ldifs:/ldifs"
|
||||||
|
- "./utils/openldap/certs:/certs"
|
||||||
|
ports:
|
||||||
|
- "1389:1389"
|
||||||
|
- "1636:1636"
|
||||||
@@ -11,6 +11,14 @@ module.exports = {
|
|||||||
// ...angularPreset,
|
// ...angularPreset,
|
||||||
preset: "jest-preset-angular",
|
preset: "jest-preset-angular",
|
||||||
|
|
||||||
|
reporters: ["default", "jest-junit"],
|
||||||
|
|
||||||
|
collectCoverage: true,
|
||||||
|
// Ensure we collect coverage from files without tests
|
||||||
|
collectCoverageFrom: ["src/**/*.ts"],
|
||||||
|
coverageReporters: ["html", "lcov"],
|
||||||
|
coverageDirectory: "coverage",
|
||||||
|
|
||||||
testEnvironment: "jsdom",
|
testEnvironment: "jsdom",
|
||||||
testMatch: ["**/+(*.)+(spec).+(ts)"],
|
testMatch: ["**/+(*.)+(spec).+(ts)"],
|
||||||
|
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
<div
|
|
||||||
#callout
|
|
||||||
class="callout callout-{{ calloutStyle }}"
|
|
||||||
[ngClass]="{ clickable: clickable }"
|
|
||||||
[attr.role]="useAlertRole ? 'alert' : null"
|
|
||||||
>
|
|
||||||
<h3 class="callout-heading" *ngIf="title">
|
|
||||||
<i class="bwi {{ icon }}" *ngIf="icon" aria-hidden="true"></i>
|
|
||||||
{{ title }}
|
|
||||||
</h3>
|
|
||||||
<div class="enforced-policy-options" *ngIf="enforcedPolicyOptions">
|
|
||||||
{{ enforcedPolicyMessage }}
|
|
||||||
<ul>
|
|
||||||
<li *ngIf="enforcedPolicyOptions?.minComplexity > 0">
|
|
||||||
{{ "policyInEffectMinComplexity" | i18n : getPasswordScoreAlertDisplay() }}
|
|
||||||
</li>
|
|
||||||
<li *ngIf="enforcedPolicyOptions?.minLength > 0">
|
|
||||||
{{ "policyInEffectMinLength" | i18n : enforcedPolicyOptions?.minLength.toString() }}
|
|
||||||
</li>
|
|
||||||
<li *ngIf="enforcedPolicyOptions?.requireUpper">
|
|
||||||
{{ "policyInEffectUppercase" | i18n }}
|
|
||||||
</li>
|
|
||||||
<li *ngIf="enforcedPolicyOptions?.requireLower">
|
|
||||||
{{ "policyInEffectLowercase" | i18n }}
|
|
||||||
</li>
|
|
||||||
<li *ngIf="enforcedPolicyOptions?.requireNumbers">
|
|
||||||
{{ "policyInEffectNumbers" | i18n }}
|
|
||||||
</li>
|
|
||||||
<li *ngIf="enforcedPolicyOptions?.requireSpecial">
|
|
||||||
{{ "policyInEffectSpecial" | i18n : "!@#$%^&*" }}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<ng-content></ng-content>
|
|
||||||
</div>
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
import { Component, Input, OnInit } from "@angular/core";
|
|
||||||
|
|
||||||
import { I18nService } from "@/jslib/common/src/abstractions/i18n.service";
|
|
||||||
import { MasterPasswordPolicyOptions } from "@/jslib/common/src/models/domain/masterPasswordPolicyOptions";
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: "app-callout",
|
|
||||||
templateUrl: "callout.component.html",
|
|
||||||
})
|
|
||||||
export class CalloutComponent implements OnInit {
|
|
||||||
@Input() type = "info";
|
|
||||||
@Input() icon: string;
|
|
||||||
@Input() title: string;
|
|
||||||
@Input() clickable: boolean;
|
|
||||||
@Input() enforcedPolicyOptions: MasterPasswordPolicyOptions;
|
|
||||||
@Input() enforcedPolicyMessage: string;
|
|
||||||
@Input() useAlertRole = false;
|
|
||||||
|
|
||||||
calloutStyle: string;
|
|
||||||
|
|
||||||
constructor(private i18nService: I18nService) {}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.calloutStyle = this.type;
|
|
||||||
|
|
||||||
if (this.enforcedPolicyMessage === undefined) {
|
|
||||||
this.enforcedPolicyMessage = this.i18nService.t("masterPasswordPolicyInEffect");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.type === "warning" || this.type === "danger") {
|
|
||||||
if (this.type === "danger") {
|
|
||||||
this.calloutStyle = "danger";
|
|
||||||
}
|
|
||||||
if (this.title === undefined) {
|
|
||||||
this.title = this.i18nService.t("warning");
|
|
||||||
}
|
|
||||||
if (this.icon === undefined) {
|
|
||||||
this.icon = "bwi-exclamation-triangle";
|
|
||||||
}
|
|
||||||
} else if (this.type === "error") {
|
|
||||||
this.calloutStyle = "danger";
|
|
||||||
if (this.title === undefined) {
|
|
||||||
this.title = this.i18nService.t("error");
|
|
||||||
}
|
|
||||||
if (this.icon === undefined) {
|
|
||||||
this.icon = "bwi-error";
|
|
||||||
}
|
|
||||||
} else if (this.type === "tip") {
|
|
||||||
this.calloutStyle = "success";
|
|
||||||
if (this.title === undefined) {
|
|
||||||
this.title = this.i18nService.t("tip");
|
|
||||||
}
|
|
||||||
if (this.icon === undefined) {
|
|
||||||
this.icon = "bwi-lightbulb";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getPasswordScoreAlertDisplay() {
|
|
||||||
if (this.enforcedPolicyOptions == null) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
let str: string;
|
|
||||||
switch (this.enforcedPolicyOptions.minComplexity) {
|
|
||||||
case 4:
|
|
||||||
str = this.i18nService.t("strong");
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
str = this.i18nService.t("good");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
str = this.i18nService.t("weak");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return str + " (" + this.enforcedPolicyOptions.minComplexity + ")";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -19,7 +19,7 @@ export class EnvironmentComponent {
|
|||||||
constructor(
|
constructor(
|
||||||
protected platformUtilsService: PlatformUtilsService,
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
protected environmentService: EnvironmentService,
|
protected environmentService: EnvironmentService,
|
||||||
protected i18nService: I18nService
|
protected i18nService: I18nService,
|
||||||
) {
|
) {
|
||||||
const urls = this.environmentService.getUrls();
|
const urls = this.environmentService.getUrls();
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
<div class="icon" aria-hidden="true">
|
|
||||||
<img
|
|
||||||
[src]="image"
|
|
||||||
appFallbackSrc="{{ fallbackImage }}"
|
|
||||||
*ngIf="imageEnabled && image"
|
|
||||||
alt=""
|
|
||||||
decoding="async"
|
|
||||||
loading="lazy"
|
|
||||||
/>
|
|
||||||
<i class="bwi bwi-fw bwi-lg {{ icon }}" *ngIf="!imageEnabled || !image"></i>
|
|
||||||
</div>
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
import { Component, Input, OnChanges } from "@angular/core";
|
|
||||||
|
|
||||||
import { EnvironmentService } from "@/jslib/common/src/abstractions/environment.service";
|
|
||||||
import { StateService } from "@/jslib/common/src/abstractions/state.service";
|
|
||||||
import { CipherType } from "@/jslib/common/src/enums/cipherType";
|
|
||||||
import { Utils } from "@/jslib/common/src/misc/utils";
|
|
||||||
import { CipherView } from "@/jslib/common/src/models/view/cipherView";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides a mapping from supported card brands to
|
|
||||||
* the filenames of icon that should be present in images/cards folder of clients.
|
|
||||||
*/
|
|
||||||
const cardIcons: Record<string, string> = {
|
|
||||||
Visa: "card-visa",
|
|
||||||
Mastercard: "card-mastercard",
|
|
||||||
Amex: "card-amex",
|
|
||||||
Discover: "card-discover",
|
|
||||||
"Diners Club": "card-diners-club",
|
|
||||||
JCB: "card-jcb",
|
|
||||||
Maestro: "card-maestro",
|
|
||||||
UnionPay: "card-union-pay",
|
|
||||||
};
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: "app-vault-icon",
|
|
||||||
templateUrl: "icon.component.html",
|
|
||||||
})
|
|
||||||
export class IconComponent implements OnChanges {
|
|
||||||
@Input() cipher: CipherView;
|
|
||||||
icon: string;
|
|
||||||
image: string;
|
|
||||||
fallbackImage: string;
|
|
||||||
imageEnabled: boolean;
|
|
||||||
|
|
||||||
private iconsUrl: string;
|
|
||||||
|
|
||||||
constructor(environmentService: EnvironmentService, private stateService: StateService) {
|
|
||||||
this.iconsUrl = environmentService.getIconsUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
async ngOnChanges() {
|
|
||||||
// Components may be re-used when using cdk-virtual-scroll. Which puts the component in a weird state,
|
|
||||||
// to avoid this we reset all state variables.
|
|
||||||
this.image = null;
|
|
||||||
this.fallbackImage = null;
|
|
||||||
this.imageEnabled = !(await this.stateService.getDisableFavicon());
|
|
||||||
this.load();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected load() {
|
|
||||||
switch (this.cipher.type) {
|
|
||||||
case CipherType.Login:
|
|
||||||
this.icon = "bwi-globe";
|
|
||||||
this.setLoginIcon();
|
|
||||||
break;
|
|
||||||
case CipherType.SecureNote:
|
|
||||||
this.icon = "bwi-sticky-note";
|
|
||||||
break;
|
|
||||||
case CipherType.Card:
|
|
||||||
this.icon = "bwi-credit-card";
|
|
||||||
this.setCardIcon();
|
|
||||||
break;
|
|
||||||
case CipherType.Identity:
|
|
||||||
this.icon = "bwi-id-card";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private setLoginIcon() {
|
|
||||||
if (this.cipher.login.uri) {
|
|
||||||
let hostnameUri = this.cipher.login.uri;
|
|
||||||
let isWebsite = false;
|
|
||||||
|
|
||||||
if (hostnameUri.indexOf("androidapp://") === 0) {
|
|
||||||
this.icon = "bwi-android";
|
|
||||||
this.image = null;
|
|
||||||
} else if (hostnameUri.indexOf("iosapp://") === 0) {
|
|
||||||
this.icon = "bwi-apple";
|
|
||||||
this.image = null;
|
|
||||||
} else if (
|
|
||||||
this.imageEnabled &&
|
|
||||||
hostnameUri.indexOf("://") === -1 &&
|
|
||||||
hostnameUri.indexOf(".") > -1
|
|
||||||
) {
|
|
||||||
hostnameUri = "http://" + hostnameUri;
|
|
||||||
isWebsite = true;
|
|
||||||
} else if (this.imageEnabled) {
|
|
||||||
isWebsite = hostnameUri.indexOf("http") === 0 && hostnameUri.indexOf(".") > -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.imageEnabled && isWebsite) {
|
|
||||||
try {
|
|
||||||
this.image = this.iconsUrl + "/" + Utils.getHostname(hostnameUri) + "/icon.png";
|
|
||||||
this.fallbackImage = "images/bwi-globe.png";
|
|
||||||
} catch (e) {
|
|
||||||
// Ignore error since the fallback icon will be shown if image is null.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.image = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private setCardIcon() {
|
|
||||||
const brand = this.cipher.card.brand;
|
|
||||||
if (this.imageEnabled && brand in cardIcons) {
|
|
||||||
this.icon = "credit-card-icon " + cardIcons[brand];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -35,7 +35,7 @@ export class DynamicModalComponent implements AfterViewInit, OnDestroy {
|
|||||||
private cd: ChangeDetectorRef,
|
private cd: ChangeDetectorRef,
|
||||||
private el: ElementRef<HTMLElement>,
|
private el: ElementRef<HTMLElement>,
|
||||||
private focusTrapFactory: ConfigurableFocusTrapFactory,
|
private focusTrapFactory: ConfigurableFocusTrapFactory,
|
||||||
public modalRef: ModalRef
|
public modalRef: ModalRef,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngAfterViewInit() {
|
ngAfterViewInit() {
|
||||||
@@ -47,7 +47,7 @@ export class DynamicModalComponent implements AfterViewInit, OnDestroy {
|
|||||||
|
|
||||||
this.modalRef.created(this.el.nativeElement);
|
this.modalRef.created(this.el.nativeElement);
|
||||||
this.focusTrap = this.focusTrapFactory.create(
|
this.focusTrap = this.focusTrapFactory.create(
|
||||||
this.el.nativeElement.querySelector(".modal-dialog")
|
this.el.nativeElement.querySelector(".modal-dialog"),
|
||||||
);
|
);
|
||||||
if (this.el.nativeElement.querySelector("[appAutoFocus]") == null) {
|
if (this.el.nativeElement.querySelector("[appAutoFocus]") == null) {
|
||||||
this.focusTrap.focusFirstTabbableElementWhenReady();
|
this.focusTrap.focusFirstTabbableElementWhenReady();
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
import { InjectFlags, InjectOptions, Injector, ProviderToken } from "@angular/core";
|
import { InjectOptions, Injector, ProviderToken } from "@angular/core";
|
||||||
|
|
||||||
export class ModalInjector implements Injector {
|
export class ModalInjector implements Injector {
|
||||||
constructor(private _parentInjector: Injector, private _additionalTokens: WeakMap<any, any>) {}
|
constructor(
|
||||||
|
private _parentInjector: Injector,
|
||||||
|
private _additionalTokens: WeakMap<any, any>,
|
||||||
|
) {}
|
||||||
|
|
||||||
get<T>(
|
get<T>(
|
||||||
token: ProviderToken<T>,
|
token: ProviderToken<T>,
|
||||||
notFoundValue: undefined,
|
notFoundValue: undefined,
|
||||||
options: InjectOptions & { optional?: false }
|
options: InjectOptions & { optional?: false },
|
||||||
): T;
|
): T;
|
||||||
get<T>(token: ProviderToken<T>, notFoundValue: null, options: InjectOptions): T;
|
get<T>(token: ProviderToken<T>, notFoundValue: null, options: InjectOptions): T;
|
||||||
get<T>(token: ProviderToken<T>, notFoundValue?: T, options?: InjectOptions | InjectFlags): T;
|
get<T>(token: ProviderToken<T>, notFoundValue?: T, options?: InjectOptions): T;
|
||||||
get<T>(token: ProviderToken<T>, notFoundValue?: T, flags?: InjectFlags): T;
|
|
||||||
get(token: any, notFoundValue?: any): any;
|
get(token: any, notFoundValue?: any): any;
|
||||||
get(token: any, notFoundValue?: any, flags?: any): any {
|
get(token: any, notFoundValue?: any, flags?: any): any {
|
||||||
return this._additionalTokens.get(token) ?? this._parentInjector.get<any>(token, notFoundValue);
|
return this._additionalTokens.get(token) ?? this._parentInjector.get<any>(token, notFoundValue);
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
import { Directive } from "@angular/core";
|
|
||||||
|
|
||||||
import { CryptoService } from "@/jslib/common/src/abstractions/crypto.service";
|
|
||||||
import { I18nService } from "@/jslib/common/src/abstractions/i18n.service";
|
|
||||||
import { PlatformUtilsService } from "@/jslib/common/src/abstractions/platformUtils.service";
|
|
||||||
|
|
||||||
import { ModalRef } from "./modal/modal.ref";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to verify the user's Master Password for the "Master Password Re-prompt" feature only.
|
|
||||||
* See UserVerificationComponent for any other situation where you need to verify the user's identity.
|
|
||||||
*/
|
|
||||||
@Directive()
|
|
||||||
export class PasswordRepromptComponent {
|
|
||||||
showPassword = false;
|
|
||||||
masterPassword = "";
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private modalRef: ModalRef,
|
|
||||||
private cryptoService: CryptoService,
|
|
||||||
private platformUtilsService: PlatformUtilsService,
|
|
||||||
private i18nService: I18nService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
togglePassword() {
|
|
||||||
this.showPassword = !this.showPassword;
|
|
||||||
}
|
|
||||||
|
|
||||||
async submit() {
|
|
||||||
if (!(await this.cryptoService.compareAndUpdateKeyHash(this.masterPassword, null))) {
|
|
||||||
this.platformUtilsService.showToast(
|
|
||||||
"error",
|
|
||||||
this.i18nService.t("errorOccurred"),
|
|
||||||
this.i18nService.t("invalidMasterPassword")
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.modalRef.close(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -60,9 +60,13 @@ import {
|
|||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
preserveWhitespaces: false,
|
preserveWhitespaces: false,
|
||||||
|
standalone: false,
|
||||||
})
|
})
|
||||||
export class BitwardenToast extends BaseToast {
|
export class BitwardenToast extends BaseToast {
|
||||||
constructor(protected toastrService: ToastrService, public toastPackage: ToastPackage) {
|
constructor(
|
||||||
|
protected toastrService: ToastrService,
|
||||||
|
public toastPackage: ToastPackage,
|
||||||
|
) {
|
||||||
super(toastrService, toastPackage);
|
super(toastrService, toastPackage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Directive, ElementRef, Input, Renderer2 } from "@angular/core";
|
|||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: "[appA11yTitle]",
|
selector: "[appA11yTitle]",
|
||||||
|
standalone: false,
|
||||||
})
|
})
|
||||||
export class A11yTitleDirective {
|
export class A11yTitleDirective {
|
||||||
@Input() set appA11yTitle(title: string) {
|
@Input() set appA11yTitle(title: string) {
|
||||||
@@ -10,7 +11,10 @@ export class A11yTitleDirective {
|
|||||||
|
|
||||||
private title: string;
|
private title: string;
|
||||||
|
|
||||||
constructor(private el: ElementRef, private renderer: Renderer2) {}
|
constructor(
|
||||||
|
private el: ElementRef,
|
||||||
|
private renderer: Renderer2,
|
||||||
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (!this.el.nativeElement.hasAttribute("title")) {
|
if (!this.el.nativeElement.hasAttribute("title")) {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { ValidationService } from "../services/validation.service";
|
|||||||
*/
|
*/
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: "[appApiAction]",
|
selector: "[appApiAction]",
|
||||||
|
standalone: false,
|
||||||
})
|
})
|
||||||
export class ApiActionDirective implements OnChanges {
|
export class ApiActionDirective implements OnChanges {
|
||||||
@Input() appApiAction: Promise<any>;
|
@Input() appApiAction: Promise<any>;
|
||||||
@@ -20,7 +21,7 @@ export class ApiActionDirective implements OnChanges {
|
|||||||
constructor(
|
constructor(
|
||||||
private el: ElementRef,
|
private el: ElementRef,
|
||||||
private validationService: ValidationService,
|
private validationService: ValidationService,
|
||||||
private logService: LogService
|
private logService: LogService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnChanges(changes: any) {
|
ngOnChanges(changes: any) {
|
||||||
@@ -43,7 +44,7 @@ export class ApiActionDirective implements OnChanges {
|
|||||||
}
|
}
|
||||||
this.logService?.error(`Received API exception: ${e}`);
|
this.logService?.error(`Received API exception: ${e}`);
|
||||||
this.validationService.showError(e);
|
this.validationService.showError(e);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Utils } from "@/jslib/common/src/misc/utils";
|
|||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: "[appAutofocus]",
|
selector: "[appAutofocus]",
|
||||||
|
standalone: false,
|
||||||
})
|
})
|
||||||
export class AutofocusDirective {
|
export class AutofocusDirective {
|
||||||
@Input() set appAutofocus(condition: boolean | string) {
|
@Input() set appAutofocus(condition: boolean | string) {
|
||||||
@@ -13,7 +14,10 @@ export class AutofocusDirective {
|
|||||||
|
|
||||||
private autofocus: boolean;
|
private autofocus: boolean;
|
||||||
|
|
||||||
constructor(private el: ElementRef, private ngZone: NgZone) {}
|
constructor(
|
||||||
|
private el: ElementRef,
|
||||||
|
private ngZone: NgZone,
|
||||||
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (!Utils.isMobileBrowser && this.autofocus) {
|
if (!Utils.isMobileBrowser && this.autofocus) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Directive, ElementRef, HostListener } from "@angular/core";
|
|||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: "[appBlurClick]",
|
selector: "[appBlurClick]",
|
||||||
|
standalone: false,
|
||||||
})
|
})
|
||||||
export class BlurClickDirective {
|
export class BlurClickDirective {
|
||||||
constructor(private el: ElementRef) {}
|
constructor(private el: ElementRef) {}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Directive, ElementRef, HostListener, OnInit } from "@angular/core";
|
|||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: "[appBoxRow]",
|
selector: "[appBoxRow]",
|
||||||
|
standalone: false,
|
||||||
})
|
})
|
||||||
export class BoxRowDirective implements OnInit {
|
export class BoxRowDirective implements OnInit {
|
||||||
el: HTMLElement = null;
|
el: HTMLElement = null;
|
||||||
@@ -13,7 +14,7 @@ export class BoxRowDirective implements OnInit {
|
|||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.formEls = Array.from(
|
this.formEls = Array.from(
|
||||||
this.el.querySelectorAll('input:not([type="hidden"]), select, textarea')
|
this.el.querySelectorAll('input:not([type="hidden"]), select, textarea'),
|
||||||
);
|
);
|
||||||
this.formEls.forEach((formEl) => {
|
this.formEls.forEach((formEl) => {
|
||||||
formEl.addEventListener(
|
formEl.addEventListener(
|
||||||
@@ -21,7 +22,7 @@ export class BoxRowDirective implements OnInit {
|
|||||||
() => {
|
() => {
|
||||||
this.el.classList.add("active");
|
this.el.classList.add("active");
|
||||||
},
|
},
|
||||||
false
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
formEl.addEventListener(
|
formEl.addEventListener(
|
||||||
@@ -29,7 +30,7 @@ export class BoxRowDirective implements OnInit {
|
|||||||
() => {
|
() => {
|
||||||
this.el.classList.remove("active");
|
this.el.classList.remove("active");
|
||||||
},
|
},
|
||||||
false
|
false,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Directive, ElementRef, HostListener, Input } from "@angular/core";
|
|||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: "[appFallbackSrc]",
|
selector: "[appFallbackSrc]",
|
||||||
|
standalone: false,
|
||||||
})
|
})
|
||||||
export class FallbackSrcDirective {
|
export class FallbackSrcDirective {
|
||||||
@Input("appFallbackSrc") appFallbackSrc: string;
|
@Input("appFallbackSrc") appFallbackSrc: string;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Directive, HostListener } from "@angular/core";
|
|||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: "[appStopClick]",
|
selector: "[appStopClick]",
|
||||||
|
standalone: false,
|
||||||
})
|
})
|
||||||
export class StopClickDirective {
|
export class StopClickDirective {
|
||||||
@HostListener("click", ["$event"]) onClick($event: MouseEvent) {
|
@HostListener("click", ["$event"]) onClick($event: MouseEvent) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Directive, HostListener } from "@angular/core";
|
|||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: "[appStopProp]",
|
selector: "[appStopProp]",
|
||||||
|
standalone: false,
|
||||||
})
|
})
|
||||||
export class StopPropDirective {
|
export class StopPropDirective {
|
||||||
@HostListener("click", ["$event"]) onClick($event: MouseEvent) {
|
@HostListener("click", ["$event"]) onClick($event: MouseEvent) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { I18nService } from "@/jslib/common/src/abstractions/i18n.service";
|
|||||||
|
|
||||||
@Pipe({
|
@Pipe({
|
||||||
name: "i18n",
|
name: "i18n",
|
||||||
|
standalone: false,
|
||||||
})
|
})
|
||||||
export class I18nPipe implements PipeTransform {
|
export class I18nPipe implements PipeTransform {
|
||||||
constructor(private i18nService: I18nService) {}
|
constructor(private i18nService: I18nService) {}
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
import { Pipe, PipeTransform } from "@angular/core";
|
|
||||||
|
|
||||||
import { CipherView } from "@/jslib/common/src/models/view/cipherView";
|
|
||||||
|
|
||||||
@Pipe({
|
|
||||||
name: "searchCiphers",
|
|
||||||
})
|
|
||||||
export class SearchCiphersPipe implements PipeTransform {
|
|
||||||
transform(ciphers: CipherView[], searchText: string, deleted = false): CipherView[] {
|
|
||||||
if (ciphers == null || ciphers.length === 0) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (searchText == null || searchText.length < 2) {
|
|
||||||
return ciphers.filter((c) => {
|
|
||||||
return deleted !== c.isDeleted;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
searchText = searchText.trim().toLowerCase();
|
|
||||||
return ciphers.filter((c) => {
|
|
||||||
if (deleted !== c.isDeleted) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (c.name != null && c.name.toLowerCase().indexOf(searchText) > -1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (searchText.length >= 8 && c.id.startsWith(searchText)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (c.subTitle != null && c.subTitle.toLowerCase().indexOf(searchText) > -1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (c.login && c.login.uri != null && c.login.uri.toLowerCase().indexOf(searchText) > -1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,8 @@ $icomoon-font-path: "/jslib/angular/src/scss/bwicons/fonts/" !default;
|
|||||||
// New font sheet? Update the font-face information below
|
// New font sheet? Update the font-face information below
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "#{$icomoon-font-family}";
|
font-family: "#{$icomoon-font-family}";
|
||||||
src: url($icomoon-font-path + "bwi-font.svg") format("svg"),
|
src:
|
||||||
|
url($icomoon-font-path + "bwi-font.svg") format("svg"),
|
||||||
url($icomoon-font-path + "bwi-font.ttf") format("truetype"),
|
url($icomoon-font-path + "bwi-font.ttf") format("truetype"),
|
||||||
url($icomoon-font-path + "bwi-font.woff") format("woff"),
|
url($icomoon-font-path + "bwi-font.woff") format("woff"),
|
||||||
url($icomoon-font-path + "bwi-font.woff2") format("woff2");
|
url($icomoon-font-path + "bwi-font.woff2") format("woff2");
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
import { Injectable } from "@angular/core";
|
|
||||||
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from "@angular/router";
|
|
||||||
|
|
||||||
import { KeyConnectorService } from "@/jslib/common/src/abstractions/keyConnector.service";
|
|
||||||
import { MessagingService } from "@/jslib/common/src/abstractions/messaging.service";
|
|
||||||
import { StateService } from "@/jslib/common/src/abstractions/state.service";
|
|
||||||
import { VaultTimeoutService } from "@/jslib/common/src/abstractions/vaultTimeout.service";
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class AuthGuardService implements CanActivate {
|
|
||||||
constructor(
|
|
||||||
private vaultTimeoutService: VaultTimeoutService,
|
|
||||||
private router: Router,
|
|
||||||
private messagingService: MessagingService,
|
|
||||||
private keyConnectorService: KeyConnectorService,
|
|
||||||
private stateService: StateService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async canActivate(route: ActivatedRouteSnapshot, routerState: RouterStateSnapshot) {
|
|
||||||
const isAuthed = await this.stateService.getIsAuthenticated();
|
|
||||||
if (!isAuthed) {
|
|
||||||
this.messagingService.send("authBlocked");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const locked = await this.vaultTimeoutService.isLocked();
|
|
||||||
if (locked) {
|
|
||||||
if (routerState != null) {
|
|
||||||
this.messagingService.send("lockedUrl", { url: routerState.url });
|
|
||||||
}
|
|
||||||
this.router.navigate(["lock"], { queryParams: { promptBiometric: true } });
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
!routerState.url.includes("remove-password") &&
|
|
||||||
(await this.keyConnectorService.getConvertAccountRequired())
|
|
||||||
) {
|
|
||||||
this.router.navigate(["/remove-password"]);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,188 +1,70 @@
|
|||||||
import { Injector, LOCALE_ID, NgModule } from "@angular/core";
|
import { LOCALE_ID, NgModule } from "@angular/core";
|
||||||
|
|
||||||
import { ApiService as ApiServiceAbstraction } from "@/jslib/common/src/abstractions/api.service";
|
import { ApiService as ApiServiceAbstraction } from "@/jslib/common/src/abstractions/api.service";
|
||||||
import { AppIdService as AppIdServiceAbstraction } from "@/jslib/common/src/abstractions/appId.service";
|
import { AppIdService as AppIdServiceAbstraction } from "@/jslib/common/src/abstractions/appId.service";
|
||||||
import { AuditService as AuditServiceAbstraction } from "@/jslib/common/src/abstractions/audit.service";
|
|
||||||
import { AuthService as AuthServiceAbstraction } from "@/jslib/common/src/abstractions/auth.service";
|
|
||||||
import { BroadcasterService as BroadcasterServiceAbstraction } from "@/jslib/common/src/abstractions/broadcaster.service";
|
import { BroadcasterService as BroadcasterServiceAbstraction } from "@/jslib/common/src/abstractions/broadcaster.service";
|
||||||
import { CipherService as CipherServiceAbstraction } from "@/jslib/common/src/abstractions/cipher.service";
|
|
||||||
import { CollectionService as CollectionServiceAbstraction } from "@/jslib/common/src/abstractions/collection.service";
|
|
||||||
import { CryptoService as CryptoServiceAbstraction } from "@/jslib/common/src/abstractions/crypto.service";
|
import { CryptoService as CryptoServiceAbstraction } from "@/jslib/common/src/abstractions/crypto.service";
|
||||||
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@/jslib/common/src/abstractions/cryptoFunction.service";
|
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@/jslib/common/src/abstractions/cryptoFunction.service";
|
||||||
import { EnvironmentService as EnvironmentServiceAbstraction } from "@/jslib/common/src/abstractions/environment.service";
|
import { EnvironmentService as EnvironmentServiceAbstraction } from "@/jslib/common/src/abstractions/environment.service";
|
||||||
import { EventService as EventServiceAbstraction } from "@/jslib/common/src/abstractions/event.service";
|
|
||||||
import { FileUploadService as FileUploadServiceAbstraction } from "@/jslib/common/src/abstractions/fileUpload.service";
|
|
||||||
import { FolderService as FolderServiceAbstraction } from "@/jslib/common/src/abstractions/folder.service";
|
|
||||||
import { I18nService as I18nServiceAbstraction } from "@/jslib/common/src/abstractions/i18n.service";
|
import { I18nService as I18nServiceAbstraction } from "@/jslib/common/src/abstractions/i18n.service";
|
||||||
import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@/jslib/common/src/abstractions/keyConnector.service";
|
|
||||||
import { LogService } from "@/jslib/common/src/abstractions/log.service";
|
import { LogService } from "@/jslib/common/src/abstractions/log.service";
|
||||||
import { MessagingService as MessagingServiceAbstraction } from "@/jslib/common/src/abstractions/messaging.service";
|
import { MessagingService as MessagingServiceAbstraction } from "@/jslib/common/src/abstractions/messaging.service";
|
||||||
import { NotificationsService as NotificationsServiceAbstraction } from "@/jslib/common/src/abstractions/notifications.service";
|
|
||||||
import { OrganizationService as OrganizationServiceAbstraction } from "@/jslib/common/src/abstractions/organization.service";
|
|
||||||
import { PasswordGenerationService as PasswordGenerationServiceAbstraction } from "@/jslib/common/src/abstractions/passwordGeneration.service";
|
|
||||||
import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "@/jslib/common/src/abstractions/passwordReprompt.service";
|
|
||||||
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@/jslib/common/src/abstractions/platformUtils.service";
|
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@/jslib/common/src/abstractions/platformUtils.service";
|
||||||
import { PolicyService as PolicyServiceAbstraction } from "@/jslib/common/src/abstractions/policy.service";
|
|
||||||
import { ProviderService as ProviderServiceAbstraction } from "@/jslib/common/src/abstractions/provider.service";
|
|
||||||
import { SearchService as SearchServiceAbstraction } from "@/jslib/common/src/abstractions/search.service";
|
|
||||||
import { SendService as SendServiceAbstraction } from "@/jslib/common/src/abstractions/send.service";
|
|
||||||
import { SettingsService as SettingsServiceAbstraction } from "@/jslib/common/src/abstractions/settings.service";
|
|
||||||
import { StateService as StateServiceAbstraction } from "@/jslib/common/src/abstractions/state.service";
|
import { StateService as StateServiceAbstraction } from "@/jslib/common/src/abstractions/state.service";
|
||||||
import { StateMigrationService as StateMigrationServiceAbstraction } from "@/jslib/common/src/abstractions/stateMigration.service";
|
import { StateMigrationService as StateMigrationServiceAbstraction } from "@/jslib/common/src/abstractions/stateMigration.service";
|
||||||
import { StorageService as StorageServiceAbstraction } from "@/jslib/common/src/abstractions/storage.service";
|
import { StorageService as StorageServiceAbstraction } from "@/jslib/common/src/abstractions/storage.service";
|
||||||
import { SyncService as SyncServiceAbstraction } from "@/jslib/common/src/abstractions/sync.service";
|
|
||||||
import { TokenService as TokenServiceAbstraction } from "@/jslib/common/src/abstractions/token.service";
|
import { TokenService as TokenServiceAbstraction } from "@/jslib/common/src/abstractions/token.service";
|
||||||
import { TotpService as TotpServiceAbstraction } from "@/jslib/common/src/abstractions/totp.service";
|
|
||||||
import { TwoFactorService as TwoFactorServiceAbstraction } from "@/jslib/common/src/abstractions/twoFactor.service";
|
|
||||||
import { UserVerificationService as UserVerificationServiceAbstraction } from "@/jslib/common/src/abstractions/userVerification.service";
|
|
||||||
import { UsernameGenerationService as UsernameGenerationServiceAbstraction } from "@/jslib/common/src/abstractions/usernameGeneration.service";
|
|
||||||
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "@/jslib/common/src/abstractions/vaultTimeout.service";
|
|
||||||
import { StateFactory } from "@/jslib/common/src/factories/stateFactory";
|
import { StateFactory } from "@/jslib/common/src/factories/stateFactory";
|
||||||
import { Account } from "@/jslib/common/src/models/domain/account";
|
import { Account } from "@/jslib/common/src/models/domain/account";
|
||||||
import { GlobalState } from "@/jslib/common/src/models/domain/globalState";
|
import { GlobalState } from "@/jslib/common/src/models/domain/globalState";
|
||||||
import { ApiService } from "@/jslib/common/src/services/api.service";
|
import { ApiService } from "@/jslib/common/src/services/api.service";
|
||||||
import { AppIdService } from "@/jslib/common/src/services/appId.service";
|
import { AppIdService } from "@/jslib/common/src/services/appId.service";
|
||||||
import { AuditService } from "@/jslib/common/src/services/audit.service";
|
|
||||||
import { AuthService } from "@/jslib/common/src/services/auth.service";
|
|
||||||
import { CipherService } from "@/jslib/common/src/services/cipher.service";
|
|
||||||
import { CollectionService } from "@/jslib/common/src/services/collection.service";
|
|
||||||
import { ConsoleLogService } from "@/jslib/common/src/services/consoleLog.service";
|
import { ConsoleLogService } from "@/jslib/common/src/services/consoleLog.service";
|
||||||
import { CryptoService } from "@/jslib/common/src/services/crypto.service";
|
import { CryptoService } from "@/jslib/common/src/services/crypto.service";
|
||||||
import { EnvironmentService } from "@/jslib/common/src/services/environment.service";
|
import { EnvironmentService } from "@/jslib/common/src/services/environment.service";
|
||||||
import { EventService } from "@/jslib/common/src/services/event.service";
|
|
||||||
import { FileUploadService } from "@/jslib/common/src/services/fileUpload.service";
|
|
||||||
import { FolderService } from "@/jslib/common/src/services/folder.service";
|
|
||||||
import { KeyConnectorService } from "@/jslib/common/src/services/keyConnector.service";
|
|
||||||
import { NotificationsService } from "@/jslib/common/src/services/notifications.service";
|
|
||||||
import { OrganizationService } from "@/jslib/common/src/services/organization.service";
|
|
||||||
import { PasswordGenerationService } from "@/jslib/common/src/services/passwordGeneration.service";
|
|
||||||
import { PolicyService } from "@/jslib/common/src/services/policy.service";
|
|
||||||
import { ProviderService } from "@/jslib/common/src/services/provider.service";
|
|
||||||
import { SearchService } from "@/jslib/common/src/services/search.service";
|
|
||||||
import { SendService } from "@/jslib/common/src/services/send.service";
|
|
||||||
import { SettingsService } from "@/jslib/common/src/services/settings.service";
|
|
||||||
import { StateService } from "@/jslib/common/src/services/state.service";
|
import { StateService } from "@/jslib/common/src/services/state.service";
|
||||||
import { StateMigrationService } from "@/jslib/common/src/services/stateMigration.service";
|
import { StateMigrationService } from "@/jslib/common/src/services/stateMigration.service";
|
||||||
import { SyncService } from "@/jslib/common/src/services/sync.service";
|
|
||||||
import { TokenService } from "@/jslib/common/src/services/token.service";
|
import { TokenService } from "@/jslib/common/src/services/token.service";
|
||||||
import { TotpService } from "@/jslib/common/src/services/totp.service";
|
|
||||||
import { TwoFactorService } from "@/jslib/common/src/services/twoFactor.service";
|
|
||||||
import { UserVerificationService } from "@/jslib/common/src/services/userVerification.service";
|
|
||||||
import { UsernameGenerationService } from "@/jslib/common/src/services/usernameGeneration.service";
|
|
||||||
import { VaultTimeoutService } from "@/jslib/common/src/services/vaultTimeout.service";
|
|
||||||
|
|
||||||
import { AuthGuardService } from "./auth-guard.service";
|
import {
|
||||||
|
SafeInjectionToken,
|
||||||
|
SECURE_STORAGE,
|
||||||
|
WINDOW,
|
||||||
|
} from "../../../../src/app/services/injection-tokens";
|
||||||
|
import { SafeProvider, safeProvider } from "../../../../src/app/services/safe-provider";
|
||||||
|
|
||||||
import { BroadcasterService } from "./broadcaster.service";
|
import { BroadcasterService } from "./broadcaster.service";
|
||||||
import { LockGuardService } from "./lock-guard.service";
|
|
||||||
import { ModalService } from "./modal.service";
|
import { ModalService } from "./modal.service";
|
||||||
import { PasswordRepromptService } from "./passwordReprompt.service";
|
|
||||||
import { UnauthGuardService } from "./unauth-guard.service";
|
|
||||||
import { ValidationService } from "./validation.service";
|
import { ValidationService } from "./validation.service";
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [],
|
declarations: [],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: "WINDOW", useValue: window },
|
safeProvider({ provide: WINDOW, useValue: window }),
|
||||||
{
|
safeProvider({
|
||||||
provide: LOCALE_ID,
|
provide: LOCALE_ID as SafeInjectionToken<string>,
|
||||||
useFactory: (i18nService: I18nServiceAbstraction) => i18nService.translationLocale,
|
useFactory: (i18nService: I18nServiceAbstraction) => i18nService.translationLocale,
|
||||||
deps: [I18nServiceAbstraction],
|
deps: [I18nServiceAbstraction],
|
||||||
},
|
}),
|
||||||
ValidationService,
|
safeProvider(ValidationService),
|
||||||
AuthGuardService,
|
safeProvider(ModalService),
|
||||||
UnauthGuardService,
|
safeProvider({
|
||||||
LockGuardService,
|
|
||||||
ModalService,
|
|
||||||
{
|
|
||||||
provide: AppIdServiceAbstraction,
|
provide: AppIdServiceAbstraction,
|
||||||
useClass: AppIdService,
|
useClass: AppIdService,
|
||||||
deps: [StorageServiceAbstraction],
|
deps: [StorageServiceAbstraction],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({ provide: LogService, useFactory: () => new ConsoleLogService(false), deps: [] }),
|
||||||
provide: AuditServiceAbstraction,
|
safeProvider({
|
||||||
useClass: AuditService,
|
|
||||||
deps: [CryptoFunctionServiceAbstraction, ApiServiceAbstraction],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: AuthServiceAbstraction,
|
|
||||||
useClass: AuthService,
|
|
||||||
deps: [
|
|
||||||
CryptoServiceAbstraction,
|
|
||||||
ApiServiceAbstraction,
|
|
||||||
TokenServiceAbstraction,
|
|
||||||
AppIdServiceAbstraction,
|
|
||||||
PlatformUtilsServiceAbstraction,
|
|
||||||
MessagingServiceAbstraction,
|
|
||||||
LogService,
|
|
||||||
KeyConnectorServiceAbstraction,
|
|
||||||
EnvironmentServiceAbstraction,
|
|
||||||
StateServiceAbstraction,
|
|
||||||
TwoFactorServiceAbstraction,
|
|
||||||
I18nServiceAbstraction,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: CipherServiceAbstraction,
|
|
||||||
useFactory: (
|
|
||||||
cryptoService: CryptoServiceAbstraction,
|
|
||||||
settingsService: SettingsServiceAbstraction,
|
|
||||||
apiService: ApiServiceAbstraction,
|
|
||||||
fileUploadService: FileUploadServiceAbstraction,
|
|
||||||
i18nService: I18nServiceAbstraction,
|
|
||||||
injector: Injector,
|
|
||||||
logService: LogService,
|
|
||||||
stateService: StateServiceAbstraction
|
|
||||||
) =>
|
|
||||||
new CipherService(
|
|
||||||
cryptoService,
|
|
||||||
settingsService,
|
|
||||||
apiService,
|
|
||||||
fileUploadService,
|
|
||||||
i18nService,
|
|
||||||
() => injector.get(SearchServiceAbstraction),
|
|
||||||
logService,
|
|
||||||
stateService
|
|
||||||
),
|
|
||||||
deps: [
|
|
||||||
CryptoServiceAbstraction,
|
|
||||||
SettingsServiceAbstraction,
|
|
||||||
ApiServiceAbstraction,
|
|
||||||
FileUploadServiceAbstraction,
|
|
||||||
I18nServiceAbstraction,
|
|
||||||
Injector, // TODO: Get rid of this circular dependency!
|
|
||||||
LogService,
|
|
||||||
StateServiceAbstraction,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: FolderServiceAbstraction,
|
|
||||||
useClass: FolderService,
|
|
||||||
deps: [
|
|
||||||
CryptoServiceAbstraction,
|
|
||||||
ApiServiceAbstraction,
|
|
||||||
I18nServiceAbstraction,
|
|
||||||
CipherServiceAbstraction,
|
|
||||||
StateServiceAbstraction,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{ provide: LogService, useFactory: () => new ConsoleLogService(false) },
|
|
||||||
{
|
|
||||||
provide: CollectionServiceAbstraction,
|
|
||||||
useClass: CollectionService,
|
|
||||||
deps: [CryptoServiceAbstraction, I18nServiceAbstraction, StateServiceAbstraction],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: EnvironmentServiceAbstraction,
|
provide: EnvironmentServiceAbstraction,
|
||||||
useClass: EnvironmentService,
|
useClass: EnvironmentService,
|
||||||
deps: [StateServiceAbstraction],
|
deps: [StateServiceAbstraction],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: TotpServiceAbstraction,
|
provide: TokenServiceAbstraction,
|
||||||
useClass: TotpService,
|
useClass: TokenService,
|
||||||
deps: [CryptoFunctionServiceAbstraction, LogService, StateServiceAbstraction],
|
deps: [StateServiceAbstraction],
|
||||||
},
|
}),
|
||||||
{ provide: TokenServiceAbstraction, useClass: TokenService, deps: [StateServiceAbstraction] },
|
safeProvider({
|
||||||
{
|
|
||||||
provide: CryptoServiceAbstraction,
|
provide: CryptoServiceAbstraction,
|
||||||
useClass: CryptoService,
|
useClass: CryptoService,
|
||||||
deps: [
|
deps: [
|
||||||
@@ -191,32 +73,22 @@ import { ValidationService } from "./validation.service";
|
|||||||
LogService,
|
LogService,
|
||||||
StateServiceAbstraction,
|
StateServiceAbstraction,
|
||||||
],
|
],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: PasswordGenerationServiceAbstraction,
|
|
||||||
useClass: PasswordGenerationService,
|
|
||||||
deps: [CryptoServiceAbstraction, PolicyServiceAbstraction, StateServiceAbstraction],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: UsernameGenerationServiceAbstraction,
|
|
||||||
useClass: UsernameGenerationService,
|
|
||||||
deps: [CryptoServiceAbstraction, StateServiceAbstraction],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: ApiServiceAbstraction,
|
provide: ApiServiceAbstraction,
|
||||||
useFactory: (
|
useFactory: (
|
||||||
tokenService: TokenServiceAbstraction,
|
tokenService: TokenServiceAbstraction,
|
||||||
platformUtilsService: PlatformUtilsServiceAbstraction,
|
platformUtilsService: PlatformUtilsServiceAbstraction,
|
||||||
environmentService: EnvironmentServiceAbstraction,
|
environmentService: EnvironmentServiceAbstraction,
|
||||||
messagingService: MessagingServiceAbstraction,
|
messagingService: MessagingServiceAbstraction,
|
||||||
appIdService: AppIdServiceAbstraction
|
appIdService: AppIdServiceAbstraction,
|
||||||
) =>
|
) =>
|
||||||
new ApiService(
|
new ApiService(
|
||||||
tokenService,
|
tokenService,
|
||||||
platformUtilsService,
|
platformUtilsService,
|
||||||
environmentService,
|
environmentService,
|
||||||
appIdService,
|
appIdService,
|
||||||
async (expired: boolean) => messagingService.send("logout", { expired: expired })
|
async (expired: boolean) => messagingService.send("logout", { expired: expired }),
|
||||||
),
|
),
|
||||||
deps: [
|
deps: [
|
||||||
TokenServiceAbstraction,
|
TokenServiceAbstraction,
|
||||||
@@ -225,250 +97,47 @@ import { ValidationService } from "./validation.service";
|
|||||||
MessagingServiceAbstraction,
|
MessagingServiceAbstraction,
|
||||||
AppIdServiceAbstraction,
|
AppIdServiceAbstraction,
|
||||||
],
|
],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: FileUploadServiceAbstraction,
|
provide: BroadcasterServiceAbstraction,
|
||||||
useClass: FileUploadService,
|
useClass: BroadcasterService,
|
||||||
deps: [LogService, ApiServiceAbstraction],
|
useAngularDecorators: true,
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: SyncServiceAbstraction,
|
|
||||||
useFactory: (
|
|
||||||
apiService: ApiServiceAbstraction,
|
|
||||||
settingsService: SettingsServiceAbstraction,
|
|
||||||
folderService: FolderServiceAbstraction,
|
|
||||||
cipherService: CipherServiceAbstraction,
|
|
||||||
cryptoService: CryptoServiceAbstraction,
|
|
||||||
collectionService: CollectionServiceAbstraction,
|
|
||||||
messagingService: MessagingServiceAbstraction,
|
|
||||||
policyService: PolicyServiceAbstraction,
|
|
||||||
sendService: SendServiceAbstraction,
|
|
||||||
logService: LogService,
|
|
||||||
keyConnectorService: KeyConnectorServiceAbstraction,
|
|
||||||
stateService: StateServiceAbstraction,
|
|
||||||
organizationService: OrganizationServiceAbstraction,
|
|
||||||
providerService: ProviderServiceAbstraction
|
|
||||||
) =>
|
|
||||||
new SyncService(
|
|
||||||
apiService,
|
|
||||||
settingsService,
|
|
||||||
folderService,
|
|
||||||
cipherService,
|
|
||||||
cryptoService,
|
|
||||||
collectionService,
|
|
||||||
messagingService,
|
|
||||||
policyService,
|
|
||||||
sendService,
|
|
||||||
logService,
|
|
||||||
keyConnectorService,
|
|
||||||
stateService,
|
|
||||||
organizationService,
|
|
||||||
providerService,
|
|
||||||
async (expired: boolean) => messagingService.send("logout", { expired: expired })
|
|
||||||
),
|
|
||||||
deps: [
|
|
||||||
ApiServiceAbstraction,
|
|
||||||
SettingsServiceAbstraction,
|
|
||||||
FolderServiceAbstraction,
|
|
||||||
CipherServiceAbstraction,
|
|
||||||
CryptoServiceAbstraction,
|
|
||||||
CollectionServiceAbstraction,
|
|
||||||
MessagingServiceAbstraction,
|
|
||||||
PolicyServiceAbstraction,
|
|
||||||
SendServiceAbstraction,
|
|
||||||
LogService,
|
|
||||||
KeyConnectorServiceAbstraction,
|
|
||||||
StateServiceAbstraction,
|
|
||||||
OrganizationServiceAbstraction,
|
|
||||||
ProviderServiceAbstraction,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{ provide: BroadcasterServiceAbstraction, useClass: BroadcasterService },
|
|
||||||
{
|
|
||||||
provide: SettingsServiceAbstraction,
|
|
||||||
useClass: SettingsService,
|
|
||||||
deps: [StateServiceAbstraction],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: VaultTimeoutServiceAbstraction,
|
|
||||||
useFactory: (
|
|
||||||
cipherService: CipherServiceAbstraction,
|
|
||||||
folderService: FolderServiceAbstraction,
|
|
||||||
collectionService: CollectionServiceAbstraction,
|
|
||||||
cryptoService: CryptoServiceAbstraction,
|
|
||||||
platformUtilsService: PlatformUtilsServiceAbstraction,
|
|
||||||
messagingService: MessagingServiceAbstraction,
|
|
||||||
searchService: SearchServiceAbstraction,
|
|
||||||
tokenService: TokenServiceAbstraction,
|
|
||||||
policyService: PolicyServiceAbstraction,
|
|
||||||
keyConnectorService: KeyConnectorServiceAbstraction,
|
|
||||||
stateService: StateServiceAbstraction
|
|
||||||
) =>
|
|
||||||
new VaultTimeoutService(
|
|
||||||
cipherService,
|
|
||||||
folderService,
|
|
||||||
collectionService,
|
|
||||||
cryptoService,
|
|
||||||
platformUtilsService,
|
|
||||||
messagingService,
|
|
||||||
searchService,
|
|
||||||
tokenService,
|
|
||||||
policyService,
|
|
||||||
keyConnectorService,
|
|
||||||
stateService,
|
|
||||||
null,
|
|
||||||
async (userId?: string) =>
|
|
||||||
messagingService.send("logout", { expired: false, userId: userId })
|
|
||||||
),
|
|
||||||
deps: [
|
|
||||||
CipherServiceAbstraction,
|
|
||||||
FolderServiceAbstraction,
|
|
||||||
CollectionServiceAbstraction,
|
|
||||||
CryptoServiceAbstraction,
|
|
||||||
PlatformUtilsServiceAbstraction,
|
|
||||||
MessagingServiceAbstraction,
|
|
||||||
SearchServiceAbstraction,
|
|
||||||
TokenServiceAbstraction,
|
|
||||||
PolicyServiceAbstraction,
|
|
||||||
KeyConnectorServiceAbstraction,
|
|
||||||
StateServiceAbstraction,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: StateServiceAbstraction,
|
provide: StateServiceAbstraction,
|
||||||
useFactory: (
|
useFactory: (
|
||||||
storageService: StorageServiceAbstraction,
|
storageService: StorageServiceAbstraction,
|
||||||
secureStorageService: StorageServiceAbstraction,
|
secureStorageService: StorageServiceAbstraction,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
stateMigrationService: StateMigrationServiceAbstraction
|
stateMigrationService: StateMigrationServiceAbstraction,
|
||||||
) =>
|
) =>
|
||||||
new StateService(
|
new StateService(
|
||||||
storageService,
|
storageService,
|
||||||
secureStorageService,
|
secureStorageService,
|
||||||
logService,
|
logService,
|
||||||
stateMigrationService,
|
stateMigrationService,
|
||||||
new StateFactory(GlobalState, Account)
|
new StateFactory(GlobalState, Account),
|
||||||
),
|
),
|
||||||
deps: [
|
deps: [
|
||||||
StorageServiceAbstraction,
|
StorageServiceAbstraction,
|
||||||
"SECURE_STORAGE",
|
SECURE_STORAGE,
|
||||||
LogService,
|
LogService,
|
||||||
StateMigrationServiceAbstraction,
|
StateMigrationServiceAbstraction,
|
||||||
],
|
],
|
||||||
},
|
}),
|
||||||
{
|
safeProvider({
|
||||||
provide: StateMigrationServiceAbstraction,
|
provide: StateMigrationServiceAbstraction,
|
||||||
useFactory: (
|
useFactory: (
|
||||||
storageService: StorageServiceAbstraction,
|
storageService: StorageServiceAbstraction,
|
||||||
secureStorageService: StorageServiceAbstraction
|
secureStorageService: StorageServiceAbstraction,
|
||||||
) =>
|
) =>
|
||||||
new StateMigrationService(
|
new StateMigrationService(
|
||||||
storageService,
|
storageService,
|
||||||
secureStorageService,
|
secureStorageService,
|
||||||
new StateFactory(GlobalState, Account)
|
new StateFactory(GlobalState, Account),
|
||||||
),
|
),
|
||||||
deps: [StorageServiceAbstraction, "SECURE_STORAGE"],
|
deps: [StorageServiceAbstraction, SECURE_STORAGE],
|
||||||
},
|
}),
|
||||||
{
|
] satisfies SafeProvider[],
|
||||||
provide: SearchServiceAbstraction,
|
|
||||||
useClass: SearchService,
|
|
||||||
deps: [CipherServiceAbstraction, LogService, I18nServiceAbstraction],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: NotificationsServiceAbstraction,
|
|
||||||
useFactory: (
|
|
||||||
syncService: SyncServiceAbstraction,
|
|
||||||
appIdService: AppIdServiceAbstraction,
|
|
||||||
apiService: ApiServiceAbstraction,
|
|
||||||
vaultTimeoutService: VaultTimeoutServiceAbstraction,
|
|
||||||
environmentService: EnvironmentServiceAbstraction,
|
|
||||||
messagingService: MessagingServiceAbstraction,
|
|
||||||
logService: LogService,
|
|
||||||
stateService: StateServiceAbstraction
|
|
||||||
) =>
|
|
||||||
new NotificationsService(
|
|
||||||
syncService,
|
|
||||||
appIdService,
|
|
||||||
apiService,
|
|
||||||
vaultTimeoutService,
|
|
||||||
environmentService,
|
|
||||||
async () => messagingService.send("logout", { expired: true }),
|
|
||||||
logService,
|
|
||||||
stateService
|
|
||||||
),
|
|
||||||
deps: [
|
|
||||||
SyncServiceAbstraction,
|
|
||||||
AppIdServiceAbstraction,
|
|
||||||
ApiServiceAbstraction,
|
|
||||||
VaultTimeoutServiceAbstraction,
|
|
||||||
EnvironmentServiceAbstraction,
|
|
||||||
MessagingServiceAbstraction,
|
|
||||||
LogService,
|
|
||||||
StateServiceAbstraction,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: EventServiceAbstraction,
|
|
||||||
useClass: EventService,
|
|
||||||
deps: [
|
|
||||||
ApiServiceAbstraction,
|
|
||||||
CipherServiceAbstraction,
|
|
||||||
StateServiceAbstraction,
|
|
||||||
LogService,
|
|
||||||
OrganizationServiceAbstraction,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: PolicyServiceAbstraction,
|
|
||||||
useClass: PolicyService,
|
|
||||||
deps: [StateServiceAbstraction, OrganizationServiceAbstraction, ApiServiceAbstraction],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: SendServiceAbstraction,
|
|
||||||
useClass: SendService,
|
|
||||||
deps: [
|
|
||||||
CryptoServiceAbstraction,
|
|
||||||
ApiServiceAbstraction,
|
|
||||||
FileUploadServiceAbstraction,
|
|
||||||
I18nServiceAbstraction,
|
|
||||||
CryptoFunctionServiceAbstraction,
|
|
||||||
StateServiceAbstraction,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: KeyConnectorServiceAbstraction,
|
|
||||||
useClass: KeyConnectorService,
|
|
||||||
deps: [
|
|
||||||
StateServiceAbstraction,
|
|
||||||
CryptoServiceAbstraction,
|
|
||||||
ApiServiceAbstraction,
|
|
||||||
TokenServiceAbstraction,
|
|
||||||
LogService,
|
|
||||||
OrganizationServiceAbstraction,
|
|
||||||
CryptoFunctionServiceAbstraction,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: UserVerificationServiceAbstraction,
|
|
||||||
useClass: UserVerificationService,
|
|
||||||
deps: [CryptoServiceAbstraction, I18nServiceAbstraction, ApiServiceAbstraction],
|
|
||||||
},
|
|
||||||
{ provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService },
|
|
||||||
{
|
|
||||||
provide: OrganizationServiceAbstraction,
|
|
||||||
useClass: OrganizationService,
|
|
||||||
deps: [StateServiceAbstraction],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: ProviderServiceAbstraction,
|
|
||||||
useClass: ProviderService,
|
|
||||||
deps: [StateServiceAbstraction],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: TwoFactorServiceAbstraction,
|
|
||||||
useClass: TwoFactorService,
|
|
||||||
deps: [I18nServiceAbstraction, PlatformUtilsServiceAbstraction],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
})
|
||||||
export class JslibServicesModule {}
|
export class JslibServicesModule {}
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
import { Injectable } from "@angular/core";
|
|
||||||
import { CanActivate, Router } from "@angular/router";
|
|
||||||
|
|
||||||
import { StateService } from "@/jslib/common/src/abstractions/state.service";
|
|
||||||
import { VaultTimeoutService } from "@/jslib/common/src/abstractions/vaultTimeout.service";
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class LockGuardService implements CanActivate {
|
|
||||||
protected homepage = "vault";
|
|
||||||
protected loginpage = "login";
|
|
||||||
constructor(
|
|
||||||
private vaultTimeoutService: VaultTimeoutService,
|
|
||||||
private router: Router,
|
|
||||||
private stateService: StateService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async canActivate() {
|
|
||||||
if (await this.vaultTimeoutService.isLocked()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const redirectUrl = (await this.stateService.getIsAuthenticated())
|
|
||||||
? [this.homepage]
|
|
||||||
: [this.loginpage];
|
|
||||||
|
|
||||||
this.router.navigate(redirectUrl);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -31,7 +31,7 @@ export class ModalService {
|
|||||||
constructor(
|
constructor(
|
||||||
private componentFactoryResolver: ComponentFactoryResolver,
|
private componentFactoryResolver: ComponentFactoryResolver,
|
||||||
private applicationRef: ApplicationRef,
|
private applicationRef: ApplicationRef,
|
||||||
private injector: Injector
|
private injector: Injector,
|
||||||
) {
|
) {
|
||||||
document.addEventListener("keyup", (event) => {
|
document.addEventListener("keyup", (event) => {
|
||||||
if (event.key === "Escape" && this.modalCount > 0) {
|
if (event.key === "Escape" && this.modalCount > 0) {
|
||||||
@@ -51,7 +51,7 @@ export class ModalService {
|
|||||||
async openViewRef<T>(
|
async openViewRef<T>(
|
||||||
componentType: Type<T>,
|
componentType: Type<T>,
|
||||||
viewContainerRef: ViewContainerRef,
|
viewContainerRef: ViewContainerRef,
|
||||||
setComponentParameters: (component: T) => void = null
|
setComponentParameters: (component: T) => void = null,
|
||||||
): Promise<[ModalRef, T]> {
|
): Promise<[ModalRef, T]> {
|
||||||
const [modalRef, modalComponentRef] = this.openInternal(componentType, null, false);
|
const [modalRef, modalComponentRef] = this.openInternal(componentType, null, false);
|
||||||
modalComponentRef.instance.setComponentParameters = setComponentParameters;
|
modalComponentRef.instance.setComponentParameters = setComponentParameters;
|
||||||
@@ -76,7 +76,7 @@ export class ModalService {
|
|||||||
|
|
||||||
registerComponentFactoryResolver<T>(
|
registerComponentFactoryResolver<T>(
|
||||||
componentType: Type<T>,
|
componentType: Type<T>,
|
||||||
componentFactoryResolver: ComponentFactoryResolver
|
componentFactoryResolver: ComponentFactoryResolver,
|
||||||
): void {
|
): void {
|
||||||
this.factoryResolvers.set(componentType, componentFactoryResolver);
|
this.factoryResolvers.set(componentType, componentFactoryResolver);
|
||||||
}
|
}
|
||||||
@@ -92,7 +92,7 @@ export class ModalService {
|
|||||||
protected openInternal(
|
protected openInternal(
|
||||||
componentType: Type<any>,
|
componentType: Type<any>,
|
||||||
config?: ModalConfig,
|
config?: ModalConfig,
|
||||||
attachToDom?: boolean
|
attachToDom?: boolean,
|
||||||
): [ModalRef, ComponentRef<DynamicModalComponent>] {
|
): [ModalRef, ComponentRef<DynamicModalComponent>] {
|
||||||
const [modalRef, componentRef] = this.createModalComponent(config);
|
const [modalRef, componentRef] = this.createModalComponent(config);
|
||||||
componentRef.instance.childComponentType = componentType;
|
componentRef.instance.childComponentType = componentType;
|
||||||
@@ -143,7 +143,7 @@ export class ModalService {
|
|||||||
dialogEl.style.zIndex = `${this.modalCount}050`;
|
dialogEl.style.zIndex = `${this.modalCount}050`;
|
||||||
|
|
||||||
const modals = Array.from(
|
const modals = Array.from(
|
||||||
el.querySelectorAll('.modal-backdrop, .modal *[data-dismiss="modal"]')
|
el.querySelectorAll('.modal-backdrop, .modal *[data-bs-dismiss="modal"]'),
|
||||||
);
|
);
|
||||||
for (const closeElement of modals) {
|
for (const closeElement of modals) {
|
||||||
closeElement.addEventListener("click", () => {
|
closeElement.addEventListener("click", () => {
|
||||||
@@ -163,7 +163,7 @@ export class ModalService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected createModalComponent(
|
protected createModalComponent(
|
||||||
config: ModalConfig
|
config: ModalConfig,
|
||||||
): [ModalRef, ComponentRef<DynamicModalComponent>] {
|
): [ModalRef, ComponentRef<DynamicModalComponent>] {
|
||||||
const modalRef = new ModalRef();
|
const modalRef = new ModalRef();
|
||||||
|
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
import { Injectable } from "@angular/core";
|
|
||||||
|
|
||||||
import { KeyConnectorService } from "@/jslib/common/src/abstractions/keyConnector.service";
|
|
||||||
import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "@/jslib/common/src/abstractions/passwordReprompt.service";
|
|
||||||
|
|
||||||
import { PasswordRepromptComponent } from "../components/password-reprompt.component";
|
|
||||||
|
|
||||||
import { ModalService } from "./modal.service";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to verify the user's Master Password for the "Master Password Re-prompt" feature only.
|
|
||||||
* See UserVerificationService for any other situation where you need to verify the user's identity.
|
|
||||||
*/
|
|
||||||
@Injectable()
|
|
||||||
export class PasswordRepromptService implements PasswordRepromptServiceAbstraction {
|
|
||||||
protected component = PasswordRepromptComponent;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private modalService: ModalService,
|
|
||||||
private keyConnectorService: KeyConnectorService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
protectedFields() {
|
|
||||||
return ["TOTP", "Password", "H_Field", "Card Number", "Security Code"];
|
|
||||||
}
|
|
||||||
|
|
||||||
async showPasswordPrompt() {
|
|
||||||
if (!(await this.enabled())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ref = this.modalService.open(this.component, { allowMultipleModals: true });
|
|
||||||
|
|
||||||
if (ref == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await ref.onClosedPromise();
|
|
||||||
return result === true;
|
|
||||||
}
|
|
||||||
|
|
||||||
async enabled() {
|
|
||||||
return !(await this.keyConnectorService.getUsesKeyConnector());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
import { Injectable } from "@angular/core";
|
|
||||||
import { CanActivate, Router } from "@angular/router";
|
|
||||||
|
|
||||||
import { StateService } from "@/jslib/common/src/abstractions/state.service";
|
|
||||||
import { VaultTimeoutService } from "@/jslib/common/src/abstractions/vaultTimeout.service";
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class UnauthGuardService implements CanActivate {
|
|
||||||
protected homepage = "vault";
|
|
||||||
constructor(
|
|
||||||
private vaultTimeoutService: VaultTimeoutService,
|
|
||||||
private router: Router,
|
|
||||||
private stateService: StateService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async canActivate() {
|
|
||||||
const isAuthed = await this.stateService.getIsAuthenticated();
|
|
||||||
if (isAuthed) {
|
|
||||||
const locked = await this.vaultTimeoutService.isLocked();
|
|
||||||
if (locked) {
|
|
||||||
this.router.navigate(["lock"]);
|
|
||||||
} else {
|
|
||||||
this.router.navigate([this.homepage]);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,7 @@ import { ErrorResponse } from "@/jslib/common/src/models/response/errorResponse"
|
|||||||
export class ValidationService {
|
export class ValidationService {
|
||||||
constructor(
|
constructor(
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private platformUtilsService: PlatformUtilsService
|
private platformUtilsService: PlatformUtilsService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
showError(data: any): string[] {
|
showError(data: any): string[] {
|
||||||
|
|||||||
@@ -1,83 +0,0 @@
|
|||||||
import { Substitute, Arg } from "@fluffy-spoon/substitute";
|
|
||||||
|
|
||||||
import { CryptoService } from "@/jslib/common/src/abstractions/crypto.service";
|
|
||||||
import { AttachmentData } from "@/jslib/common/src/models/data/attachmentData";
|
|
||||||
import { Attachment } from "@/jslib/common/src/models/domain/attachment";
|
|
||||||
import { SymmetricCryptoKey } from "@/jslib/common/src/models/domain/symmetricCryptoKey";
|
|
||||||
import { ContainerService } from "@/jslib/common/src/services/container.service";
|
|
||||||
|
|
||||||
import { makeStaticByteArray, mockEnc } from "../utils";
|
|
||||||
|
|
||||||
describe("Attachment", () => {
|
|
||||||
let data: AttachmentData;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
data = {
|
|
||||||
id: "id",
|
|
||||||
url: "url",
|
|
||||||
fileName: "fileName",
|
|
||||||
key: "key",
|
|
||||||
size: "1100",
|
|
||||||
sizeName: "1.1 KB",
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert from empty", () => {
|
|
||||||
const data = new AttachmentData();
|
|
||||||
const attachment = new Attachment(data);
|
|
||||||
|
|
||||||
expect(attachment).toEqual({
|
|
||||||
id: null,
|
|
||||||
url: null,
|
|
||||||
size: undefined,
|
|
||||||
sizeName: null,
|
|
||||||
key: null,
|
|
||||||
fileName: null,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert", () => {
|
|
||||||
const attachment = new Attachment(data);
|
|
||||||
|
|
||||||
expect(attachment).toEqual({
|
|
||||||
size: "1100",
|
|
||||||
id: "id",
|
|
||||||
url: "url",
|
|
||||||
sizeName: "1.1 KB",
|
|
||||||
fileName: { encryptedString: "fileName", encryptionType: 0 },
|
|
||||||
key: { encryptedString: "key", encryptionType: 0 },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("toAttachmentData", () => {
|
|
||||||
const attachment = new Attachment(data);
|
|
||||||
expect(attachment.toAttachmentData()).toEqual(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Decrypt", async () => {
|
|
||||||
const attachment = new Attachment();
|
|
||||||
attachment.id = "id";
|
|
||||||
attachment.url = "url";
|
|
||||||
attachment.size = "1100";
|
|
||||||
attachment.sizeName = "1.1 KB";
|
|
||||||
attachment.key = mockEnc("key");
|
|
||||||
attachment.fileName = mockEnc("fileName");
|
|
||||||
|
|
||||||
const cryptoService = Substitute.for<CryptoService>();
|
|
||||||
cryptoService.getOrgKey(null).resolves(null);
|
|
||||||
cryptoService.decryptToBytes(Arg.any(), Arg.any()).resolves(makeStaticByteArray(32));
|
|
||||||
|
|
||||||
(window as any).bitwardenContainerService = new ContainerService(cryptoService);
|
|
||||||
|
|
||||||
const view = await attachment.decrypt(null);
|
|
||||||
|
|
||||||
expect(view).toEqual({
|
|
||||||
id: "id",
|
|
||||||
url: "url",
|
|
||||||
size: "1100",
|
|
||||||
sizeName: "1.1 KB",
|
|
||||||
fileName: "fileName",
|
|
||||||
key: expect.any(SymmetricCryptoKey),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
import { CardData } from "@/jslib/common/src/models/data/cardData";
|
|
||||||
import { Card } from "@/jslib/common/src/models/domain/card";
|
|
||||||
|
|
||||||
import { mockEnc } from "../utils";
|
|
||||||
|
|
||||||
describe("Card", () => {
|
|
||||||
let data: CardData;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
data = {
|
|
||||||
cardholderName: "encHolder",
|
|
||||||
brand: "encBrand",
|
|
||||||
number: "encNumber",
|
|
||||||
expMonth: "encMonth",
|
|
||||||
expYear: "encYear",
|
|
||||||
code: "encCode",
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert from empty", () => {
|
|
||||||
const data = new CardData();
|
|
||||||
const card = new Card(data);
|
|
||||||
|
|
||||||
expect(card).toEqual({
|
|
||||||
cardholderName: null,
|
|
||||||
brand: null,
|
|
||||||
number: null,
|
|
||||||
expMonth: null,
|
|
||||||
expYear: null,
|
|
||||||
code: null,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert", () => {
|
|
||||||
const card = new Card(data);
|
|
||||||
|
|
||||||
expect(card).toEqual({
|
|
||||||
cardholderName: { encryptedString: "encHolder", encryptionType: 0 },
|
|
||||||
brand: { encryptedString: "encBrand", encryptionType: 0 },
|
|
||||||
number: { encryptedString: "encNumber", encryptionType: 0 },
|
|
||||||
expMonth: { encryptedString: "encMonth", encryptionType: 0 },
|
|
||||||
expYear: { encryptedString: "encYear", encryptionType: 0 },
|
|
||||||
code: { encryptedString: "encCode", encryptionType: 0 },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("toCardData", () => {
|
|
||||||
const card = new Card(data);
|
|
||||||
expect(card.toCardData()).toEqual(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Decrypt", async () => {
|
|
||||||
const card = new Card();
|
|
||||||
card.cardholderName = mockEnc("cardHolder");
|
|
||||||
card.brand = mockEnc("brand");
|
|
||||||
card.number = mockEnc("number");
|
|
||||||
card.expMonth = mockEnc("expMonth");
|
|
||||||
card.expYear = mockEnc("expYear");
|
|
||||||
card.code = mockEnc("code");
|
|
||||||
|
|
||||||
const view = await card.decrypt(null);
|
|
||||||
|
|
||||||
expect(view).toEqual({
|
|
||||||
_brand: "brand",
|
|
||||||
_number: "number",
|
|
||||||
_subTitle: null,
|
|
||||||
cardholderName: "cardHolder",
|
|
||||||
code: "code",
|
|
||||||
expMonth: "expMonth",
|
|
||||||
expYear: "expYear",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,599 +0,0 @@
|
|||||||
import { Substitute, Arg } from "@fluffy-spoon/substitute";
|
|
||||||
|
|
||||||
import { CipherRepromptType } from "@/jslib/common/src/enums/cipherRepromptType";
|
|
||||||
import { CipherType } from "@/jslib/common/src/enums/cipherType";
|
|
||||||
import { FieldType } from "@/jslib/common/src/enums/fieldType";
|
|
||||||
import { SecureNoteType } from "@/jslib/common/src/enums/secureNoteType";
|
|
||||||
import { UriMatchType } from "@/jslib/common/src/enums/uriMatchType";
|
|
||||||
import { CipherData } from "@/jslib/common/src/models/data/cipherData";
|
|
||||||
import { Card } from "@/jslib/common/src/models/domain/card";
|
|
||||||
import { Cipher } from "@/jslib/common/src/models/domain/cipher";
|
|
||||||
import { Identity } from "@/jslib/common/src/models/domain/identity";
|
|
||||||
import { Login } from "@/jslib/common/src/models/domain/login";
|
|
||||||
import { SecureNote } from "@/jslib/common/src/models/domain/secureNote";
|
|
||||||
import { CardView } from "@/jslib/common/src/models/view/cardView";
|
|
||||||
import { IdentityView } from "@/jslib/common/src/models/view/identityView";
|
|
||||||
import { LoginView } from "@/jslib/common/src/models/view/loginView";
|
|
||||||
|
|
||||||
import { mockEnc } from "../utils";
|
|
||||||
|
|
||||||
describe("Cipher DTO", () => {
|
|
||||||
it("Convert from empty CipherData", () => {
|
|
||||||
const data = new CipherData();
|
|
||||||
const cipher = new Cipher(data);
|
|
||||||
|
|
||||||
expect(cipher).toEqual({
|
|
||||||
id: null,
|
|
||||||
userId: null,
|
|
||||||
organizationId: null,
|
|
||||||
folderId: null,
|
|
||||||
name: null,
|
|
||||||
notes: null,
|
|
||||||
type: undefined,
|
|
||||||
favorite: undefined,
|
|
||||||
organizationUseTotp: undefined,
|
|
||||||
edit: undefined,
|
|
||||||
viewPassword: true,
|
|
||||||
revisionDate: null,
|
|
||||||
collectionIds: undefined,
|
|
||||||
localData: null,
|
|
||||||
deletedDate: null,
|
|
||||||
reprompt: undefined,
|
|
||||||
attachments: null,
|
|
||||||
fields: null,
|
|
||||||
passwordHistory: null,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("LoginCipher", () => {
|
|
||||||
let cipherData: CipherData;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
cipherData = {
|
|
||||||
id: "id",
|
|
||||||
organizationId: "orgId",
|
|
||||||
folderId: "folderId",
|
|
||||||
userId: "userId",
|
|
||||||
edit: true,
|
|
||||||
viewPassword: true,
|
|
||||||
organizationUseTotp: true,
|
|
||||||
favorite: false,
|
|
||||||
revisionDate: "2022-01-31T12:00:00.000Z",
|
|
||||||
type: CipherType.Login,
|
|
||||||
name: "EncryptedString",
|
|
||||||
notes: "EncryptedString",
|
|
||||||
deletedDate: null,
|
|
||||||
reprompt: CipherRepromptType.None,
|
|
||||||
login: {
|
|
||||||
uris: [{ uri: "EncryptedString", match: UriMatchType.Domain }],
|
|
||||||
username: "EncryptedString",
|
|
||||||
password: "EncryptedString",
|
|
||||||
passwordRevisionDate: "2022-01-31T12:00:00.000Z",
|
|
||||||
totp: "EncryptedString",
|
|
||||||
autofillOnPageLoad: false,
|
|
||||||
},
|
|
||||||
passwordHistory: [
|
|
||||||
{ password: "EncryptedString", lastUsedDate: "2022-01-31T12:00:00.000Z" },
|
|
||||||
],
|
|
||||||
attachments: [
|
|
||||||
{
|
|
||||||
id: "a1",
|
|
||||||
url: "url",
|
|
||||||
size: "1100",
|
|
||||||
sizeName: "1.1 KB",
|
|
||||||
fileName: "file",
|
|
||||||
key: "EncKey",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "a2",
|
|
||||||
url: "url",
|
|
||||||
size: "1100",
|
|
||||||
sizeName: "1.1 KB",
|
|
||||||
fileName: "file",
|
|
||||||
key: "EncKey",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: "EncryptedString",
|
|
||||||
value: "EncryptedString",
|
|
||||||
type: FieldType.Text,
|
|
||||||
linkedId: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "EncryptedString",
|
|
||||||
value: "EncryptedString",
|
|
||||||
type: FieldType.Hidden,
|
|
||||||
linkedId: null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert", () => {
|
|
||||||
const cipher = new Cipher(cipherData);
|
|
||||||
|
|
||||||
expect(cipher).toEqual({
|
|
||||||
id: "id",
|
|
||||||
userId: "userId",
|
|
||||||
organizationId: "orgId",
|
|
||||||
folderId: "folderId",
|
|
||||||
name: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
notes: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
type: 1,
|
|
||||||
favorite: false,
|
|
||||||
organizationUseTotp: true,
|
|
||||||
edit: true,
|
|
||||||
viewPassword: true,
|
|
||||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
collectionIds: undefined,
|
|
||||||
localData: null,
|
|
||||||
deletedDate: null,
|
|
||||||
reprompt: 0,
|
|
||||||
login: {
|
|
||||||
passwordRevisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
autofillOnPageLoad: false,
|
|
||||||
username: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
password: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
totp: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
uris: [{ match: 0, uri: { encryptedString: "EncryptedString", encryptionType: 0 } }],
|
|
||||||
},
|
|
||||||
attachments: [
|
|
||||||
{
|
|
||||||
fileName: { encryptedString: "file", encryptionType: 0 },
|
|
||||||
id: "a1",
|
|
||||||
key: { encryptedString: "EncKey", encryptionType: 0 },
|
|
||||||
size: "1100",
|
|
||||||
sizeName: "1.1 KB",
|
|
||||||
url: "url",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fileName: { encryptedString: "file", encryptionType: 0 },
|
|
||||||
id: "a2",
|
|
||||||
key: { encryptedString: "EncKey", encryptionType: 0 },
|
|
||||||
size: "1100",
|
|
||||||
sizeName: "1.1 KB",
|
|
||||||
url: "url",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
linkedId: null,
|
|
||||||
name: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
type: 0,
|
|
||||||
value: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
linkedId: null,
|
|
||||||
name: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
type: 1,
|
|
||||||
value: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
},
|
|
||||||
],
|
|
||||||
passwordHistory: [
|
|
||||||
{
|
|
||||||
lastUsedDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
password: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("toCipherData", () => {
|
|
||||||
const cipher = new Cipher(cipherData);
|
|
||||||
expect(cipher.toCipherData("userId")).toEqual(cipherData);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Decrypt", async () => {
|
|
||||||
const cipher = new Cipher();
|
|
||||||
cipher.id = "id";
|
|
||||||
cipher.organizationId = "orgId";
|
|
||||||
cipher.folderId = "folderId";
|
|
||||||
cipher.edit = true;
|
|
||||||
cipher.viewPassword = true;
|
|
||||||
cipher.organizationUseTotp = true;
|
|
||||||
cipher.favorite = false;
|
|
||||||
cipher.revisionDate = new Date("2022-01-31T12:00:00.000Z");
|
|
||||||
cipher.type = CipherType.Login;
|
|
||||||
cipher.name = mockEnc("EncryptedString");
|
|
||||||
cipher.notes = mockEnc("EncryptedString");
|
|
||||||
cipher.deletedDate = null;
|
|
||||||
cipher.reprompt = CipherRepromptType.None;
|
|
||||||
|
|
||||||
const loginView = new LoginView();
|
|
||||||
loginView.username = "username";
|
|
||||||
loginView.password = "password";
|
|
||||||
|
|
||||||
const login = Substitute.for<Login>();
|
|
||||||
login.decrypt(Arg.any(), Arg.any()).resolves(loginView);
|
|
||||||
cipher.login = login;
|
|
||||||
|
|
||||||
const cipherView = await cipher.decrypt();
|
|
||||||
|
|
||||||
expect(cipherView).toMatchObject({
|
|
||||||
id: "id",
|
|
||||||
organizationId: "orgId",
|
|
||||||
folderId: "folderId",
|
|
||||||
name: "EncryptedString",
|
|
||||||
notes: "EncryptedString",
|
|
||||||
type: 1,
|
|
||||||
favorite: false,
|
|
||||||
organizationUseTotp: true,
|
|
||||||
edit: true,
|
|
||||||
viewPassword: true,
|
|
||||||
login: loginView,
|
|
||||||
attachments: null,
|
|
||||||
fields: null,
|
|
||||||
passwordHistory: null,
|
|
||||||
collectionIds: undefined,
|
|
||||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
deletedDate: null,
|
|
||||||
reprompt: 0,
|
|
||||||
localData: undefined,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("SecureNoteCipher", () => {
|
|
||||||
let cipherData: CipherData;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
cipherData = {
|
|
||||||
id: "id",
|
|
||||||
organizationId: "orgId",
|
|
||||||
folderId: "folderId",
|
|
||||||
userId: "userId",
|
|
||||||
edit: true,
|
|
||||||
viewPassword: true,
|
|
||||||
organizationUseTotp: true,
|
|
||||||
favorite: false,
|
|
||||||
revisionDate: "2022-01-31T12:00:00.000Z",
|
|
||||||
type: CipherType.SecureNote,
|
|
||||||
name: "EncryptedString",
|
|
||||||
notes: "EncryptedString",
|
|
||||||
deletedDate: null,
|
|
||||||
reprompt: CipherRepromptType.None,
|
|
||||||
secureNote: {
|
|
||||||
type: SecureNoteType.Generic,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert", () => {
|
|
||||||
const cipher = new Cipher(cipherData);
|
|
||||||
|
|
||||||
expect(cipher).toEqual({
|
|
||||||
id: "id",
|
|
||||||
userId: "userId",
|
|
||||||
organizationId: "orgId",
|
|
||||||
folderId: "folderId",
|
|
||||||
name: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
notes: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
type: 2,
|
|
||||||
favorite: false,
|
|
||||||
organizationUseTotp: true,
|
|
||||||
edit: true,
|
|
||||||
viewPassword: true,
|
|
||||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
collectionIds: undefined,
|
|
||||||
localData: null,
|
|
||||||
deletedDate: null,
|
|
||||||
reprompt: 0,
|
|
||||||
secureNote: { type: SecureNoteType.Generic },
|
|
||||||
attachments: null,
|
|
||||||
fields: null,
|
|
||||||
passwordHistory: null,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("toCipherData", () => {
|
|
||||||
const cipher = new Cipher(cipherData);
|
|
||||||
expect(cipher.toCipherData("userId")).toEqual(cipherData);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Decrypt", async () => {
|
|
||||||
const cipher = new Cipher();
|
|
||||||
cipher.id = "id";
|
|
||||||
cipher.organizationId = "orgId";
|
|
||||||
cipher.folderId = "folderId";
|
|
||||||
cipher.edit = true;
|
|
||||||
cipher.viewPassword = true;
|
|
||||||
cipher.organizationUseTotp = true;
|
|
||||||
cipher.favorite = false;
|
|
||||||
cipher.revisionDate = new Date("2022-01-31T12:00:00.000Z");
|
|
||||||
cipher.type = CipherType.SecureNote;
|
|
||||||
cipher.name = mockEnc("EncryptedString");
|
|
||||||
cipher.notes = mockEnc("EncryptedString");
|
|
||||||
cipher.deletedDate = null;
|
|
||||||
cipher.reprompt = CipherRepromptType.None;
|
|
||||||
cipher.secureNote = new SecureNote();
|
|
||||||
cipher.secureNote.type = SecureNoteType.Generic;
|
|
||||||
|
|
||||||
const cipherView = await cipher.decrypt();
|
|
||||||
|
|
||||||
expect(cipherView).toMatchObject({
|
|
||||||
id: "id",
|
|
||||||
organizationId: "orgId",
|
|
||||||
folderId: "folderId",
|
|
||||||
name: "EncryptedString",
|
|
||||||
notes: "EncryptedString",
|
|
||||||
type: 2,
|
|
||||||
favorite: false,
|
|
||||||
organizationUseTotp: true,
|
|
||||||
edit: true,
|
|
||||||
viewPassword: true,
|
|
||||||
secureNote: { type: 0 },
|
|
||||||
attachments: null,
|
|
||||||
fields: null,
|
|
||||||
passwordHistory: null,
|
|
||||||
collectionIds: undefined,
|
|
||||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
deletedDate: null,
|
|
||||||
reprompt: 0,
|
|
||||||
localData: undefined,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("CardCipher", () => {
|
|
||||||
let cipherData: CipherData;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
cipherData = {
|
|
||||||
id: "id",
|
|
||||||
organizationId: "orgId",
|
|
||||||
folderId: "folderId",
|
|
||||||
userId: "userId",
|
|
||||||
edit: true,
|
|
||||||
viewPassword: true,
|
|
||||||
organizationUseTotp: true,
|
|
||||||
favorite: false,
|
|
||||||
revisionDate: "2022-01-31T12:00:00.000Z",
|
|
||||||
type: CipherType.Card,
|
|
||||||
name: "EncryptedString",
|
|
||||||
notes: "EncryptedString",
|
|
||||||
deletedDate: null,
|
|
||||||
reprompt: CipherRepromptType.None,
|
|
||||||
card: {
|
|
||||||
cardholderName: "EncryptedString",
|
|
||||||
brand: "EncryptedString",
|
|
||||||
number: "EncryptedString",
|
|
||||||
expMonth: "EncryptedString",
|
|
||||||
expYear: "EncryptedString",
|
|
||||||
code: "EncryptedString",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert", () => {
|
|
||||||
const cipher = new Cipher(cipherData);
|
|
||||||
|
|
||||||
expect(cipher).toEqual({
|
|
||||||
id: "id",
|
|
||||||
userId: "userId",
|
|
||||||
organizationId: "orgId",
|
|
||||||
folderId: "folderId",
|
|
||||||
name: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
notes: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
type: 3,
|
|
||||||
favorite: false,
|
|
||||||
organizationUseTotp: true,
|
|
||||||
edit: true,
|
|
||||||
viewPassword: true,
|
|
||||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
collectionIds: undefined,
|
|
||||||
localData: null,
|
|
||||||
deletedDate: null,
|
|
||||||
reprompt: 0,
|
|
||||||
card: {
|
|
||||||
cardholderName: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
brand: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
number: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
expMonth: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
expYear: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
code: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
},
|
|
||||||
attachments: null,
|
|
||||||
fields: null,
|
|
||||||
passwordHistory: null,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("toCipherData", () => {
|
|
||||||
const cipher = new Cipher(cipherData);
|
|
||||||
expect(cipher.toCipherData("userId")).toEqual(cipherData);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Decrypt", async () => {
|
|
||||||
const cipher = new Cipher();
|
|
||||||
cipher.id = "id";
|
|
||||||
cipher.organizationId = "orgId";
|
|
||||||
cipher.folderId = "folderId";
|
|
||||||
cipher.edit = true;
|
|
||||||
cipher.viewPassword = true;
|
|
||||||
cipher.organizationUseTotp = true;
|
|
||||||
cipher.favorite = false;
|
|
||||||
cipher.revisionDate = new Date("2022-01-31T12:00:00.000Z");
|
|
||||||
cipher.type = CipherType.Card;
|
|
||||||
cipher.name = mockEnc("EncryptedString");
|
|
||||||
cipher.notes = mockEnc("EncryptedString");
|
|
||||||
cipher.deletedDate = null;
|
|
||||||
cipher.reprompt = CipherRepromptType.None;
|
|
||||||
|
|
||||||
const cardView = new CardView();
|
|
||||||
cardView.cardholderName = "cardholderName";
|
|
||||||
cardView.number = "4111111111111111";
|
|
||||||
|
|
||||||
const card = Substitute.for<Card>();
|
|
||||||
card.decrypt(Arg.any(), Arg.any()).resolves(cardView);
|
|
||||||
cipher.card = card;
|
|
||||||
|
|
||||||
const cipherView = await cipher.decrypt();
|
|
||||||
|
|
||||||
expect(cipherView).toMatchObject({
|
|
||||||
id: "id",
|
|
||||||
organizationId: "orgId",
|
|
||||||
folderId: "folderId",
|
|
||||||
name: "EncryptedString",
|
|
||||||
notes: "EncryptedString",
|
|
||||||
type: 3,
|
|
||||||
favorite: false,
|
|
||||||
organizationUseTotp: true,
|
|
||||||
edit: true,
|
|
||||||
viewPassword: true,
|
|
||||||
card: cardView,
|
|
||||||
attachments: null,
|
|
||||||
fields: null,
|
|
||||||
passwordHistory: null,
|
|
||||||
collectionIds: undefined,
|
|
||||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
deletedDate: null,
|
|
||||||
reprompt: 0,
|
|
||||||
localData: undefined,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("IdentityCipher", () => {
|
|
||||||
let cipherData: CipherData;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
cipherData = {
|
|
||||||
id: "id",
|
|
||||||
organizationId: "orgId",
|
|
||||||
folderId: "folderId",
|
|
||||||
userId: "userId",
|
|
||||||
edit: true,
|
|
||||||
viewPassword: true,
|
|
||||||
organizationUseTotp: true,
|
|
||||||
favorite: false,
|
|
||||||
revisionDate: "2022-01-31T12:00:00.000Z",
|
|
||||||
type: CipherType.Identity,
|
|
||||||
name: "EncryptedString",
|
|
||||||
notes: "EncryptedString",
|
|
||||||
deletedDate: null,
|
|
||||||
reprompt: CipherRepromptType.None,
|
|
||||||
identity: {
|
|
||||||
title: "EncryptedString",
|
|
||||||
firstName: "EncryptedString",
|
|
||||||
middleName: "EncryptedString",
|
|
||||||
lastName: "EncryptedString",
|
|
||||||
address1: "EncryptedString",
|
|
||||||
address2: "EncryptedString",
|
|
||||||
address3: "EncryptedString",
|
|
||||||
city: "EncryptedString",
|
|
||||||
state: "EncryptedString",
|
|
||||||
postalCode: "EncryptedString",
|
|
||||||
country: "EncryptedString",
|
|
||||||
company: "EncryptedString",
|
|
||||||
email: "EncryptedString",
|
|
||||||
phone: "EncryptedString",
|
|
||||||
ssn: "EncryptedString",
|
|
||||||
username: "EncryptedString",
|
|
||||||
passportNumber: "EncryptedString",
|
|
||||||
licenseNumber: "EncryptedString",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert", () => {
|
|
||||||
const cipher = new Cipher(cipherData);
|
|
||||||
|
|
||||||
expect(cipher).toEqual({
|
|
||||||
id: "id",
|
|
||||||
userId: "userId",
|
|
||||||
organizationId: "orgId",
|
|
||||||
folderId: "folderId",
|
|
||||||
name: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
notes: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
type: 4,
|
|
||||||
favorite: false,
|
|
||||||
organizationUseTotp: true,
|
|
||||||
edit: true,
|
|
||||||
viewPassword: true,
|
|
||||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
collectionIds: undefined,
|
|
||||||
localData: null,
|
|
||||||
deletedDate: null,
|
|
||||||
reprompt: 0,
|
|
||||||
identity: {
|
|
||||||
title: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
firstName: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
middleName: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
lastName: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
address1: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
address2: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
address3: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
city: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
state: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
postalCode: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
country: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
company: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
email: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
phone: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
ssn: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
username: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
passportNumber: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
licenseNumber: { encryptedString: "EncryptedString", encryptionType: 0 },
|
|
||||||
},
|
|
||||||
attachments: null,
|
|
||||||
fields: null,
|
|
||||||
passwordHistory: null,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("toCipherData", () => {
|
|
||||||
const cipher = new Cipher(cipherData);
|
|
||||||
expect(cipher.toCipherData("userId")).toEqual(cipherData);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Decrypt", async () => {
|
|
||||||
const cipher = new Cipher();
|
|
||||||
cipher.id = "id";
|
|
||||||
cipher.organizationId = "orgId";
|
|
||||||
cipher.folderId = "folderId";
|
|
||||||
cipher.edit = true;
|
|
||||||
cipher.viewPassword = true;
|
|
||||||
cipher.organizationUseTotp = true;
|
|
||||||
cipher.favorite = false;
|
|
||||||
cipher.revisionDate = new Date("2022-01-31T12:00:00.000Z");
|
|
||||||
cipher.type = CipherType.Identity;
|
|
||||||
cipher.name = mockEnc("EncryptedString");
|
|
||||||
cipher.notes = mockEnc("EncryptedString");
|
|
||||||
cipher.deletedDate = null;
|
|
||||||
cipher.reprompt = CipherRepromptType.None;
|
|
||||||
|
|
||||||
const identityView = new IdentityView();
|
|
||||||
identityView.firstName = "firstName";
|
|
||||||
identityView.lastName = "lastName";
|
|
||||||
|
|
||||||
const identity = Substitute.for<Identity>();
|
|
||||||
identity.decrypt(Arg.any(), Arg.any()).resolves(identityView);
|
|
||||||
cipher.identity = identity;
|
|
||||||
|
|
||||||
const cipherView = await cipher.decrypt();
|
|
||||||
|
|
||||||
expect(cipherView).toMatchObject({
|
|
||||||
id: "id",
|
|
||||||
organizationId: "orgId",
|
|
||||||
folderId: "folderId",
|
|
||||||
name: "EncryptedString",
|
|
||||||
notes: "EncryptedString",
|
|
||||||
type: 4,
|
|
||||||
favorite: false,
|
|
||||||
organizationUseTotp: true,
|
|
||||||
edit: true,
|
|
||||||
viewPassword: true,
|
|
||||||
identity: identityView,
|
|
||||||
attachments: null,
|
|
||||||
fields: null,
|
|
||||||
passwordHistory: null,
|
|
||||||
collectionIds: undefined,
|
|
||||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
deletedDate: null,
|
|
||||||
reprompt: 0,
|
|
||||||
localData: undefined,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
import { CollectionData } from "@/jslib/common/src/models/data/collectionData";
|
|
||||||
import { Collection } from "@/jslib/common/src/models/domain/collection";
|
|
||||||
|
|
||||||
import { mockEnc } from "../utils";
|
|
||||||
|
|
||||||
describe("Collection", () => {
|
|
||||||
let data: CollectionData;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
data = {
|
|
||||||
id: "id",
|
|
||||||
organizationId: "orgId",
|
|
||||||
name: "encName",
|
|
||||||
externalId: "extId",
|
|
||||||
readOnly: true,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert from empty", () => {
|
|
||||||
const data = new CollectionData({} as any);
|
|
||||||
const card = new Collection(data);
|
|
||||||
|
|
||||||
expect(card).toEqual({
|
|
||||||
externalId: null,
|
|
||||||
hidePasswords: null,
|
|
||||||
id: null,
|
|
||||||
name: null,
|
|
||||||
organizationId: null,
|
|
||||||
readOnly: null,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert", () => {
|
|
||||||
const collection = new Collection(data);
|
|
||||||
|
|
||||||
expect(collection).toEqual({
|
|
||||||
id: "id",
|
|
||||||
organizationId: "orgId",
|
|
||||||
name: { encryptedString: "encName", encryptionType: 0 },
|
|
||||||
externalId: "extId",
|
|
||||||
readOnly: true,
|
|
||||||
hidePasswords: null,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Decrypt", async () => {
|
|
||||||
const collection = new Collection();
|
|
||||||
collection.id = "id";
|
|
||||||
collection.organizationId = "orgId";
|
|
||||||
collection.name = mockEnc("encName");
|
|
||||||
collection.externalId = "extId";
|
|
||||||
collection.readOnly = false;
|
|
||||||
collection.hidePasswords = false;
|
|
||||||
|
|
||||||
const view = await collection.decrypt();
|
|
||||||
|
|
||||||
expect(view).toEqual({
|
|
||||||
externalId: "extId",
|
|
||||||
hidePasswords: false,
|
|
||||||
id: "id",
|
|
||||||
name: "encName",
|
|
||||||
organizationId: "orgId",
|
|
||||||
readOnly: false,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
import { FieldType } from "@/jslib/common/src/enums/fieldType";
|
|
||||||
import { FieldData } from "@/jslib/common/src/models/data/fieldData";
|
|
||||||
import { Field } from "@/jslib/common/src/models/domain/field";
|
|
||||||
|
|
||||||
import { mockEnc } from "../utils";
|
|
||||||
|
|
||||||
describe("Field", () => {
|
|
||||||
let data: FieldData;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
data = {
|
|
||||||
type: FieldType.Text,
|
|
||||||
name: "encName",
|
|
||||||
value: "encValue",
|
|
||||||
linkedId: null,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert from empty", () => {
|
|
||||||
const data = new FieldData();
|
|
||||||
const field = new Field(data);
|
|
||||||
|
|
||||||
expect(field).toEqual({
|
|
||||||
type: undefined,
|
|
||||||
name: null,
|
|
||||||
value: null,
|
|
||||||
linkedId: undefined,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert", () => {
|
|
||||||
const field = new Field(data);
|
|
||||||
|
|
||||||
expect(field).toEqual({
|
|
||||||
type: FieldType.Text,
|
|
||||||
name: { encryptedString: "encName", encryptionType: 0 },
|
|
||||||
value: { encryptedString: "encValue", encryptionType: 0 },
|
|
||||||
linkedId: null,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("toFieldData", () => {
|
|
||||||
const field = new Field(data);
|
|
||||||
expect(field.toFieldData()).toEqual(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Decrypt", async () => {
|
|
||||||
const field = new Field();
|
|
||||||
field.type = FieldType.Text;
|
|
||||||
field.name = mockEnc("encName");
|
|
||||||
field.value = mockEnc("encValue");
|
|
||||||
|
|
||||||
const view = await field.decrypt(null);
|
|
||||||
|
|
||||||
expect(view).toEqual({
|
|
||||||
type: 0,
|
|
||||||
name: "encName",
|
|
||||||
value: "encValue",
|
|
||||||
newField: false,
|
|
||||||
showCount: false,
|
|
||||||
showValue: false,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
import { FolderData } from "@/jslib/common/src/models/data/folderData";
|
|
||||||
import { Folder } from "@/jslib/common/src/models/domain/folder";
|
|
||||||
|
|
||||||
import { mockEnc } from "../utils";
|
|
||||||
|
|
||||||
describe("Folder", () => {
|
|
||||||
let data: FolderData;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
data = {
|
|
||||||
id: "id",
|
|
||||||
userId: "userId",
|
|
||||||
name: "encName",
|
|
||||||
revisionDate: "2022-01-31T12:00:00.000Z",
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert", () => {
|
|
||||||
const field = new Folder(data);
|
|
||||||
|
|
||||||
expect(field).toEqual({
|
|
||||||
id: "id",
|
|
||||||
name: { encryptedString: "encName", encryptionType: 0 },
|
|
||||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Decrypt", async () => {
|
|
||||||
const folder = new Folder();
|
|
||||||
folder.id = "id";
|
|
||||||
folder.name = mockEnc("encName");
|
|
||||||
folder.revisionDate = new Date("2022-01-31T12:00:00.000Z");
|
|
||||||
|
|
||||||
const view = await folder.decrypt();
|
|
||||||
|
|
||||||
expect(view).toEqual({
|
|
||||||
id: "id",
|
|
||||||
name: "encName",
|
|
||||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
import { IdentityData } from "@/jslib/common/src/models/data/identityData";
|
|
||||||
import { Identity } from "@/jslib/common/src/models/domain/identity";
|
|
||||||
|
|
||||||
import { mockEnc } from "../utils";
|
|
||||||
|
|
||||||
describe("Identity", () => {
|
|
||||||
let data: IdentityData;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
data = {
|
|
||||||
title: "enctitle",
|
|
||||||
firstName: "encfirstName",
|
|
||||||
middleName: "encmiddleName",
|
|
||||||
lastName: "enclastName",
|
|
||||||
address1: "encaddress1",
|
|
||||||
address2: "encaddress2",
|
|
||||||
address3: "encaddress3",
|
|
||||||
city: "enccity",
|
|
||||||
state: "encstate",
|
|
||||||
postalCode: "encpostalCode",
|
|
||||||
country: "enccountry",
|
|
||||||
company: "enccompany",
|
|
||||||
email: "encemail",
|
|
||||||
phone: "encphone",
|
|
||||||
ssn: "encssn",
|
|
||||||
username: "encusername",
|
|
||||||
passportNumber: "encpassportNumber",
|
|
||||||
licenseNumber: "enclicenseNumber",
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert from empty", () => {
|
|
||||||
const data = new IdentityData();
|
|
||||||
const identity = new Identity(data);
|
|
||||||
|
|
||||||
expect(identity).toEqual({
|
|
||||||
address1: null,
|
|
||||||
address2: null,
|
|
||||||
address3: null,
|
|
||||||
city: null,
|
|
||||||
company: null,
|
|
||||||
country: null,
|
|
||||||
email: null,
|
|
||||||
firstName: null,
|
|
||||||
lastName: null,
|
|
||||||
licenseNumber: null,
|
|
||||||
middleName: null,
|
|
||||||
passportNumber: null,
|
|
||||||
phone: null,
|
|
||||||
postalCode: null,
|
|
||||||
ssn: null,
|
|
||||||
state: null,
|
|
||||||
title: null,
|
|
||||||
username: null,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert", () => {
|
|
||||||
const identity = new Identity(data);
|
|
||||||
|
|
||||||
expect(identity).toEqual({
|
|
||||||
title: { encryptedString: "enctitle", encryptionType: 0 },
|
|
||||||
firstName: { encryptedString: "encfirstName", encryptionType: 0 },
|
|
||||||
middleName: { encryptedString: "encmiddleName", encryptionType: 0 },
|
|
||||||
lastName: { encryptedString: "enclastName", encryptionType: 0 },
|
|
||||||
address1: { encryptedString: "encaddress1", encryptionType: 0 },
|
|
||||||
address2: { encryptedString: "encaddress2", encryptionType: 0 },
|
|
||||||
address3: { encryptedString: "encaddress3", encryptionType: 0 },
|
|
||||||
city: { encryptedString: "enccity", encryptionType: 0 },
|
|
||||||
state: { encryptedString: "encstate", encryptionType: 0 },
|
|
||||||
postalCode: { encryptedString: "encpostalCode", encryptionType: 0 },
|
|
||||||
country: { encryptedString: "enccountry", encryptionType: 0 },
|
|
||||||
company: { encryptedString: "enccompany", encryptionType: 0 },
|
|
||||||
email: { encryptedString: "encemail", encryptionType: 0 },
|
|
||||||
phone: { encryptedString: "encphone", encryptionType: 0 },
|
|
||||||
ssn: { encryptedString: "encssn", encryptionType: 0 },
|
|
||||||
username: { encryptedString: "encusername", encryptionType: 0 },
|
|
||||||
passportNumber: { encryptedString: "encpassportNumber", encryptionType: 0 },
|
|
||||||
licenseNumber: { encryptedString: "enclicenseNumber", encryptionType: 0 },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("toIdentityData", () => {
|
|
||||||
const identity = new Identity(data);
|
|
||||||
expect(identity.toIdentityData()).toEqual(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Decrypt", async () => {
|
|
||||||
const identity = new Identity();
|
|
||||||
|
|
||||||
identity.title = mockEnc("mockTitle");
|
|
||||||
identity.firstName = mockEnc("mockFirstName");
|
|
||||||
identity.middleName = mockEnc("mockMiddleName");
|
|
||||||
identity.lastName = mockEnc("mockLastName");
|
|
||||||
identity.address1 = mockEnc("mockAddress1");
|
|
||||||
identity.address2 = mockEnc("mockAddress2");
|
|
||||||
identity.address3 = mockEnc("mockAddress3");
|
|
||||||
identity.city = mockEnc("mockCity");
|
|
||||||
identity.state = mockEnc("mockState");
|
|
||||||
identity.postalCode = mockEnc("mockPostalCode");
|
|
||||||
identity.country = mockEnc("mockCountry");
|
|
||||||
identity.company = mockEnc("mockCompany");
|
|
||||||
identity.email = mockEnc("mockEmail");
|
|
||||||
identity.phone = mockEnc("mockPhone");
|
|
||||||
identity.ssn = mockEnc("mockSsn");
|
|
||||||
identity.username = mockEnc("mockUsername");
|
|
||||||
identity.passportNumber = mockEnc("mockPassportNumber");
|
|
||||||
identity.licenseNumber = mockEnc("mockLicenseNumber");
|
|
||||||
|
|
||||||
const view = await identity.decrypt(null);
|
|
||||||
|
|
||||||
expect(view).toEqual({
|
|
||||||
_firstName: "mockFirstName",
|
|
||||||
_lastName: "mockLastName",
|
|
||||||
_subTitle: null,
|
|
||||||
address1: "mockAddress1",
|
|
||||||
address2: "mockAddress2",
|
|
||||||
address3: "mockAddress3",
|
|
||||||
city: "mockCity",
|
|
||||||
company: "mockCompany",
|
|
||||||
country: "mockCountry",
|
|
||||||
email: "mockEmail",
|
|
||||||
licenseNumber: "mockLicenseNumber",
|
|
||||||
middleName: "mockMiddleName",
|
|
||||||
passportNumber: "mockPassportNumber",
|
|
||||||
phone: "mockPhone",
|
|
||||||
postalCode: "mockPostalCode",
|
|
||||||
ssn: "mockSsn",
|
|
||||||
state: "mockState",
|
|
||||||
title: "mockTitle",
|
|
||||||
username: "mockUsername",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
import { Substitute, Arg } from "@fluffy-spoon/substitute";
|
|
||||||
|
|
||||||
import { UriMatchType } from "@/jslib/common/src/enums/uriMatchType";
|
|
||||||
import { LoginData } from "@/jslib/common/src/models/data/loginData";
|
|
||||||
import { Login } from "@/jslib/common/src/models/domain/login";
|
|
||||||
import { LoginUri } from "@/jslib/common/src/models/domain/loginUri";
|
|
||||||
import { LoginUriView } from "@/jslib/common/src/models/view/loginUriView";
|
|
||||||
|
|
||||||
import { mockEnc } from "../utils";
|
|
||||||
|
|
||||||
describe("Login DTO", () => {
|
|
||||||
it("Convert from empty LoginData", () => {
|
|
||||||
const data = new LoginData();
|
|
||||||
const login = new Login(data);
|
|
||||||
|
|
||||||
expect(login).toEqual({
|
|
||||||
passwordRevisionDate: null,
|
|
||||||
autofillOnPageLoad: undefined,
|
|
||||||
username: null,
|
|
||||||
password: null,
|
|
||||||
totp: null,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert from full LoginData", () => {
|
|
||||||
const data: LoginData = {
|
|
||||||
uris: [{ uri: "uri", match: UriMatchType.Domain }],
|
|
||||||
username: "username",
|
|
||||||
password: "password",
|
|
||||||
passwordRevisionDate: "2022-01-31T12:00:00.000Z",
|
|
||||||
totp: "123",
|
|
||||||
autofillOnPageLoad: false,
|
|
||||||
};
|
|
||||||
const login = new Login(data);
|
|
||||||
|
|
||||||
expect(login).toEqual({
|
|
||||||
passwordRevisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
autofillOnPageLoad: false,
|
|
||||||
username: { encryptedString: "username", encryptionType: 0 },
|
|
||||||
password: { encryptedString: "password", encryptionType: 0 },
|
|
||||||
totp: { encryptedString: "123", encryptionType: 0 },
|
|
||||||
uris: [{ match: 0, uri: { encryptedString: "uri", encryptionType: 0 } }],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Initialize without LoginData", () => {
|
|
||||||
const login = new Login();
|
|
||||||
|
|
||||||
expect(login).toEqual({});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Decrypts correctly", async () => {
|
|
||||||
const loginUri = Substitute.for<LoginUri>();
|
|
||||||
const loginUriView = new LoginUriView();
|
|
||||||
loginUriView.uri = "decrypted uri";
|
|
||||||
loginUri.decrypt(Arg.any()).resolves(loginUriView);
|
|
||||||
|
|
||||||
const login = new Login();
|
|
||||||
login.uris = [loginUri];
|
|
||||||
login.username = mockEnc("encrypted username");
|
|
||||||
login.password = mockEnc("encrypted password");
|
|
||||||
login.passwordRevisionDate = new Date("2022-01-31T12:00:00.000Z");
|
|
||||||
login.totp = mockEnc("encrypted totp");
|
|
||||||
login.autofillOnPageLoad = true;
|
|
||||||
|
|
||||||
const loginView = await login.decrypt(null);
|
|
||||||
expect(loginView).toEqual({
|
|
||||||
username: "encrypted username",
|
|
||||||
password: "encrypted password",
|
|
||||||
passwordRevisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
totp: "encrypted totp",
|
|
||||||
uris: [
|
|
||||||
{
|
|
||||||
match: null,
|
|
||||||
_uri: "decrypted uri",
|
|
||||||
_domain: null,
|
|
||||||
_hostname: null,
|
|
||||||
_host: null,
|
|
||||||
_canLaunch: null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
autofillOnPageLoad: true,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Converts from LoginData and back", () => {
|
|
||||||
const data: LoginData = {
|
|
||||||
uris: [{ uri: "uri", match: UriMatchType.Domain }],
|
|
||||||
username: "username",
|
|
||||||
password: "password",
|
|
||||||
passwordRevisionDate: "2022-01-31T12:00:00.000Z",
|
|
||||||
totp: "123",
|
|
||||||
autofillOnPageLoad: false,
|
|
||||||
};
|
|
||||||
const login = new Login(data);
|
|
||||||
|
|
||||||
const loginData = login.toLoginData();
|
|
||||||
|
|
||||||
expect(loginData).toEqual(data);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
import { UriMatchType } from "@/jslib/common/src/enums/uriMatchType";
|
|
||||||
import { LoginUriData } from "@/jslib/common/src/models/data/loginUriData";
|
|
||||||
import { LoginUri } from "@/jslib/common/src/models/domain/loginUri";
|
|
||||||
|
|
||||||
import { mockEnc } from "../utils";
|
|
||||||
|
|
||||||
describe("LoginUri", () => {
|
|
||||||
let data: LoginUriData;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
data = {
|
|
||||||
uri: "encUri",
|
|
||||||
match: UriMatchType.Domain,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert from empty", () => {
|
|
||||||
const data = new LoginUriData();
|
|
||||||
const loginUri = new LoginUri(data);
|
|
||||||
|
|
||||||
expect(loginUri).toEqual({
|
|
||||||
match: null,
|
|
||||||
uri: null,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert", () => {
|
|
||||||
const loginUri = new LoginUri(data);
|
|
||||||
|
|
||||||
expect(loginUri).toEqual({
|
|
||||||
match: 0,
|
|
||||||
uri: { encryptedString: "encUri", encryptionType: 0 },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("toLoginUriData", () => {
|
|
||||||
const loginUri = new LoginUri(data);
|
|
||||||
expect(loginUri.toLoginUriData()).toEqual(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Decrypt", async () => {
|
|
||||||
const loginUri = new LoginUri();
|
|
||||||
loginUri.match = UriMatchType.Exact;
|
|
||||||
loginUri.uri = mockEnc("uri");
|
|
||||||
|
|
||||||
const view = await loginUri.decrypt(null);
|
|
||||||
|
|
||||||
expect(view).toEqual({
|
|
||||||
_canLaunch: null,
|
|
||||||
_domain: null,
|
|
||||||
_host: null,
|
|
||||||
_hostname: null,
|
|
||||||
_uri: "uri",
|
|
||||||
match: 3,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
import { PasswordHistoryData } from "@/jslib/common/src/models/data/passwordHistoryData";
|
|
||||||
import { Password } from "@/jslib/common/src/models/domain/password";
|
|
||||||
|
|
||||||
import { mockEnc } from "../utils";
|
|
||||||
|
|
||||||
describe("Password", () => {
|
|
||||||
let data: PasswordHistoryData;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
data = {
|
|
||||||
password: "encPassword",
|
|
||||||
lastUsedDate: "2022-01-31T12:00:00.000Z",
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert from empty", () => {
|
|
||||||
const data = new PasswordHistoryData();
|
|
||||||
const password = new Password(data);
|
|
||||||
|
|
||||||
expect(password).toMatchObject({
|
|
||||||
password: null,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert", () => {
|
|
||||||
const password = new Password(data);
|
|
||||||
|
|
||||||
expect(password).toEqual({
|
|
||||||
password: { encryptedString: "encPassword", encryptionType: 0 },
|
|
||||||
lastUsedDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("toPasswordHistoryData", () => {
|
|
||||||
const password = new Password(data);
|
|
||||||
expect(password.toPasswordHistoryData()).toEqual(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Decrypt", async () => {
|
|
||||||
const password = new Password();
|
|
||||||
password.password = mockEnc("password");
|
|
||||||
password.lastUsedDate = new Date("2022-01-31T12:00:00.000Z");
|
|
||||||
|
|
||||||
const view = await password.decrypt(null);
|
|
||||||
|
|
||||||
expect(view).toEqual({
|
|
||||||
password: "password",
|
|
||||||
lastUsedDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
import { SecureNoteType } from "@/jslib/common/src/enums/secureNoteType";
|
|
||||||
import { SecureNoteData } from "@/jslib/common/src/models/data/secureNoteData";
|
|
||||||
import { SecureNote } from "@/jslib/common/src/models/domain/secureNote";
|
|
||||||
|
|
||||||
describe("SecureNote", () => {
|
|
||||||
let data: SecureNoteData;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
data = {
|
|
||||||
type: SecureNoteType.Generic,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert from empty", () => {
|
|
||||||
const data = new SecureNoteData();
|
|
||||||
const secureNote = new SecureNote(data);
|
|
||||||
|
|
||||||
expect(secureNote).toEqual({
|
|
||||||
type: undefined,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert", () => {
|
|
||||||
const secureNote = new SecureNote(data);
|
|
||||||
|
|
||||||
expect(secureNote).toEqual({
|
|
||||||
type: 0,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("toSecureNoteData", () => {
|
|
||||||
const secureNote = new SecureNote(data);
|
|
||||||
expect(secureNote.toSecureNoteData()).toEqual(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Decrypt", async () => {
|
|
||||||
const secureNote = new SecureNote();
|
|
||||||
secureNote.type = SecureNoteType.Generic;
|
|
||||||
|
|
||||||
const view = await secureNote.decrypt(null);
|
|
||||||
|
|
||||||
expect(view).toEqual({
|
|
||||||
type: 0,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
import { Substitute, Arg, SubstituteOf } from "@fluffy-spoon/substitute";
|
|
||||||
|
|
||||||
import { CryptoService } from "@/jslib/common/src/abstractions/crypto.service";
|
|
||||||
import { SendType } from "@/jslib/common/src/enums/sendType";
|
|
||||||
import { SendData } from "@/jslib/common/src/models/data/sendData";
|
|
||||||
import { EncString } from "@/jslib/common/src/models/domain/encString";
|
|
||||||
import { Send } from "@/jslib/common/src/models/domain/send";
|
|
||||||
import { SendText } from "@/jslib/common/src/models/domain/sendText";
|
|
||||||
import { ContainerService } from "@/jslib/common/src/services/container.service";
|
|
||||||
|
|
||||||
import { makeStaticByteArray, mockEnc } from "../utils";
|
|
||||||
|
|
||||||
describe("Send", () => {
|
|
||||||
let data: SendData;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
data = {
|
|
||||||
id: "id",
|
|
||||||
accessId: "accessId",
|
|
||||||
userId: "userId",
|
|
||||||
type: SendType.Text,
|
|
||||||
name: "encName",
|
|
||||||
notes: "encNotes",
|
|
||||||
text: {
|
|
||||||
text: "encText",
|
|
||||||
hidden: true,
|
|
||||||
},
|
|
||||||
file: null,
|
|
||||||
key: "encKey",
|
|
||||||
maxAccessCount: null,
|
|
||||||
accessCount: 10,
|
|
||||||
revisionDate: "2022-01-31T12:00:00.000Z",
|
|
||||||
expirationDate: "2022-01-31T12:00:00.000Z",
|
|
||||||
deletionDate: "2022-01-31T12:00:00.000Z",
|
|
||||||
password: "password",
|
|
||||||
disabled: false,
|
|
||||||
hideEmail: true,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert from empty", () => {
|
|
||||||
const data = new SendData();
|
|
||||||
const send = new Send(data);
|
|
||||||
|
|
||||||
expect(send).toEqual({
|
|
||||||
id: null,
|
|
||||||
accessId: null,
|
|
||||||
userId: null,
|
|
||||||
type: undefined,
|
|
||||||
name: null,
|
|
||||||
notes: null,
|
|
||||||
text: undefined,
|
|
||||||
file: undefined,
|
|
||||||
key: null,
|
|
||||||
maxAccessCount: undefined,
|
|
||||||
accessCount: undefined,
|
|
||||||
revisionDate: null,
|
|
||||||
expirationDate: null,
|
|
||||||
deletionDate: null,
|
|
||||||
password: undefined,
|
|
||||||
disabled: undefined,
|
|
||||||
hideEmail: undefined,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert", () => {
|
|
||||||
const send = new Send(data);
|
|
||||||
|
|
||||||
expect(send).toEqual({
|
|
||||||
id: "id",
|
|
||||||
accessId: "accessId",
|
|
||||||
userId: "userId",
|
|
||||||
type: SendType.Text,
|
|
||||||
name: { encryptedString: "encName", encryptionType: 0 },
|
|
||||||
notes: { encryptedString: "encNotes", encryptionType: 0 },
|
|
||||||
text: {
|
|
||||||
text: { encryptedString: "encText", encryptionType: 0 },
|
|
||||||
hidden: true,
|
|
||||||
},
|
|
||||||
key: { encryptedString: "encKey", encryptionType: 0 },
|
|
||||||
maxAccessCount: null,
|
|
||||||
accessCount: 10,
|
|
||||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
expirationDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
deletionDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
password: "password",
|
|
||||||
disabled: false,
|
|
||||||
hideEmail: true,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Decrypt", async () => {
|
|
||||||
const text = Substitute.for<SendText>();
|
|
||||||
text.decrypt(Arg.any()).resolves("textView" as any);
|
|
||||||
|
|
||||||
const send = new Send();
|
|
||||||
send.id = "id";
|
|
||||||
send.accessId = "accessId";
|
|
||||||
send.userId = "userId";
|
|
||||||
send.type = SendType.Text;
|
|
||||||
send.name = mockEnc("name");
|
|
||||||
send.notes = mockEnc("notes");
|
|
||||||
send.text = text;
|
|
||||||
send.key = mockEnc("key");
|
|
||||||
send.accessCount = 10;
|
|
||||||
send.revisionDate = new Date("2022-01-31T12:00:00.000Z");
|
|
||||||
send.expirationDate = new Date("2022-01-31T12:00:00.000Z");
|
|
||||||
send.deletionDate = new Date("2022-01-31T12:00:00.000Z");
|
|
||||||
send.password = "password";
|
|
||||||
send.disabled = false;
|
|
||||||
send.hideEmail = true;
|
|
||||||
|
|
||||||
const cryptoService = Substitute.for<CryptoService>();
|
|
||||||
cryptoService.decryptToBytes(send.key, null).resolves(makeStaticByteArray(32));
|
|
||||||
cryptoService.makeSendKey(Arg.any()).resolves("cryptoKey" as any);
|
|
||||||
|
|
||||||
(window as any).bitwardenContainerService = new ContainerService(cryptoService);
|
|
||||||
|
|
||||||
const view = await send.decrypt();
|
|
||||||
|
|
||||||
text.received(1).decrypt("cryptoKey" as any);
|
|
||||||
(send.name as SubstituteOf<EncString>).received(1).decrypt(null, "cryptoKey" as any);
|
|
||||||
|
|
||||||
expect(view).toMatchObject({
|
|
||||||
id: "id",
|
|
||||||
accessId: "accessId",
|
|
||||||
name: "name",
|
|
||||||
notes: "notes",
|
|
||||||
type: 0,
|
|
||||||
key: expect.anything(),
|
|
||||||
cryptoKey: "cryptoKey",
|
|
||||||
file: expect.anything(),
|
|
||||||
text: "textView",
|
|
||||||
maxAccessCount: undefined,
|
|
||||||
accessCount: 10,
|
|
||||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
expirationDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
deletionDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
password: "password",
|
|
||||||
disabled: false,
|
|
||||||
hideEmail: true,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
import { Substitute, Arg } from "@fluffy-spoon/substitute";
|
|
||||||
|
|
||||||
import { SendType } from "@/jslib/common/src/enums/sendType";
|
|
||||||
import { SendAccess } from "@/jslib/common/src/models/domain/sendAccess";
|
|
||||||
import { SendText } from "@/jslib/common/src/models/domain/sendText";
|
|
||||||
import { SendAccessResponse } from "@/jslib/common/src/models/response/sendAccessResponse";
|
|
||||||
|
|
||||||
import { mockEnc } from "../utils";
|
|
||||||
|
|
||||||
describe("SendAccess", () => {
|
|
||||||
let request: SendAccessResponse;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
request = {
|
|
||||||
id: "id",
|
|
||||||
type: SendType.Text,
|
|
||||||
name: "encName",
|
|
||||||
file: null,
|
|
||||||
text: {
|
|
||||||
text: "encText",
|
|
||||||
hidden: true,
|
|
||||||
},
|
|
||||||
expirationDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
creatorIdentifier: "creatorIdentifier",
|
|
||||||
} as SendAccessResponse;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert from empty", () => {
|
|
||||||
const request = new SendAccessResponse({});
|
|
||||||
const sendAccess = new SendAccess(request);
|
|
||||||
|
|
||||||
expect(sendAccess).toEqual({
|
|
||||||
id: null,
|
|
||||||
type: undefined,
|
|
||||||
name: null,
|
|
||||||
creatorIdentifier: null,
|
|
||||||
expirationDate: null,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert", () => {
|
|
||||||
const sendAccess = new SendAccess(request);
|
|
||||||
|
|
||||||
expect(sendAccess).toEqual({
|
|
||||||
id: "id",
|
|
||||||
type: 0,
|
|
||||||
name: { encryptedString: "encName", encryptionType: 0 },
|
|
||||||
text: {
|
|
||||||
hidden: true,
|
|
||||||
text: { encryptedString: "encText", encryptionType: 0 },
|
|
||||||
},
|
|
||||||
expirationDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
creatorIdentifier: "creatorIdentifier",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Decrypt", async () => {
|
|
||||||
const sendAccess = new SendAccess();
|
|
||||||
sendAccess.id = "id";
|
|
||||||
sendAccess.type = SendType.Text;
|
|
||||||
sendAccess.name = mockEnc("name");
|
|
||||||
|
|
||||||
const text = Substitute.for<SendText>();
|
|
||||||
text.decrypt(Arg.any()).resolves({} as any);
|
|
||||||
sendAccess.text = text;
|
|
||||||
|
|
||||||
sendAccess.expirationDate = new Date("2022-01-31T12:00:00.000Z");
|
|
||||||
sendAccess.creatorIdentifier = "creatorIdentifier";
|
|
||||||
|
|
||||||
const view = await sendAccess.decrypt(null);
|
|
||||||
|
|
||||||
text.received(1).decrypt(Arg.any());
|
|
||||||
|
|
||||||
expect(view).toEqual({
|
|
||||||
id: "id",
|
|
||||||
type: 0,
|
|
||||||
name: "name",
|
|
||||||
text: {},
|
|
||||||
file: expect.anything(),
|
|
||||||
expirationDate: new Date("2022-01-31T12:00:00.000Z"),
|
|
||||||
creatorIdentifier: "creatorIdentifier",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
import { SendFileData } from "@/jslib/common/src/models/data/sendFileData";
|
|
||||||
import { SendFile } from "@/jslib/common/src/models/domain/sendFile";
|
|
||||||
|
|
||||||
import { mockEnc } from "../utils";
|
|
||||||
|
|
||||||
describe("SendFile", () => {
|
|
||||||
let data: SendFileData;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
data = {
|
|
||||||
id: "id",
|
|
||||||
size: "1100",
|
|
||||||
sizeName: "1.1 KB",
|
|
||||||
fileName: "encFileName",
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert from empty", () => {
|
|
||||||
const data = new SendFileData();
|
|
||||||
const sendFile = new SendFile(data);
|
|
||||||
|
|
||||||
expect(sendFile).toEqual({
|
|
||||||
fileName: null,
|
|
||||||
id: null,
|
|
||||||
size: undefined,
|
|
||||||
sizeName: null,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert", () => {
|
|
||||||
const sendFile = new SendFile(data);
|
|
||||||
|
|
||||||
expect(sendFile).toEqual({
|
|
||||||
id: "id",
|
|
||||||
size: "1100",
|
|
||||||
sizeName: "1.1 KB",
|
|
||||||
fileName: { encryptedString: "encFileName", encryptionType: 0 },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Decrypt", async () => {
|
|
||||||
const sendFile = new SendFile();
|
|
||||||
sendFile.id = "id";
|
|
||||||
sendFile.size = "1100";
|
|
||||||
sendFile.sizeName = "1.1 KB";
|
|
||||||
sendFile.fileName = mockEnc("fileName");
|
|
||||||
|
|
||||||
const view = await sendFile.decrypt(null);
|
|
||||||
|
|
||||||
expect(view).toEqual({
|
|
||||||
fileName: "fileName",
|
|
||||||
id: "id",
|
|
||||||
size: "1100",
|
|
||||||
sizeName: "1.1 KB",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
import { SendTextData } from "@/jslib/common/src/models/data/sendTextData";
|
|
||||||
import { SendText } from "@/jslib/common/src/models/domain/sendText";
|
|
||||||
|
|
||||||
import { mockEnc } from "../utils";
|
|
||||||
|
|
||||||
describe("SendText", () => {
|
|
||||||
let data: SendTextData;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
data = {
|
|
||||||
text: "encText",
|
|
||||||
hidden: false,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert from empty", () => {
|
|
||||||
const data = new SendTextData();
|
|
||||||
const secureNote = new SendText(data);
|
|
||||||
|
|
||||||
expect(secureNote).toEqual({
|
|
||||||
hidden: undefined,
|
|
||||||
text: null,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Convert", () => {
|
|
||||||
const secureNote = new SendText(data);
|
|
||||||
|
|
||||||
expect(secureNote).toEqual({
|
|
||||||
hidden: false,
|
|
||||||
text: { encryptedString: "encText", encryptionType: 0 },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Decrypt", async () => {
|
|
||||||
const secureNote = new SendText();
|
|
||||||
secureNote.text = mockEnc("text");
|
|
||||||
secureNote.hidden = true;
|
|
||||||
|
|
||||||
const view = await secureNote.decrypt(null);
|
|
||||||
|
|
||||||
expect(view).toEqual({
|
|
||||||
text: "text",
|
|
||||||
hidden: true,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute";
|
|
||||||
|
|
||||||
import { ApiService } from "@/jslib/common/src/abstractions/api.service";
|
|
||||||
import { AppIdService } from "@/jslib/common/src/abstractions/appId.service";
|
|
||||||
import { CryptoService } from "@/jslib/common/src/abstractions/crypto.service";
|
|
||||||
import { EnvironmentService } from "@/jslib/common/src/abstractions/environment.service";
|
|
||||||
import { KeyConnectorService } from "@/jslib/common/src/abstractions/keyConnector.service";
|
|
||||||
import { LogService } from "@/jslib/common/src/abstractions/log.service";
|
|
||||||
import { MessagingService } from "@/jslib/common/src/abstractions/messaging.service";
|
|
||||||
import { PlatformUtilsService } from "@/jslib/common/src/abstractions/platformUtils.service";
|
|
||||||
import { StateService } from "@/jslib/common/src/abstractions/state.service";
|
|
||||||
import { TokenService } from "@/jslib/common/src/abstractions/token.service";
|
|
||||||
import { TwoFactorService } from "@/jslib/common/src/abstractions/twoFactor.service";
|
|
||||||
import { ApiLogInStrategy } from "@/jslib/common/src/misc/logInStrategies/apiLogin.strategy";
|
|
||||||
import { Utils } from "@/jslib/common/src/misc/utils";
|
|
||||||
import { ApiLogInCredentials } from "@/jslib/common/src/models/domain/logInCredentials";
|
|
||||||
|
|
||||||
import { identityTokenResponseFactory } from "./logIn.strategy.spec";
|
|
||||||
|
|
||||||
describe("ApiLogInStrategy", () => {
|
|
||||||
let cryptoService: SubstituteOf<CryptoService>;
|
|
||||||
let apiService: SubstituteOf<ApiService>;
|
|
||||||
let tokenService: SubstituteOf<TokenService>;
|
|
||||||
let appIdService: SubstituteOf<AppIdService>;
|
|
||||||
let platformUtilsService: SubstituteOf<PlatformUtilsService>;
|
|
||||||
let messagingService: SubstituteOf<MessagingService>;
|
|
||||||
let logService: SubstituteOf<LogService>;
|
|
||||||
let environmentService: SubstituteOf<EnvironmentService>;
|
|
||||||
let keyConnectorService: SubstituteOf<KeyConnectorService>;
|
|
||||||
let stateService: SubstituteOf<StateService>;
|
|
||||||
let twoFactorService: SubstituteOf<TwoFactorService>;
|
|
||||||
|
|
||||||
let apiLogInStrategy: ApiLogInStrategy;
|
|
||||||
let credentials: ApiLogInCredentials;
|
|
||||||
|
|
||||||
const deviceId = Utils.newGuid();
|
|
||||||
const keyConnectorUrl = "KEY_CONNECTOR_URL";
|
|
||||||
const apiClientId = "API_CLIENT_ID";
|
|
||||||
const apiClientSecret = "API_CLIENT_SECRET";
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
cryptoService = Substitute.for<CryptoService>();
|
|
||||||
apiService = Substitute.for<ApiService>();
|
|
||||||
tokenService = Substitute.for<TokenService>();
|
|
||||||
appIdService = Substitute.for<AppIdService>();
|
|
||||||
platformUtilsService = Substitute.for<PlatformUtilsService>();
|
|
||||||
messagingService = Substitute.for<MessagingService>();
|
|
||||||
logService = Substitute.for<LogService>();
|
|
||||||
environmentService = Substitute.for<EnvironmentService>();
|
|
||||||
stateService = Substitute.for<StateService>();
|
|
||||||
keyConnectorService = Substitute.for<KeyConnectorService>();
|
|
||||||
twoFactorService = Substitute.for<TwoFactorService>();
|
|
||||||
|
|
||||||
appIdService.getAppId().resolves(deviceId);
|
|
||||||
tokenService.getTwoFactorToken().resolves(null);
|
|
||||||
|
|
||||||
apiLogInStrategy = new ApiLogInStrategy(
|
|
||||||
cryptoService,
|
|
||||||
apiService,
|
|
||||||
tokenService,
|
|
||||||
appIdService,
|
|
||||||
platformUtilsService,
|
|
||||||
messagingService,
|
|
||||||
logService,
|
|
||||||
stateService,
|
|
||||||
twoFactorService,
|
|
||||||
environmentService,
|
|
||||||
keyConnectorService
|
|
||||||
);
|
|
||||||
|
|
||||||
credentials = new ApiLogInCredentials(apiClientId, apiClientSecret);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sends api key credentials to the server", async () => {
|
|
||||||
apiService.postIdentityToken(Arg.any()).resolves(identityTokenResponseFactory());
|
|
||||||
await apiLogInStrategy.logIn(credentials);
|
|
||||||
|
|
||||||
apiService.received(1).postIdentityToken(
|
|
||||||
Arg.is((actual) => {
|
|
||||||
const apiTokenRequest = actual as any;
|
|
||||||
return (
|
|
||||||
apiTokenRequest.clientId === apiClientId &&
|
|
||||||
apiTokenRequest.clientSecret === apiClientSecret &&
|
|
||||||
apiTokenRequest.device.identifier === deviceId &&
|
|
||||||
apiTokenRequest.twoFactor.provider == null &&
|
|
||||||
apiTokenRequest.twoFactor.token == null &&
|
|
||||||
apiTokenRequest.captchaResponse == null
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sets the local environment after a successful login", async () => {
|
|
||||||
apiService.postIdentityToken(Arg.any()).resolves(identityTokenResponseFactory());
|
|
||||||
|
|
||||||
await apiLogInStrategy.logIn(credentials);
|
|
||||||
|
|
||||||
stateService.received(1).setApiKeyClientId(apiClientId);
|
|
||||||
stateService.received(1).setApiKeyClientSecret(apiClientSecret);
|
|
||||||
stateService.received(1).addAccount(Arg.any());
|
|
||||||
});
|
|
||||||
|
|
||||||
it("gets and sets the Key Connector key from environmentUrl", async () => {
|
|
||||||
const tokenResponse = identityTokenResponseFactory();
|
|
||||||
tokenResponse.apiUseKeyConnector = true;
|
|
||||||
|
|
||||||
apiService.postIdentityToken(Arg.any()).resolves(tokenResponse);
|
|
||||||
environmentService.getKeyConnectorUrl().returns(keyConnectorUrl);
|
|
||||||
|
|
||||||
await apiLogInStrategy.logIn(credentials);
|
|
||||||
|
|
||||||
keyConnectorService.received(1).getAndSetKey(keyConnectorUrl);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,288 +0,0 @@
|
|||||||
import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute";
|
|
||||||
|
|
||||||
import { ApiService } from "@/jslib/common/src/abstractions/api.service";
|
|
||||||
import { AppIdService } from "@/jslib/common/src/abstractions/appId.service";
|
|
||||||
import { AuthService } from "@/jslib/common/src/abstractions/auth.service";
|
|
||||||
import { CryptoService } from "@/jslib/common/src/abstractions/crypto.service";
|
|
||||||
import { LogService } from "@/jslib/common/src/abstractions/log.service";
|
|
||||||
import { MessagingService } from "@/jslib/common/src/abstractions/messaging.service";
|
|
||||||
import { PlatformUtilsService } from "@/jslib/common/src/abstractions/platformUtils.service";
|
|
||||||
import { StateService } from "@/jslib/common/src/abstractions/state.service";
|
|
||||||
import { TokenService } from "@/jslib/common/src/abstractions/token.service";
|
|
||||||
import { TwoFactorService } from "@/jslib/common/src/abstractions/twoFactor.service";
|
|
||||||
import { TwoFactorProviderType } from "@/jslib/common/src/enums/twoFactorProviderType";
|
|
||||||
import { PasswordLogInStrategy } from "@/jslib/common/src/misc/logInStrategies/passwordLogin.strategy";
|
|
||||||
import { Utils } from "@/jslib/common/src/misc/utils";
|
|
||||||
import { Account, AccountProfile, AccountTokens } from "@/jslib/common/src/models/domain/account";
|
|
||||||
import { AuthResult } from "@/jslib/common/src/models/domain/authResult";
|
|
||||||
import { EncString } from "@/jslib/common/src/models/domain/encString";
|
|
||||||
import { PasswordLogInCredentials } from "@/jslib/common/src/models/domain/logInCredentials";
|
|
||||||
import { PasswordTokenRequest } from "@/jslib/common/src/models/request/identityToken/passwordTokenRequest";
|
|
||||||
import { TokenRequestTwoFactor } from "@/jslib/common/src/models/request/identityToken/tokenRequestTwoFactor";
|
|
||||||
import { IdentityCaptchaResponse } from "@/jslib/common/src/models/response/identityCaptchaResponse";
|
|
||||||
import { IdentityTokenResponse } from "@/jslib/common/src/models/response/identityTokenResponse";
|
|
||||||
import { IdentityTwoFactorResponse } from "@/jslib/common/src/models/response/identityTwoFactorResponse";
|
|
||||||
|
|
||||||
const email = "hello@world.com";
|
|
||||||
const masterPassword = "password";
|
|
||||||
|
|
||||||
const deviceId = Utils.newGuid();
|
|
||||||
const accessToken = "ACCESS_TOKEN";
|
|
||||||
const refreshToken = "REFRESH_TOKEN";
|
|
||||||
const encKey = "ENC_KEY";
|
|
||||||
const privateKey = "PRIVATE_KEY";
|
|
||||||
const captchaSiteKey = "CAPTCHA_SITE_KEY";
|
|
||||||
const kdf = 0;
|
|
||||||
const kdfIterations = 10000;
|
|
||||||
const userId = Utils.newGuid();
|
|
||||||
const masterPasswordHash = "MASTER_PASSWORD_HASH";
|
|
||||||
|
|
||||||
const decodedToken = {
|
|
||||||
sub: userId,
|
|
||||||
email: email,
|
|
||||||
premium: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
const twoFactorProviderType = TwoFactorProviderType.Authenticator;
|
|
||||||
const twoFactorToken = "TWO_FACTOR_TOKEN";
|
|
||||||
const twoFactorRemember = true;
|
|
||||||
|
|
||||||
export function identityTokenResponseFactory() {
|
|
||||||
return new IdentityTokenResponse({
|
|
||||||
ForcePasswordReset: false,
|
|
||||||
Kdf: kdf,
|
|
||||||
KdfIterations: kdfIterations,
|
|
||||||
Key: encKey,
|
|
||||||
PrivateKey: privateKey,
|
|
||||||
ResetMasterPassword: false,
|
|
||||||
access_token: accessToken,
|
|
||||||
expires_in: 3600,
|
|
||||||
refresh_token: refreshToken,
|
|
||||||
scope: "api offline_access",
|
|
||||||
token_type: "Bearer",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("LogInStrategy", () => {
|
|
||||||
let cryptoService: SubstituteOf<CryptoService>;
|
|
||||||
let apiService: SubstituteOf<ApiService>;
|
|
||||||
let tokenService: SubstituteOf<TokenService>;
|
|
||||||
let appIdService: SubstituteOf<AppIdService>;
|
|
||||||
let platformUtilsService: SubstituteOf<PlatformUtilsService>;
|
|
||||||
let messagingService: SubstituteOf<MessagingService>;
|
|
||||||
let logService: SubstituteOf<LogService>;
|
|
||||||
let stateService: SubstituteOf<StateService>;
|
|
||||||
let twoFactorService: SubstituteOf<TwoFactorService>;
|
|
||||||
let authService: SubstituteOf<AuthService>;
|
|
||||||
|
|
||||||
let passwordLogInStrategy: PasswordLogInStrategy;
|
|
||||||
let credentials: PasswordLogInCredentials;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
cryptoService = Substitute.for<CryptoService>();
|
|
||||||
apiService = Substitute.for<ApiService>();
|
|
||||||
tokenService = Substitute.for<TokenService>();
|
|
||||||
appIdService = Substitute.for<AppIdService>();
|
|
||||||
platformUtilsService = Substitute.for<PlatformUtilsService>();
|
|
||||||
messagingService = Substitute.for<MessagingService>();
|
|
||||||
logService = Substitute.for<LogService>();
|
|
||||||
stateService = Substitute.for<StateService>();
|
|
||||||
twoFactorService = Substitute.for<TwoFactorService>();
|
|
||||||
authService = Substitute.for<AuthService>();
|
|
||||||
|
|
||||||
appIdService.getAppId().resolves(deviceId);
|
|
||||||
|
|
||||||
// The base class is abstract so we test it via PasswordLogInStrategy
|
|
||||||
passwordLogInStrategy = new PasswordLogInStrategy(
|
|
||||||
cryptoService,
|
|
||||||
apiService,
|
|
||||||
tokenService,
|
|
||||||
appIdService,
|
|
||||||
platformUtilsService,
|
|
||||||
messagingService,
|
|
||||||
logService,
|
|
||||||
stateService,
|
|
||||||
twoFactorService,
|
|
||||||
authService
|
|
||||||
);
|
|
||||||
credentials = new PasswordLogInCredentials(email, masterPassword);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("base class", () => {
|
|
||||||
it("sets the local environment after a successful login", async () => {
|
|
||||||
apiService.postIdentityToken(Arg.any()).resolves(identityTokenResponseFactory());
|
|
||||||
tokenService.decodeToken(accessToken).resolves(decodedToken);
|
|
||||||
|
|
||||||
await passwordLogInStrategy.logIn(credentials);
|
|
||||||
|
|
||||||
stateService.received(1).addAccount(
|
|
||||||
new Account({
|
|
||||||
profile: {
|
|
||||||
...new AccountProfile(),
|
|
||||||
...{
|
|
||||||
userId: userId,
|
|
||||||
email: email,
|
|
||||||
hasPremiumPersonally: false,
|
|
||||||
kdfIterations: kdfIterations,
|
|
||||||
kdfType: kdf,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tokens: {
|
|
||||||
...new AccountTokens(),
|
|
||||||
...{
|
|
||||||
accessToken: accessToken,
|
|
||||||
refreshToken: refreshToken,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
cryptoService.received(1).setEncKey(encKey);
|
|
||||||
cryptoService.received(1).setEncPrivateKey(privateKey);
|
|
||||||
|
|
||||||
stateService.received(1).setBiometricLocked(false);
|
|
||||||
messagingService.received(1).send("loggedIn");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("builds AuthResult", async () => {
|
|
||||||
const tokenResponse = identityTokenResponseFactory();
|
|
||||||
tokenResponse.forcePasswordReset = true;
|
|
||||||
tokenResponse.resetMasterPassword = true;
|
|
||||||
|
|
||||||
apiService.postIdentityToken(Arg.any()).resolves(tokenResponse);
|
|
||||||
|
|
||||||
const result = await passwordLogInStrategy.logIn(credentials);
|
|
||||||
|
|
||||||
const expected = new AuthResult();
|
|
||||||
expected.forcePasswordReset = true;
|
|
||||||
expected.resetMasterPassword = true;
|
|
||||||
expected.twoFactorProviders = null;
|
|
||||||
expected.captchaSiteKey = "";
|
|
||||||
expect(result).toEqual(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("rejects login if CAPTCHA is required", async () => {
|
|
||||||
// Sample CAPTCHA response
|
|
||||||
const tokenResponse = new IdentityCaptchaResponse({
|
|
||||||
error: "invalid_grant",
|
|
||||||
error_description: "Captcha required.",
|
|
||||||
HCaptcha_SiteKey: captchaSiteKey,
|
|
||||||
});
|
|
||||||
|
|
||||||
apiService.postIdentityToken(Arg.any()).resolves(tokenResponse);
|
|
||||||
|
|
||||||
const result = await passwordLogInStrategy.logIn(credentials);
|
|
||||||
|
|
||||||
stateService.didNotReceive().addAccount(Arg.any());
|
|
||||||
messagingService.didNotReceive().send(Arg.any());
|
|
||||||
|
|
||||||
const expected = new AuthResult();
|
|
||||||
expected.captchaSiteKey = captchaSiteKey;
|
|
||||||
expect(result).toEqual(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("makes a new public and private key for an old account", async () => {
|
|
||||||
const tokenResponse = identityTokenResponseFactory();
|
|
||||||
tokenResponse.privateKey = null;
|
|
||||||
cryptoService.makeKeyPair(Arg.any()).resolves(["PUBLIC_KEY", new EncString("PRIVATE_KEY")]);
|
|
||||||
|
|
||||||
apiService.postIdentityToken(Arg.any()).resolves(tokenResponse);
|
|
||||||
|
|
||||||
await passwordLogInStrategy.logIn(credentials);
|
|
||||||
|
|
||||||
apiService.received(1).postAccountKeys(Arg.any());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("Two-factor authentication", () => {
|
|
||||||
it("rejects login if 2FA is required", async () => {
|
|
||||||
// Sample response where TOTP 2FA required
|
|
||||||
const tokenResponse = new IdentityTwoFactorResponse({
|
|
||||||
TwoFactorProviders: ["0"],
|
|
||||||
TwoFactorProviders2: { 0: null },
|
|
||||||
error: "invalid_grant",
|
|
||||||
error_description: "Two factor required.",
|
|
||||||
});
|
|
||||||
|
|
||||||
apiService.postIdentityToken(Arg.any()).resolves(tokenResponse);
|
|
||||||
|
|
||||||
const result = await passwordLogInStrategy.logIn(credentials);
|
|
||||||
|
|
||||||
stateService.didNotReceive().addAccount(Arg.any());
|
|
||||||
messagingService.didNotReceive().send(Arg.any());
|
|
||||||
|
|
||||||
const expected = new AuthResult();
|
|
||||||
expected.twoFactorProviders = new Map<TwoFactorProviderType, { [key: string]: string }>();
|
|
||||||
expected.twoFactorProviders.set(0, null);
|
|
||||||
expect(result).toEqual(expected);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sends stored 2FA token to server", async () => {
|
|
||||||
tokenService.getTwoFactorToken().resolves(twoFactorToken);
|
|
||||||
apiService.postIdentityToken(Arg.any()).resolves(identityTokenResponseFactory());
|
|
||||||
|
|
||||||
await passwordLogInStrategy.logIn(credentials);
|
|
||||||
|
|
||||||
apiService.received(1).postIdentityToken(
|
|
||||||
Arg.is((actual) => {
|
|
||||||
const passwordTokenRequest = actual as any;
|
|
||||||
return (
|
|
||||||
passwordTokenRequest.twoFactor.provider === TwoFactorProviderType.Remember &&
|
|
||||||
passwordTokenRequest.twoFactor.token === twoFactorToken &&
|
|
||||||
passwordTokenRequest.twoFactor.remember === false
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sends 2FA token provided by user to server (single step)", async () => {
|
|
||||||
// This occurs if the user enters the 2FA code as an argument in the CLI
|
|
||||||
apiService.postIdentityToken(Arg.any()).resolves(identityTokenResponseFactory());
|
|
||||||
credentials.twoFactor = new TokenRequestTwoFactor(
|
|
||||||
twoFactorProviderType,
|
|
||||||
twoFactorToken,
|
|
||||||
twoFactorRemember
|
|
||||||
);
|
|
||||||
|
|
||||||
await passwordLogInStrategy.logIn(credentials);
|
|
||||||
|
|
||||||
apiService.received(1).postIdentityToken(
|
|
||||||
Arg.is((actual) => {
|
|
||||||
const passwordTokenRequest = actual as any;
|
|
||||||
return (
|
|
||||||
passwordTokenRequest.twoFactor.provider === twoFactorProviderType &&
|
|
||||||
passwordTokenRequest.twoFactor.token === twoFactorToken &&
|
|
||||||
passwordTokenRequest.twoFactor.remember === twoFactorRemember
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sends 2FA token provided by user to server (two-step)", async () => {
|
|
||||||
// Simulate a partially completed login
|
|
||||||
passwordLogInStrategy.tokenRequest = new PasswordTokenRequest(
|
|
||||||
email,
|
|
||||||
masterPasswordHash,
|
|
||||||
null,
|
|
||||||
null
|
|
||||||
);
|
|
||||||
|
|
||||||
apiService.postIdentityToken(Arg.any()).resolves(identityTokenResponseFactory());
|
|
||||||
|
|
||||||
await passwordLogInStrategy.logInTwoFactor(
|
|
||||||
new TokenRequestTwoFactor(twoFactorProviderType, twoFactorToken, twoFactorRemember),
|
|
||||||
null
|
|
||||||
);
|
|
||||||
|
|
||||||
apiService.received(1).postIdentityToken(
|
|
||||||
Arg.is((actual) => {
|
|
||||||
const passwordTokenRequest = actual as any;
|
|
||||||
return (
|
|
||||||
passwordTokenRequest.twoFactor.provider === twoFactorProviderType &&
|
|
||||||
passwordTokenRequest.twoFactor.token === twoFactorToken &&
|
|
||||||
passwordTokenRequest.twoFactor.remember === twoFactorRemember
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute";
|
|
||||||
|
|
||||||
import { ApiService } from "@/jslib/common/src/abstractions/api.service";
|
|
||||||
import { AppIdService } from "@/jslib/common/src/abstractions/appId.service";
|
|
||||||
import { AuthService } from "@/jslib/common/src/abstractions/auth.service";
|
|
||||||
import { CryptoService } from "@/jslib/common/src/abstractions/crypto.service";
|
|
||||||
import { LogService } from "@/jslib/common/src/abstractions/log.service";
|
|
||||||
import { MessagingService } from "@/jslib/common/src/abstractions/messaging.service";
|
|
||||||
import { PlatformUtilsService } from "@/jslib/common/src/abstractions/platformUtils.service";
|
|
||||||
import { StateService } from "@/jslib/common/src/abstractions/state.service";
|
|
||||||
import { TokenService } from "@/jslib/common/src/abstractions/token.service";
|
|
||||||
import { TwoFactorService } from "@/jslib/common/src/abstractions/twoFactor.service";
|
|
||||||
import { HashPurpose } from "@/jslib/common/src/enums/hashPurpose";
|
|
||||||
import { PasswordLogInStrategy } from "@/jslib/common/src/misc/logInStrategies/passwordLogin.strategy";
|
|
||||||
import { Utils } from "@/jslib/common/src/misc/utils";
|
|
||||||
import { PasswordLogInCredentials } from "@/jslib/common/src/models/domain/logInCredentials";
|
|
||||||
import { SymmetricCryptoKey } from "@/jslib/common/src/models/domain/symmetricCryptoKey";
|
|
||||||
|
|
||||||
import { identityTokenResponseFactory } from "./logIn.strategy.spec";
|
|
||||||
|
|
||||||
const email = "hello@world.com";
|
|
||||||
const masterPassword = "password";
|
|
||||||
const hashedPassword = "HASHED_PASSWORD";
|
|
||||||
const localHashedPassword = "LOCAL_HASHED_PASSWORD";
|
|
||||||
const preloginKey = new SymmetricCryptoKey(
|
|
||||||
Utils.fromB64ToArray(
|
|
||||||
"N2KWjlLpfi5uHjv+YcfUKIpZ1l+W+6HRensmIqD+BFYBf6N/dvFpJfWwYnVBdgFCK2tJTAIMLhqzIQQEUmGFgg=="
|
|
||||||
)
|
|
||||||
);
|
|
||||||
const deviceId = Utils.newGuid();
|
|
||||||
|
|
||||||
describe("PasswordLogInStrategy", () => {
|
|
||||||
let cryptoService: SubstituteOf<CryptoService>;
|
|
||||||
let apiService: SubstituteOf<ApiService>;
|
|
||||||
let tokenService: SubstituteOf<TokenService>;
|
|
||||||
let appIdService: SubstituteOf<AppIdService>;
|
|
||||||
let platformUtilsService: SubstituteOf<PlatformUtilsService>;
|
|
||||||
let messagingService: SubstituteOf<MessagingService>;
|
|
||||||
let logService: SubstituteOf<LogService>;
|
|
||||||
let stateService: SubstituteOf<StateService>;
|
|
||||||
let twoFactorService: SubstituteOf<TwoFactorService>;
|
|
||||||
let authService: SubstituteOf<AuthService>;
|
|
||||||
|
|
||||||
let passwordLogInStrategy: PasswordLogInStrategy;
|
|
||||||
let credentials: PasswordLogInCredentials;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
cryptoService = Substitute.for<CryptoService>();
|
|
||||||
apiService = Substitute.for<ApiService>();
|
|
||||||
tokenService = Substitute.for<TokenService>();
|
|
||||||
appIdService = Substitute.for<AppIdService>();
|
|
||||||
platformUtilsService = Substitute.for<PlatformUtilsService>();
|
|
||||||
messagingService = Substitute.for<MessagingService>();
|
|
||||||
logService = Substitute.for<LogService>();
|
|
||||||
stateService = Substitute.for<StateService>();
|
|
||||||
twoFactorService = Substitute.for<TwoFactorService>();
|
|
||||||
authService = Substitute.for<AuthService>();
|
|
||||||
|
|
||||||
appIdService.getAppId().resolves(deviceId);
|
|
||||||
tokenService.getTwoFactorToken().resolves(null);
|
|
||||||
|
|
||||||
authService.makePreloginKey(Arg.any(), Arg.any()).resolves(preloginKey);
|
|
||||||
|
|
||||||
cryptoService.hashPassword(masterPassword, Arg.any()).resolves(hashedPassword);
|
|
||||||
cryptoService
|
|
||||||
.hashPassword(masterPassword, Arg.any(), HashPurpose.LocalAuthorization)
|
|
||||||
.resolves(localHashedPassword);
|
|
||||||
|
|
||||||
passwordLogInStrategy = new PasswordLogInStrategy(
|
|
||||||
cryptoService,
|
|
||||||
apiService,
|
|
||||||
tokenService,
|
|
||||||
appIdService,
|
|
||||||
platformUtilsService,
|
|
||||||
messagingService,
|
|
||||||
logService,
|
|
||||||
stateService,
|
|
||||||
twoFactorService,
|
|
||||||
authService
|
|
||||||
);
|
|
||||||
credentials = new PasswordLogInCredentials(email, masterPassword);
|
|
||||||
|
|
||||||
apiService.postIdentityToken(Arg.any()).resolves(identityTokenResponseFactory());
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sends master password credentials to the server", async () => {
|
|
||||||
await passwordLogInStrategy.logIn(credentials);
|
|
||||||
|
|
||||||
apiService.received(1).postIdentityToken(
|
|
||||||
Arg.is((actual) => {
|
|
||||||
const passwordTokenRequest = actual as any; // Need to access private fields
|
|
||||||
return (
|
|
||||||
passwordTokenRequest.email === email &&
|
|
||||||
passwordTokenRequest.masterPasswordHash === hashedPassword &&
|
|
||||||
passwordTokenRequest.device.identifier === deviceId &&
|
|
||||||
passwordTokenRequest.twoFactor.provider == null &&
|
|
||||||
passwordTokenRequest.twoFactor.token == null &&
|
|
||||||
passwordTokenRequest.captchaResponse == null
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sets the local environment after a successful login", async () => {
|
|
||||||
await passwordLogInStrategy.logIn(credentials);
|
|
||||||
|
|
||||||
cryptoService.received(1).setKey(preloginKey);
|
|
||||||
cryptoService.received(1).setKeyHash(localHashedPassword);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute";
|
|
||||||
|
|
||||||
import { ApiService } from "@/jslib/common/src/abstractions/api.service";
|
|
||||||
import { AppIdService } from "@/jslib/common/src/abstractions/appId.service";
|
|
||||||
import { CryptoService } from "@/jslib/common/src/abstractions/crypto.service";
|
|
||||||
import { KeyConnectorService } from "@/jslib/common/src/abstractions/keyConnector.service";
|
|
||||||
import { LogService } from "@/jslib/common/src/abstractions/log.service";
|
|
||||||
import { MessagingService } from "@/jslib/common/src/abstractions/messaging.service";
|
|
||||||
import { PlatformUtilsService } from "@/jslib/common/src/abstractions/platformUtils.service";
|
|
||||||
import { StateService } from "@/jslib/common/src/abstractions/state.service";
|
|
||||||
import { TokenService } from "@/jslib/common/src/abstractions/token.service";
|
|
||||||
import { TwoFactorService } from "@/jslib/common/src/abstractions/twoFactor.service";
|
|
||||||
import { SsoLogInStrategy } from "@/jslib/common/src/misc/logInStrategies/ssoLogin.strategy";
|
|
||||||
import { Utils } from "@/jslib/common/src/misc/utils";
|
|
||||||
import { SsoLogInCredentials } from "@/jslib/common/src/models/domain/logInCredentials";
|
|
||||||
|
|
||||||
import { identityTokenResponseFactory } from "./logIn.strategy.spec";
|
|
||||||
|
|
||||||
describe("SsoLogInStrategy", () => {
|
|
||||||
let cryptoService: SubstituteOf<CryptoService>;
|
|
||||||
let apiService: SubstituteOf<ApiService>;
|
|
||||||
let tokenService: SubstituteOf<TokenService>;
|
|
||||||
let appIdService: SubstituteOf<AppIdService>;
|
|
||||||
let platformUtilsService: SubstituteOf<PlatformUtilsService>;
|
|
||||||
let messagingService: SubstituteOf<MessagingService>;
|
|
||||||
let logService: SubstituteOf<LogService>;
|
|
||||||
let keyConnectorService: SubstituteOf<KeyConnectorService>;
|
|
||||||
let stateService: SubstituteOf<StateService>;
|
|
||||||
let twoFactorService: SubstituteOf<TwoFactorService>;
|
|
||||||
|
|
||||||
let ssoLogInStrategy: SsoLogInStrategy;
|
|
||||||
let credentials: SsoLogInCredentials;
|
|
||||||
|
|
||||||
const deviceId = Utils.newGuid();
|
|
||||||
const encKey = "ENC_KEY";
|
|
||||||
const privateKey = "PRIVATE_KEY";
|
|
||||||
const keyConnectorUrl = "KEY_CONNECTOR_URL";
|
|
||||||
|
|
||||||
const ssoCode = "SSO_CODE";
|
|
||||||
const ssoCodeVerifier = "SSO_CODE_VERIFIER";
|
|
||||||
const ssoRedirectUrl = "SSO_REDIRECT_URL";
|
|
||||||
const ssoOrgId = "SSO_ORG_ID";
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
cryptoService = Substitute.for<CryptoService>();
|
|
||||||
apiService = Substitute.for<ApiService>();
|
|
||||||
tokenService = Substitute.for<TokenService>();
|
|
||||||
appIdService = Substitute.for<AppIdService>();
|
|
||||||
platformUtilsService = Substitute.for<PlatformUtilsService>();
|
|
||||||
messagingService = Substitute.for<MessagingService>();
|
|
||||||
logService = Substitute.for<LogService>();
|
|
||||||
stateService = Substitute.for<StateService>();
|
|
||||||
keyConnectorService = Substitute.for<KeyConnectorService>();
|
|
||||||
twoFactorService = Substitute.for<TwoFactorService>();
|
|
||||||
|
|
||||||
tokenService.getTwoFactorToken().resolves(null);
|
|
||||||
appIdService.getAppId().resolves(deviceId);
|
|
||||||
|
|
||||||
ssoLogInStrategy = new SsoLogInStrategy(
|
|
||||||
cryptoService,
|
|
||||||
apiService,
|
|
||||||
tokenService,
|
|
||||||
appIdService,
|
|
||||||
platformUtilsService,
|
|
||||||
messagingService,
|
|
||||||
logService,
|
|
||||||
stateService,
|
|
||||||
twoFactorService,
|
|
||||||
keyConnectorService
|
|
||||||
);
|
|
||||||
credentials = new SsoLogInCredentials(ssoCode, ssoCodeVerifier, ssoRedirectUrl, ssoOrgId);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sends SSO information to server", async () => {
|
|
||||||
apiService.postIdentityToken(Arg.any()).resolves(identityTokenResponseFactory());
|
|
||||||
|
|
||||||
await ssoLogInStrategy.logIn(credentials);
|
|
||||||
|
|
||||||
apiService.received(1).postIdentityToken(
|
|
||||||
Arg.is((actual) => {
|
|
||||||
const ssoTokenRequest = actual as any;
|
|
||||||
return (
|
|
||||||
ssoTokenRequest.code === ssoCode &&
|
|
||||||
ssoTokenRequest.codeVerifier === ssoCodeVerifier &&
|
|
||||||
ssoTokenRequest.redirectUri === ssoRedirectUrl &&
|
|
||||||
ssoTokenRequest.device.identifier === deviceId &&
|
|
||||||
ssoTokenRequest.twoFactor.provider == null &&
|
|
||||||
ssoTokenRequest.twoFactor.token == null
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not set keys for new SSO user flow", async () => {
|
|
||||||
const tokenResponse = identityTokenResponseFactory();
|
|
||||||
tokenResponse.key = null;
|
|
||||||
apiService.postIdentityToken(Arg.any()).resolves(tokenResponse);
|
|
||||||
|
|
||||||
await ssoLogInStrategy.logIn(credentials);
|
|
||||||
|
|
||||||
cryptoService.didNotReceive().setEncPrivateKey(privateKey);
|
|
||||||
cryptoService.didNotReceive().setEncKey(encKey);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("gets and sets KeyConnector key for enrolled user", async () => {
|
|
||||||
const tokenResponse = identityTokenResponseFactory();
|
|
||||||
tokenResponse.keyConnectorUrl = keyConnectorUrl;
|
|
||||||
|
|
||||||
apiService.postIdentityToken(Arg.any()).resolves(tokenResponse);
|
|
||||||
|
|
||||||
await ssoLogInStrategy.logIn(credentials);
|
|
||||||
|
|
||||||
keyConnectorService.received(1).getAndSetKey(keyConnectorUrl);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("converts new SSO user to Key Connector on first login", async () => {
|
|
||||||
const tokenResponse = identityTokenResponseFactory();
|
|
||||||
tokenResponse.keyConnectorUrl = keyConnectorUrl;
|
|
||||||
tokenResponse.key = null;
|
|
||||||
|
|
||||||
apiService.postIdentityToken(Arg.any()).resolves(tokenResponse);
|
|
||||||
|
|
||||||
await ssoLogInStrategy.logIn(credentials);
|
|
||||||
|
|
||||||
keyConnectorService.received(1).convertNewSsoUserToKeyConnector(tokenResponse, ssoOrgId);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute";
|
|
||||||
|
|
||||||
import { ApiService } from "@/jslib/common/src/abstractions/api.service";
|
|
||||||
import { CryptoService } from "@/jslib/common/src/abstractions/crypto.service";
|
|
||||||
import { FileUploadService } from "@/jslib/common/src/abstractions/fileUpload.service";
|
|
||||||
import { I18nService } from "@/jslib/common/src/abstractions/i18n.service";
|
|
||||||
import { LogService } from "@/jslib/common/src/abstractions/log.service";
|
|
||||||
import { SearchService } from "@/jslib/common/src/abstractions/search.service";
|
|
||||||
import { SettingsService } from "@/jslib/common/src/abstractions/settings.service";
|
|
||||||
import { StateService } from "@/jslib/common/src/abstractions/state.service";
|
|
||||||
import { Utils } from "@/jslib/common/src/misc/utils";
|
|
||||||
import { Cipher } from "@/jslib/common/src/models/domain/cipher";
|
|
||||||
import { EncArrayBuffer } from "@/jslib/common/src/models/domain/encArrayBuffer";
|
|
||||||
import { EncString } from "@/jslib/common/src/models/domain/encString";
|
|
||||||
import { SymmetricCryptoKey } from "@/jslib/common/src/models/domain/symmetricCryptoKey";
|
|
||||||
import { CipherService } from "@/jslib/common/src/services/cipher.service";
|
|
||||||
|
|
||||||
const ENCRYPTED_TEXT = "This data has been encrypted";
|
|
||||||
const ENCRYPTED_BYTES = new EncArrayBuffer(Utils.fromUtf8ToArray(ENCRYPTED_TEXT).buffer);
|
|
||||||
|
|
||||||
describe("Cipher Service", () => {
|
|
||||||
let cryptoService: SubstituteOf<CryptoService>;
|
|
||||||
let stateService: SubstituteOf<StateService>;
|
|
||||||
let settingsService: SubstituteOf<SettingsService>;
|
|
||||||
let apiService: SubstituteOf<ApiService>;
|
|
||||||
let fileUploadService: SubstituteOf<FileUploadService>;
|
|
||||||
let i18nService: SubstituteOf<I18nService>;
|
|
||||||
let searchService: SubstituteOf<SearchService>;
|
|
||||||
let logService: SubstituteOf<LogService>;
|
|
||||||
|
|
||||||
let cipherService: CipherService;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
cryptoService = Substitute.for<CryptoService>();
|
|
||||||
stateService = Substitute.for<StateService>();
|
|
||||||
settingsService = Substitute.for<SettingsService>();
|
|
||||||
apiService = Substitute.for<ApiService>();
|
|
||||||
fileUploadService = Substitute.for<FileUploadService>();
|
|
||||||
i18nService = Substitute.for<I18nService>();
|
|
||||||
searchService = Substitute.for<SearchService>();
|
|
||||||
logService = Substitute.for<LogService>();
|
|
||||||
|
|
||||||
cryptoService.encryptToBytes(Arg.any(), Arg.any()).resolves(ENCRYPTED_BYTES);
|
|
||||||
cryptoService.encrypt(Arg.any(), Arg.any()).resolves(new EncString(ENCRYPTED_TEXT));
|
|
||||||
|
|
||||||
cipherService = new CipherService(
|
|
||||||
cryptoService,
|
|
||||||
settingsService,
|
|
||||||
apiService,
|
|
||||||
fileUploadService,
|
|
||||||
i18nService,
|
|
||||||
() => searchService,
|
|
||||||
logService,
|
|
||||||
stateService
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("attachments upload encrypted file contents", async () => {
|
|
||||||
const fileName = "filename";
|
|
||||||
const fileData = new Uint8Array(10).buffer;
|
|
||||||
cryptoService.getOrgKey(Arg.any()).resolves(new SymmetricCryptoKey(new Uint8Array(32).buffer));
|
|
||||||
|
|
||||||
await cipherService.saveAttachmentRawWithServer(new Cipher(), fileName, fileData);
|
|
||||||
|
|
||||||
fileUploadService
|
|
||||||
.received(1)
|
|
||||||
.uploadCipherAttachment(Arg.any(), Arg.any(), new EncString(ENCRYPTED_TEXT), ENCRYPTED_BYTES);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -24,7 +24,7 @@ describe("State Migration Service", () => {
|
|||||||
stateMigrationService = new StateMigrationService(
|
stateMigrationService = new StateMigrationService(
|
||||||
storageService,
|
storageService,
|
||||||
secureStorageService,
|
secureStorageService,
|
||||||
stateFactory
|
stateFactory,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ describe("State Migration Service", () => {
|
|||||||
storageService.received(1).save(
|
storageService.received(1).save(
|
||||||
"global",
|
"global",
|
||||||
Arg.is((globals: GlobalState) => globals.stateVersion === StateVersion.Four),
|
Arg.is((globals: GlobalState) => globals.stateVersion === StateVersion.Four),
|
||||||
Arg.any()
|
Arg.any(),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export function GetUniqueString(prefix = "") {
|
|||||||
|
|
||||||
export function BuildTestObject<T, K extends keyof T = keyof T>(
|
export function BuildTestObject<T, K extends keyof T = keyof T>(
|
||||||
def: Partial<Pick<T, K>> | T,
|
def: Partial<Pick<T, K>> | T,
|
||||||
constructor?: new () => T
|
constructor?: new () => T,
|
||||||
): T {
|
): T {
|
||||||
return Object.assign(constructor === null ? {} : new constructor(), def) as T;
|
return Object.assign(constructor === null ? {} : new constructor(), def) as T;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,679 +1,14 @@
|
|||||||
import { PolicyType } from "../enums/policyType";
|
|
||||||
import { SetKeyConnectorKeyRequest } from "../models/request/account/setKeyConnectorKeyRequest";
|
|
||||||
import { VerifyOTPRequest } from "../models/request/account/verifyOTPRequest";
|
|
||||||
import { AttachmentRequest } from "../models/request/attachmentRequest";
|
|
||||||
import { BitPayInvoiceRequest } from "../models/request/bitPayInvoiceRequest";
|
|
||||||
import { CipherBulkDeleteRequest } from "../models/request/cipherBulkDeleteRequest";
|
|
||||||
import { CipherBulkMoveRequest } from "../models/request/cipherBulkMoveRequest";
|
|
||||||
import { CipherBulkRestoreRequest } from "../models/request/cipherBulkRestoreRequest";
|
|
||||||
import { CipherBulkShareRequest } from "../models/request/cipherBulkShareRequest";
|
|
||||||
import { CipherCollectionsRequest } from "../models/request/cipherCollectionsRequest";
|
|
||||||
import { CipherCreateRequest } from "../models/request/cipherCreateRequest";
|
|
||||||
import { CipherRequest } from "../models/request/cipherRequest";
|
|
||||||
import { CipherShareRequest } from "../models/request/cipherShareRequest";
|
|
||||||
import { CollectionRequest } from "../models/request/collectionRequest";
|
|
||||||
import { DeleteRecoverRequest } from "../models/request/deleteRecoverRequest";
|
|
||||||
import { EmailRequest } from "../models/request/emailRequest";
|
|
||||||
import { EmailTokenRequest } from "../models/request/emailTokenRequest";
|
|
||||||
import { EmergencyAccessAcceptRequest } from "../models/request/emergencyAccessAcceptRequest";
|
|
||||||
import { EmergencyAccessConfirmRequest } from "../models/request/emergencyAccessConfirmRequest";
|
|
||||||
import { EmergencyAccessInviteRequest } from "../models/request/emergencyAccessInviteRequest";
|
|
||||||
import { EmergencyAccessPasswordRequest } from "../models/request/emergencyAccessPasswordRequest";
|
|
||||||
import { EmergencyAccessUpdateRequest } from "../models/request/emergencyAccessUpdateRequest";
|
|
||||||
import { EventRequest } from "../models/request/eventRequest";
|
|
||||||
import { FolderRequest } from "../models/request/folderRequest";
|
|
||||||
import { GroupRequest } from "../models/request/groupRequest";
|
|
||||||
import { IapCheckRequest } from "../models/request/iapCheckRequest";
|
|
||||||
import { ApiTokenRequest } from "../models/request/identityToken/apiTokenRequest";
|
import { ApiTokenRequest } from "../models/request/identityToken/apiTokenRequest";
|
||||||
import { PasswordTokenRequest } from "../models/request/identityToken/passwordTokenRequest";
|
import { PasswordTokenRequest } from "../models/request/identityToken/passwordTokenRequest";
|
||||||
import { SsoTokenRequest } from "../models/request/identityToken/ssoTokenRequest";
|
import { SsoTokenRequest } from "../models/request/identityToken/ssoTokenRequest";
|
||||||
import { ImportCiphersRequest } from "../models/request/importCiphersRequest";
|
|
||||||
import { ImportDirectoryRequest } from "../models/request/importDirectoryRequest";
|
|
||||||
import { ImportOrganizationCiphersRequest } from "../models/request/importOrganizationCiphersRequest";
|
|
||||||
import { KdfRequest } from "../models/request/kdfRequest";
|
|
||||||
import { KeyConnectorUserKeyRequest } from "../models/request/keyConnectorUserKeyRequest";
|
|
||||||
import { KeysRequest } from "../models/request/keysRequest";
|
|
||||||
import { OrganizationSponsorshipCreateRequest } from "../models/request/organization/organizationSponsorshipCreateRequest";
|
|
||||||
import { OrganizationSponsorshipRedeemRequest } from "../models/request/organization/organizationSponsorshipRedeemRequest";
|
|
||||||
import { OrganizationSsoRequest } from "../models/request/organization/organizationSsoRequest";
|
|
||||||
import { OrganizationCreateRequest } from "../models/request/organizationCreateRequest";
|
|
||||||
import { OrganizationImportRequest } from "../models/request/organizationImportRequest";
|
import { OrganizationImportRequest } from "../models/request/organizationImportRequest";
|
||||||
import { OrganizationKeysRequest } from "../models/request/organizationKeysRequest";
|
|
||||||
import { OrganizationSubscriptionUpdateRequest } from "../models/request/organizationSubscriptionUpdateRequest";
|
|
||||||
import { OrganizationTaxInfoUpdateRequest } from "../models/request/organizationTaxInfoUpdateRequest";
|
|
||||||
import { OrganizationUpdateRequest } from "../models/request/organizationUpdateRequest";
|
|
||||||
import { OrganizationUpgradeRequest } from "../models/request/organizationUpgradeRequest";
|
|
||||||
import { OrganizationUserAcceptRequest } from "../models/request/organizationUserAcceptRequest";
|
|
||||||
import { OrganizationUserBulkConfirmRequest } from "../models/request/organizationUserBulkConfirmRequest";
|
|
||||||
import { OrganizationUserBulkRequest } from "../models/request/organizationUserBulkRequest";
|
|
||||||
import { OrganizationUserConfirmRequest } from "../models/request/organizationUserConfirmRequest";
|
|
||||||
import { OrganizationUserInviteRequest } from "../models/request/organizationUserInviteRequest";
|
|
||||||
import { OrganizationUserResetPasswordEnrollmentRequest } from "../models/request/organizationUserResetPasswordEnrollmentRequest";
|
|
||||||
import { OrganizationUserResetPasswordRequest } from "../models/request/organizationUserResetPasswordRequest";
|
|
||||||
import { OrganizationUserUpdateGroupsRequest } from "../models/request/organizationUserUpdateGroupsRequest";
|
|
||||||
import { OrganizationUserUpdateRequest } from "../models/request/organizationUserUpdateRequest";
|
|
||||||
import { PasswordHintRequest } from "../models/request/passwordHintRequest";
|
|
||||||
import { PasswordRequest } from "../models/request/passwordRequest";
|
|
||||||
import { PaymentRequest } from "../models/request/paymentRequest";
|
|
||||||
import { PolicyRequest } from "../models/request/policyRequest";
|
|
||||||
import { PreloginRequest } from "../models/request/preloginRequest";
|
|
||||||
import { ProviderAddOrganizationRequest } from "../models/request/provider/providerAddOrganizationRequest";
|
|
||||||
import { ProviderOrganizationCreateRequest } from "../models/request/provider/providerOrganizationCreateRequest";
|
|
||||||
import { ProviderSetupRequest } from "../models/request/provider/providerSetupRequest";
|
|
||||||
import { ProviderUpdateRequest } from "../models/request/provider/providerUpdateRequest";
|
|
||||||
import { ProviderUserAcceptRequest } from "../models/request/provider/providerUserAcceptRequest";
|
|
||||||
import { ProviderUserBulkConfirmRequest } from "../models/request/provider/providerUserBulkConfirmRequest";
|
|
||||||
import { ProviderUserBulkRequest } from "../models/request/provider/providerUserBulkRequest";
|
|
||||||
import { ProviderUserConfirmRequest } from "../models/request/provider/providerUserConfirmRequest";
|
|
||||||
import { ProviderUserInviteRequest } from "../models/request/provider/providerUserInviteRequest";
|
|
||||||
import { ProviderUserUpdateRequest } from "../models/request/provider/providerUserUpdateRequest";
|
|
||||||
import { RegisterRequest } from "../models/request/registerRequest";
|
|
||||||
import { SeatRequest } from "../models/request/seatRequest";
|
|
||||||
import { SecretVerificationRequest } from "../models/request/secretVerificationRequest";
|
|
||||||
import { SelectionReadOnlyRequest } from "../models/request/selectionReadOnlyRequest";
|
|
||||||
import { SendAccessRequest } from "../models/request/sendAccessRequest";
|
|
||||||
import { SendRequest } from "../models/request/sendRequest";
|
|
||||||
import { SetPasswordRequest } from "../models/request/setPasswordRequest";
|
|
||||||
import { StorageRequest } from "../models/request/storageRequest";
|
|
||||||
import { TaxInfoUpdateRequest } from "../models/request/taxInfoUpdateRequest";
|
|
||||||
import { TwoFactorEmailRequest } from "../models/request/twoFactorEmailRequest";
|
|
||||||
import { TwoFactorProviderRequest } from "../models/request/twoFactorProviderRequest";
|
|
||||||
import { TwoFactorRecoveryRequest } from "../models/request/twoFactorRecoveryRequest";
|
|
||||||
import { UpdateDomainsRequest } from "../models/request/updateDomainsRequest";
|
|
||||||
import { UpdateKeyRequest } from "../models/request/updateKeyRequest";
|
|
||||||
import { UpdateProfileRequest } from "../models/request/updateProfileRequest";
|
|
||||||
import { UpdateTempPasswordRequest } from "../models/request/updateTempPasswordRequest";
|
|
||||||
import { UpdateTwoFactorAuthenticatorRequest } from "../models/request/updateTwoFactorAuthenticatorRequest";
|
|
||||||
import { UpdateTwoFactorDuoRequest } from "../models/request/updateTwoFactorDuoRequest";
|
|
||||||
import { UpdateTwoFactorEmailRequest } from "../models/request/updateTwoFactorEmailRequest";
|
|
||||||
import { UpdateTwoFactorWebAuthnDeleteRequest } from "../models/request/updateTwoFactorWebAuthnDeleteRequest";
|
|
||||||
import { UpdateTwoFactorWebAuthnRequest } from "../models/request/updateTwoFactorWebAuthnRequest";
|
|
||||||
import { UpdateTwoFactorYubioOtpRequest } from "../models/request/updateTwoFactorYubioOtpRequest";
|
|
||||||
import { VerifyBankRequest } from "../models/request/verifyBankRequest";
|
|
||||||
import { VerifyDeleteRecoverRequest } from "../models/request/verifyDeleteRecoverRequest";
|
|
||||||
import { VerifyEmailRequest } from "../models/request/verifyEmailRequest";
|
|
||||||
import { ApiKeyResponse } from "../models/response/apiKeyResponse";
|
|
||||||
import { AttachmentResponse } from "../models/response/attachmentResponse";
|
|
||||||
import { AttachmentUploadDataResponse } from "../models/response/attachmentUploadDataResponse";
|
|
||||||
import { BillingResponse } from "../models/response/billingResponse";
|
|
||||||
import { BreachAccountResponse } from "../models/response/breachAccountResponse";
|
|
||||||
import { CipherResponse } from "../models/response/cipherResponse";
|
|
||||||
import {
|
|
||||||
CollectionGroupDetailsResponse,
|
|
||||||
CollectionResponse,
|
|
||||||
} from "../models/response/collectionResponse";
|
|
||||||
import { DomainsResponse } from "../models/response/domainsResponse";
|
|
||||||
import {
|
|
||||||
EmergencyAccessGranteeDetailsResponse,
|
|
||||||
EmergencyAccessGrantorDetailsResponse,
|
|
||||||
EmergencyAccessTakeoverResponse,
|
|
||||||
EmergencyAccessViewResponse,
|
|
||||||
} from "../models/response/emergencyAccessResponse";
|
|
||||||
import { EventResponse } from "../models/response/eventResponse";
|
|
||||||
import { FolderResponse } from "../models/response/folderResponse";
|
|
||||||
import { GroupDetailsResponse, GroupResponse } from "../models/response/groupResponse";
|
|
||||||
import { IdentityCaptchaResponse } from "../models/response/identityCaptchaResponse";
|
import { IdentityCaptchaResponse } from "../models/response/identityCaptchaResponse";
|
||||||
import { IdentityTokenResponse } from "../models/response/identityTokenResponse";
|
import { IdentityTokenResponse } from "../models/response/identityTokenResponse";
|
||||||
import { IdentityTwoFactorResponse } from "../models/response/identityTwoFactorResponse";
|
import { IdentityTwoFactorResponse } from "../models/response/identityTwoFactorResponse";
|
||||||
import { KeyConnectorUserKeyResponse } from "../models/response/keyConnectorUserKeyResponse";
|
|
||||||
import { ListResponse } from "../models/response/listResponse";
|
|
||||||
import { OrganizationSsoResponse } from "../models/response/organization/organizationSsoResponse";
|
|
||||||
import { OrganizationAutoEnrollStatusResponse } from "../models/response/organizationAutoEnrollStatusResponse";
|
|
||||||
import { OrganizationKeysResponse } from "../models/response/organizationKeysResponse";
|
|
||||||
import { OrganizationResponse } from "../models/response/organizationResponse";
|
|
||||||
import { OrganizationSubscriptionResponse } from "../models/response/organizationSubscriptionResponse";
|
|
||||||
import { OrganizationUserBulkPublicKeyResponse } from "../models/response/organizationUserBulkPublicKeyResponse";
|
|
||||||
import { OrganizationUserBulkResponse } from "../models/response/organizationUserBulkResponse";
|
|
||||||
import {
|
|
||||||
OrganizationUserDetailsResponse,
|
|
||||||
OrganizationUserResetPasswordDetailsReponse,
|
|
||||||
OrganizationUserUserDetailsResponse,
|
|
||||||
} from "../models/response/organizationUserResponse";
|
|
||||||
import { PaymentResponse } from "../models/response/paymentResponse";
|
|
||||||
import { PlanResponse } from "../models/response/planResponse";
|
|
||||||
import { PolicyResponse } from "../models/response/policyResponse";
|
|
||||||
import { PreloginResponse } from "../models/response/preloginResponse";
|
|
||||||
import { ProfileResponse } from "../models/response/profileResponse";
|
|
||||||
import {
|
|
||||||
ProviderOrganizationOrganizationDetailsResponse,
|
|
||||||
ProviderOrganizationResponse,
|
|
||||||
} from "../models/response/provider/providerOrganizationResponse";
|
|
||||||
import { ProviderResponse } from "../models/response/provider/providerResponse";
|
|
||||||
import { ProviderUserBulkPublicKeyResponse } from "../models/response/provider/providerUserBulkPublicKeyResponse";
|
|
||||||
import { ProviderUserBulkResponse } from "../models/response/provider/providerUserBulkResponse";
|
|
||||||
import {
|
|
||||||
ProviderUserResponse,
|
|
||||||
ProviderUserUserDetailsResponse,
|
|
||||||
} from "../models/response/provider/providerUserResponse";
|
|
||||||
import { SelectionReadOnlyResponse } from "../models/response/selectionReadOnlyResponse";
|
|
||||||
import { SendAccessResponse } from "../models/response/sendAccessResponse";
|
|
||||||
import { SendFileDownloadDataResponse } from "../models/response/sendFileDownloadDataResponse";
|
|
||||||
import { SendFileUploadDataResponse } from "../models/response/sendFileUploadDataResponse";
|
|
||||||
import { SendResponse } from "../models/response/sendResponse";
|
|
||||||
import { SubscriptionResponse } from "../models/response/subscriptionResponse";
|
|
||||||
import { SyncResponse } from "../models/response/syncResponse";
|
|
||||||
import { TaxInfoResponse } from "../models/response/taxInfoResponse";
|
|
||||||
import { TaxRateResponse } from "../models/response/taxRateResponse";
|
|
||||||
import { TwoFactorAuthenticatorResponse } from "../models/response/twoFactorAuthenticatorResponse";
|
|
||||||
import { TwoFactorDuoResponse } from "../models/response/twoFactorDuoResponse";
|
|
||||||
import { TwoFactorEmailResponse } from "../models/response/twoFactorEmailResponse";
|
|
||||||
import { TwoFactorProviderResponse } from "../models/response/twoFactorProviderResponse";
|
|
||||||
import { TwoFactorRecoverResponse } from "../models/response/twoFactorRescoverResponse";
|
|
||||||
import {
|
|
||||||
ChallengeResponse,
|
|
||||||
TwoFactorWebAuthnResponse,
|
|
||||||
} from "../models/response/twoFactorWebAuthnResponse";
|
|
||||||
import { TwoFactorYubiKeyResponse } from "../models/response/twoFactorYubiKeyResponse";
|
|
||||||
import { UserKeyResponse } from "../models/response/userKeyResponse";
|
|
||||||
import { SendAccessView } from "../models/view/sendAccessView";
|
|
||||||
|
|
||||||
export abstract class ApiService {
|
export abstract class ApiService {
|
||||||
postIdentityToken: (
|
postIdentityToken: (
|
||||||
request: PasswordTokenRequest | SsoTokenRequest | ApiTokenRequest
|
request: PasswordTokenRequest | SsoTokenRequest | ApiTokenRequest,
|
||||||
) => Promise<IdentityTokenResponse | IdentityTwoFactorResponse | IdentityCaptchaResponse>;
|
) => Promise<IdentityTokenResponse | IdentityTwoFactorResponse | IdentityCaptchaResponse>;
|
||||||
refreshIdentityToken: () => Promise<any>;
|
|
||||||
|
|
||||||
getProfile: () => Promise<ProfileResponse>;
|
|
||||||
getUserBilling: () => Promise<BillingResponse>;
|
|
||||||
getUserSubscription: () => Promise<SubscriptionResponse>;
|
|
||||||
getTaxInfo: () => Promise<TaxInfoResponse>;
|
|
||||||
putProfile: (request: UpdateProfileRequest) => Promise<ProfileResponse>;
|
|
||||||
putTaxInfo: (request: TaxInfoUpdateRequest) => Promise<any>;
|
|
||||||
postPrelogin: (request: PreloginRequest) => Promise<PreloginResponse>;
|
|
||||||
postEmailToken: (request: EmailTokenRequest) => Promise<any>;
|
|
||||||
postEmail: (request: EmailRequest) => Promise<any>;
|
|
||||||
postPassword: (request: PasswordRequest) => Promise<any>;
|
|
||||||
setPassword: (request: SetPasswordRequest) => Promise<any>;
|
|
||||||
postSetKeyConnectorKey: (request: SetKeyConnectorKeyRequest) => Promise<any>;
|
|
||||||
postSecurityStamp: (request: SecretVerificationRequest) => Promise<any>;
|
|
||||||
deleteAccount: (request: SecretVerificationRequest) => Promise<any>;
|
|
||||||
getAccountRevisionDate: () => Promise<number>;
|
|
||||||
postPasswordHint: (request: PasswordHintRequest) => Promise<any>;
|
|
||||||
postRegister: (request: RegisterRequest) => Promise<any>;
|
|
||||||
postPremium: (data: FormData) => Promise<PaymentResponse>;
|
|
||||||
postIapCheck: (request: IapCheckRequest) => Promise<any>;
|
|
||||||
postReinstatePremium: () => Promise<any>;
|
|
||||||
postCancelPremium: () => Promise<any>;
|
|
||||||
postAccountStorage: (request: StorageRequest) => Promise<PaymentResponse>;
|
|
||||||
postAccountPayment: (request: PaymentRequest) => Promise<any>;
|
|
||||||
postAccountLicense: (data: FormData) => Promise<any>;
|
|
||||||
postAccountKey: (request: UpdateKeyRequest) => Promise<any>;
|
|
||||||
postAccountKeys: (request: KeysRequest) => Promise<any>;
|
|
||||||
postAccountVerifyEmail: () => Promise<any>;
|
|
||||||
postAccountVerifyEmailToken: (request: VerifyEmailRequest) => Promise<any>;
|
|
||||||
postAccountVerifyPassword: (request: SecretVerificationRequest) => Promise<any>;
|
|
||||||
postAccountRecoverDelete: (request: DeleteRecoverRequest) => Promise<any>;
|
|
||||||
postAccountRecoverDeleteToken: (request: VerifyDeleteRecoverRequest) => Promise<any>;
|
|
||||||
postAccountKdf: (request: KdfRequest) => Promise<any>;
|
|
||||||
postUserApiKey: (id: string, request: SecretVerificationRequest) => Promise<ApiKeyResponse>;
|
|
||||||
postUserRotateApiKey: (id: string, request: SecretVerificationRequest) => Promise<ApiKeyResponse>;
|
|
||||||
putUpdateTempPassword: (request: UpdateTempPasswordRequest) => Promise<any>;
|
|
||||||
postAccountRequestOTP: () => Promise<void>;
|
|
||||||
postAccountVerifyOTP: (request: VerifyOTPRequest) => Promise<void>;
|
|
||||||
postConvertToKeyConnector: () => Promise<void>;
|
|
||||||
|
|
||||||
getFolder: (id: string) => Promise<FolderResponse>;
|
|
||||||
postFolder: (request: FolderRequest) => Promise<FolderResponse>;
|
|
||||||
putFolder: (id: string, request: FolderRequest) => Promise<FolderResponse>;
|
|
||||||
deleteFolder: (id: string) => Promise<any>;
|
|
||||||
|
|
||||||
getSend: (id: string) => Promise<SendResponse>;
|
|
||||||
postSendAccess: (
|
|
||||||
id: string,
|
|
||||||
request: SendAccessRequest,
|
|
||||||
apiUrl?: string
|
|
||||||
) => Promise<SendAccessResponse>;
|
|
||||||
getSends: () => Promise<ListResponse<SendResponse>>;
|
|
||||||
postSend: (request: SendRequest) => Promise<SendResponse>;
|
|
||||||
postFileTypeSend: (request: SendRequest) => Promise<SendFileUploadDataResponse>;
|
|
||||||
postSendFile: (sendId: string, fileId: string, data: FormData) => Promise<any>;
|
|
||||||
/**
|
|
||||||
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
|
|
||||||
* This method still exists for backward compatibility with old server versions.
|
|
||||||
*/
|
|
||||||
postSendFileLegacy: (data: FormData) => Promise<SendResponse>;
|
|
||||||
putSend: (id: string, request: SendRequest) => Promise<SendResponse>;
|
|
||||||
putSendRemovePassword: (id: string) => Promise<SendResponse>;
|
|
||||||
deleteSend: (id: string) => Promise<any>;
|
|
||||||
getSendFileDownloadData: (
|
|
||||||
send: SendAccessView,
|
|
||||||
request: SendAccessRequest,
|
|
||||||
apiUrl?: string
|
|
||||||
) => Promise<SendFileDownloadDataResponse>;
|
|
||||||
renewSendFileUploadUrl: (sendId: string, fileId: string) => Promise<SendFileUploadDataResponse>;
|
|
||||||
|
|
||||||
getCipher: (id: string) => Promise<CipherResponse>;
|
|
||||||
getCipherAdmin: (id: string) => Promise<CipherResponse>;
|
|
||||||
getAttachmentData: (
|
|
||||||
cipherId: string,
|
|
||||||
attachmentId: string,
|
|
||||||
emergencyAccessId?: string
|
|
||||||
) => Promise<AttachmentResponse>;
|
|
||||||
getCiphersOrganization: (organizationId: string) => Promise<ListResponse<CipherResponse>>;
|
|
||||||
postCipher: (request: CipherRequest) => Promise<CipherResponse>;
|
|
||||||
postCipherCreate: (request: CipherCreateRequest) => Promise<CipherResponse>;
|
|
||||||
postCipherAdmin: (request: CipherCreateRequest) => Promise<CipherResponse>;
|
|
||||||
putCipher: (id: string, request: CipherRequest) => Promise<CipherResponse>;
|
|
||||||
putCipherAdmin: (id: string, request: CipherRequest) => Promise<CipherResponse>;
|
|
||||||
deleteCipher: (id: string) => Promise<any>;
|
|
||||||
deleteCipherAdmin: (id: string) => Promise<any>;
|
|
||||||
deleteManyCiphers: (request: CipherBulkDeleteRequest) => Promise<any>;
|
|
||||||
deleteManyCiphersAdmin: (request: CipherBulkDeleteRequest) => Promise<any>;
|
|
||||||
putMoveCiphers: (request: CipherBulkMoveRequest) => Promise<any>;
|
|
||||||
putShareCipher: (id: string, request: CipherShareRequest) => Promise<CipherResponse>;
|
|
||||||
putShareCiphers: (request: CipherBulkShareRequest) => Promise<any>;
|
|
||||||
putCipherCollections: (id: string, request: CipherCollectionsRequest) => Promise<any>;
|
|
||||||
putCipherCollectionsAdmin: (id: string, request: CipherCollectionsRequest) => Promise<any>;
|
|
||||||
postPurgeCiphers: (request: SecretVerificationRequest, organizationId?: string) => Promise<any>;
|
|
||||||
postImportCiphers: (request: ImportCiphersRequest) => Promise<any>;
|
|
||||||
postImportOrganizationCiphers: (
|
|
||||||
organizationId: string,
|
|
||||||
request: ImportOrganizationCiphersRequest
|
|
||||||
) => Promise<any>;
|
|
||||||
putDeleteCipher: (id: string) => Promise<any>;
|
|
||||||
putDeleteCipherAdmin: (id: string) => Promise<any>;
|
|
||||||
putDeleteManyCiphers: (request: CipherBulkDeleteRequest) => Promise<any>;
|
|
||||||
putDeleteManyCiphersAdmin: (request: CipherBulkDeleteRequest) => Promise<any>;
|
|
||||||
putRestoreCipher: (id: string) => Promise<CipherResponse>;
|
|
||||||
putRestoreCipherAdmin: (id: string) => Promise<CipherResponse>;
|
|
||||||
putRestoreManyCiphers: (
|
|
||||||
request: CipherBulkRestoreRequest
|
|
||||||
) => Promise<ListResponse<CipherResponse>>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
|
|
||||||
* This method still exists for backward compatibility with old server versions.
|
|
||||||
*/
|
|
||||||
postCipherAttachmentLegacy: (id: string, data: FormData) => Promise<CipherResponse>;
|
|
||||||
/**
|
|
||||||
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
|
|
||||||
* This method still exists for backward compatibility with old server versions.
|
|
||||||
*/
|
|
||||||
postCipherAttachmentAdminLegacy: (id: string, data: FormData) => Promise<CipherResponse>;
|
|
||||||
postCipherAttachment: (
|
|
||||||
id: string,
|
|
||||||
request: AttachmentRequest
|
|
||||||
) => Promise<AttachmentUploadDataResponse>;
|
|
||||||
deleteCipherAttachment: (id: string, attachmentId: string) => Promise<any>;
|
|
||||||
deleteCipherAttachmentAdmin: (id: string, attachmentId: string) => Promise<any>;
|
|
||||||
postShareCipherAttachment: (
|
|
||||||
id: string,
|
|
||||||
attachmentId: string,
|
|
||||||
data: FormData,
|
|
||||||
organizationId: string
|
|
||||||
) => Promise<any>;
|
|
||||||
renewAttachmentUploadUrl: (
|
|
||||||
id: string,
|
|
||||||
attachmentId: string
|
|
||||||
) => Promise<AttachmentUploadDataResponse>;
|
|
||||||
postAttachmentFile: (id: string, attachmentId: string, data: FormData) => Promise<any>;
|
|
||||||
|
|
||||||
getCollectionDetails: (
|
|
||||||
organizationId: string,
|
|
||||||
id: string
|
|
||||||
) => Promise<CollectionGroupDetailsResponse>;
|
|
||||||
getUserCollections: () => Promise<ListResponse<CollectionResponse>>;
|
|
||||||
getCollections: (organizationId: string) => Promise<ListResponse<CollectionResponse>>;
|
|
||||||
getCollectionUsers: (organizationId: string, id: string) => Promise<SelectionReadOnlyResponse[]>;
|
|
||||||
postCollection: (
|
|
||||||
organizationId: string,
|
|
||||||
request: CollectionRequest
|
|
||||||
) => Promise<CollectionResponse>;
|
|
||||||
putCollectionUsers: (
|
|
||||||
organizationId: string,
|
|
||||||
id: string,
|
|
||||||
request: SelectionReadOnlyRequest[]
|
|
||||||
) => Promise<any>;
|
|
||||||
putCollection: (
|
|
||||||
organizationId: string,
|
|
||||||
id: string,
|
|
||||||
request: CollectionRequest
|
|
||||||
) => Promise<CollectionResponse>;
|
|
||||||
deleteCollection: (organizationId: string, id: string) => Promise<any>;
|
|
||||||
deleteCollectionUser: (
|
|
||||||
organizationId: string,
|
|
||||||
id: string,
|
|
||||||
organizationUserId: string
|
|
||||||
) => Promise<any>;
|
|
||||||
|
|
||||||
getGroupDetails: (organizationId: string, id: string) => Promise<GroupDetailsResponse>;
|
|
||||||
getGroups: (organizationId: string) => Promise<ListResponse<GroupResponse>>;
|
|
||||||
getGroupUsers: (organizationId: string, id: string) => Promise<string[]>;
|
|
||||||
postGroup: (organizationId: string, request: GroupRequest) => Promise<GroupResponse>;
|
|
||||||
putGroup: (organizationId: string, id: string, request: GroupRequest) => Promise<GroupResponse>;
|
|
||||||
putGroupUsers: (organizationId: string, id: string, request: string[]) => Promise<any>;
|
|
||||||
deleteGroup: (organizationId: string, id: string) => Promise<any>;
|
|
||||||
deleteGroupUser: (organizationId: string, id: string, organizationUserId: string) => Promise<any>;
|
|
||||||
|
|
||||||
getPolicy: (organizationId: string, type: PolicyType) => Promise<PolicyResponse>;
|
|
||||||
getPolicies: (organizationId: string) => Promise<ListResponse<PolicyResponse>>;
|
|
||||||
getPoliciesByToken: (
|
|
||||||
organizationId: string,
|
|
||||||
token: string,
|
|
||||||
email: string,
|
|
||||||
organizationUserId: string
|
|
||||||
) => Promise<ListResponse<PolicyResponse>>;
|
|
||||||
getPoliciesByInvitedUser: (
|
|
||||||
organizationId: string,
|
|
||||||
userId: string
|
|
||||||
) => Promise<ListResponse<PolicyResponse>>;
|
|
||||||
putPolicy: (
|
|
||||||
organizationId: string,
|
|
||||||
type: PolicyType,
|
|
||||||
request: PolicyRequest
|
|
||||||
) => Promise<PolicyResponse>;
|
|
||||||
|
|
||||||
getOrganizationUser: (
|
|
||||||
organizationId: string,
|
|
||||||
id: string
|
|
||||||
) => Promise<OrganizationUserDetailsResponse>;
|
|
||||||
getOrganizationUserGroups: (organizationId: string, id: string) => Promise<string[]>;
|
|
||||||
getOrganizationUsers: (
|
|
||||||
organizationId: string
|
|
||||||
) => Promise<ListResponse<OrganizationUserUserDetailsResponse>>;
|
|
||||||
getOrganizationUserResetPasswordDetails: (
|
|
||||||
organizationId: string,
|
|
||||||
id: string
|
|
||||||
) => Promise<OrganizationUserResetPasswordDetailsReponse>;
|
|
||||||
postOrganizationUserInvite: (
|
|
||||||
organizationId: string,
|
|
||||||
request: OrganizationUserInviteRequest
|
|
||||||
) => Promise<any>;
|
|
||||||
postOrganizationUserReinvite: (organizationId: string, id: string) => Promise<any>;
|
|
||||||
postManyOrganizationUserReinvite: (
|
|
||||||
organizationId: string,
|
|
||||||
request: OrganizationUserBulkRequest
|
|
||||||
) => Promise<ListResponse<OrganizationUserBulkResponse>>;
|
|
||||||
postOrganizationUserAccept: (
|
|
||||||
organizationId: string,
|
|
||||||
id: string,
|
|
||||||
request: OrganizationUserAcceptRequest
|
|
||||||
) => Promise<any>;
|
|
||||||
postOrganizationUserConfirm: (
|
|
||||||
organizationId: string,
|
|
||||||
id: string,
|
|
||||||
request: OrganizationUserConfirmRequest
|
|
||||||
) => Promise<any>;
|
|
||||||
postOrganizationUsersPublicKey: (
|
|
||||||
organizationId: string,
|
|
||||||
request: OrganizationUserBulkRequest
|
|
||||||
) => Promise<ListResponse<OrganizationUserBulkPublicKeyResponse>>;
|
|
||||||
postOrganizationUserBulkConfirm: (
|
|
||||||
organizationId: string,
|
|
||||||
request: OrganizationUserBulkConfirmRequest
|
|
||||||
) => Promise<ListResponse<OrganizationUserBulkResponse>>;
|
|
||||||
|
|
||||||
putOrganizationUser: (
|
|
||||||
organizationId: string,
|
|
||||||
id: string,
|
|
||||||
request: OrganizationUserUpdateRequest
|
|
||||||
) => Promise<any>;
|
|
||||||
putOrganizationUserGroups: (
|
|
||||||
organizationId: string,
|
|
||||||
id: string,
|
|
||||||
request: OrganizationUserUpdateGroupsRequest
|
|
||||||
) => Promise<any>;
|
|
||||||
putOrganizationUserResetPasswordEnrollment: (
|
|
||||||
organizationId: string,
|
|
||||||
userId: string,
|
|
||||||
request: OrganizationUserResetPasswordEnrollmentRequest
|
|
||||||
) => Promise<any>;
|
|
||||||
putOrganizationUserResetPassword: (
|
|
||||||
organizationId: string,
|
|
||||||
id: string,
|
|
||||||
request: OrganizationUserResetPasswordRequest
|
|
||||||
) => Promise<any>;
|
|
||||||
deleteOrganizationUser: (organizationId: string, id: string) => Promise<any>;
|
|
||||||
deleteManyOrganizationUsers: (
|
|
||||||
organizationId: string,
|
|
||||||
request: OrganizationUserBulkRequest
|
|
||||||
) => Promise<ListResponse<OrganizationUserBulkResponse>>;
|
|
||||||
|
|
||||||
getSync: () => Promise<SyncResponse>;
|
|
||||||
postImportDirectory: (organizationId: string, request: ImportDirectoryRequest) => Promise<any>;
|
|
||||||
postPublicImportDirectory: (request: OrganizationImportRequest) => Promise<any>;
|
postPublicImportDirectory: (request: OrganizationImportRequest) => Promise<any>;
|
||||||
|
|
||||||
getSettingsDomains: () => Promise<DomainsResponse>;
|
|
||||||
putSettingsDomains: (request: UpdateDomainsRequest) => Promise<DomainsResponse>;
|
|
||||||
|
|
||||||
getTwoFactorProviders: () => Promise<ListResponse<TwoFactorProviderResponse>>;
|
|
||||||
getTwoFactorOrganizationProviders: (
|
|
||||||
organizationId: string
|
|
||||||
) => Promise<ListResponse<TwoFactorProviderResponse>>;
|
|
||||||
getTwoFactorAuthenticator: (
|
|
||||||
request: SecretVerificationRequest
|
|
||||||
) => Promise<TwoFactorAuthenticatorResponse>;
|
|
||||||
getTwoFactorEmail: (request: SecretVerificationRequest) => Promise<TwoFactorEmailResponse>;
|
|
||||||
getTwoFactorDuo: (request: SecretVerificationRequest) => Promise<TwoFactorDuoResponse>;
|
|
||||||
getTwoFactorOrganizationDuo: (
|
|
||||||
organizationId: string,
|
|
||||||
request: SecretVerificationRequest
|
|
||||||
) => Promise<TwoFactorDuoResponse>;
|
|
||||||
getTwoFactorYubiKey: (request: SecretVerificationRequest) => Promise<TwoFactorYubiKeyResponse>;
|
|
||||||
getTwoFactorWebAuthn: (request: SecretVerificationRequest) => Promise<TwoFactorWebAuthnResponse>;
|
|
||||||
getTwoFactorWebAuthnChallenge: (request: SecretVerificationRequest) => Promise<ChallengeResponse>;
|
|
||||||
getTwoFactorRecover: (request: SecretVerificationRequest) => Promise<TwoFactorRecoverResponse>;
|
|
||||||
putTwoFactorAuthenticator: (
|
|
||||||
request: UpdateTwoFactorAuthenticatorRequest
|
|
||||||
) => Promise<TwoFactorAuthenticatorResponse>;
|
|
||||||
putTwoFactorEmail: (request: UpdateTwoFactorEmailRequest) => Promise<TwoFactorEmailResponse>;
|
|
||||||
putTwoFactorDuo: (request: UpdateTwoFactorDuoRequest) => Promise<TwoFactorDuoResponse>;
|
|
||||||
putTwoFactorOrganizationDuo: (
|
|
||||||
organizationId: string,
|
|
||||||
request: UpdateTwoFactorDuoRequest
|
|
||||||
) => Promise<TwoFactorDuoResponse>;
|
|
||||||
putTwoFactorYubiKey: (
|
|
||||||
request: UpdateTwoFactorYubioOtpRequest
|
|
||||||
) => Promise<TwoFactorYubiKeyResponse>;
|
|
||||||
putTwoFactorWebAuthn: (
|
|
||||||
request: UpdateTwoFactorWebAuthnRequest
|
|
||||||
) => Promise<TwoFactorWebAuthnResponse>;
|
|
||||||
deleteTwoFactorWebAuthn: (
|
|
||||||
request: UpdateTwoFactorWebAuthnDeleteRequest
|
|
||||||
) => Promise<TwoFactorWebAuthnResponse>;
|
|
||||||
putTwoFactorDisable: (request: TwoFactorProviderRequest) => Promise<TwoFactorProviderResponse>;
|
|
||||||
putTwoFactorOrganizationDisable: (
|
|
||||||
organizationId: string,
|
|
||||||
request: TwoFactorProviderRequest
|
|
||||||
) => Promise<TwoFactorProviderResponse>;
|
|
||||||
postTwoFactorRecover: (request: TwoFactorRecoveryRequest) => Promise<any>;
|
|
||||||
postTwoFactorEmailSetup: (request: TwoFactorEmailRequest) => Promise<any>;
|
|
||||||
postTwoFactorEmail: (request: TwoFactorEmailRequest) => Promise<any>;
|
|
||||||
|
|
||||||
getEmergencyAccessTrusted: () => Promise<ListResponse<EmergencyAccessGranteeDetailsResponse>>;
|
|
||||||
getEmergencyAccessGranted: () => Promise<ListResponse<EmergencyAccessGrantorDetailsResponse>>;
|
|
||||||
getEmergencyAccess: (id: string) => Promise<EmergencyAccessGranteeDetailsResponse>;
|
|
||||||
getEmergencyGrantorPolicies: (id: string) => Promise<ListResponse<PolicyResponse>>;
|
|
||||||
putEmergencyAccess: (id: string, request: EmergencyAccessUpdateRequest) => Promise<any>;
|
|
||||||
deleteEmergencyAccess: (id: string) => Promise<any>;
|
|
||||||
postEmergencyAccessInvite: (request: EmergencyAccessInviteRequest) => Promise<any>;
|
|
||||||
postEmergencyAccessReinvite: (id: string) => Promise<any>;
|
|
||||||
postEmergencyAccessAccept: (id: string, request: EmergencyAccessAcceptRequest) => Promise<any>;
|
|
||||||
postEmergencyAccessConfirm: (id: string, request: EmergencyAccessConfirmRequest) => Promise<any>;
|
|
||||||
postEmergencyAccessInitiate: (id: string) => Promise<any>;
|
|
||||||
postEmergencyAccessApprove: (id: string) => Promise<any>;
|
|
||||||
postEmergencyAccessReject: (id: string) => Promise<any>;
|
|
||||||
postEmergencyAccessTakeover: (id: string) => Promise<EmergencyAccessTakeoverResponse>;
|
|
||||||
postEmergencyAccessPassword: (
|
|
||||||
id: string,
|
|
||||||
request: EmergencyAccessPasswordRequest
|
|
||||||
) => Promise<any>;
|
|
||||||
postEmergencyAccessView: (id: string) => Promise<EmergencyAccessViewResponse>;
|
|
||||||
|
|
||||||
getOrganization: (id: string) => Promise<OrganizationResponse>;
|
|
||||||
getOrganizationBilling: (id: string) => Promise<BillingResponse>;
|
|
||||||
getOrganizationSubscription: (id: string) => Promise<OrganizationSubscriptionResponse>;
|
|
||||||
getOrganizationLicense: (id: string, installationId: string) => Promise<any>;
|
|
||||||
getOrganizationTaxInfo: (id: string) => Promise<TaxInfoResponse>;
|
|
||||||
getOrganizationAutoEnrollStatus: (
|
|
||||||
identifier: string
|
|
||||||
) => Promise<OrganizationAutoEnrollStatusResponse>;
|
|
||||||
getOrganizationSso: (id: string) => Promise<OrganizationSsoResponse>;
|
|
||||||
postOrganization: (request: OrganizationCreateRequest) => Promise<OrganizationResponse>;
|
|
||||||
putOrganization: (
|
|
||||||
id: string,
|
|
||||||
request: OrganizationUpdateRequest
|
|
||||||
) => Promise<OrganizationResponse>;
|
|
||||||
putOrganizationTaxInfo: (id: string, request: OrganizationTaxInfoUpdateRequest) => Promise<any>;
|
|
||||||
postLeaveOrganization: (id: string) => Promise<any>;
|
|
||||||
postOrganizationLicense: (data: FormData) => Promise<OrganizationResponse>;
|
|
||||||
postOrganizationLicenseUpdate: (id: string, data: FormData) => Promise<any>;
|
|
||||||
postOrganizationApiKey: (
|
|
||||||
id: string,
|
|
||||||
request: SecretVerificationRequest
|
|
||||||
) => Promise<ApiKeyResponse>;
|
|
||||||
postOrganizationRotateApiKey: (
|
|
||||||
id: string,
|
|
||||||
request: SecretVerificationRequest
|
|
||||||
) => Promise<ApiKeyResponse>;
|
|
||||||
postOrganizationSso: (
|
|
||||||
id: string,
|
|
||||||
request: OrganizationSsoRequest
|
|
||||||
) => Promise<OrganizationSsoResponse>;
|
|
||||||
postOrganizationUpgrade: (
|
|
||||||
id: string,
|
|
||||||
request: OrganizationUpgradeRequest
|
|
||||||
) => Promise<PaymentResponse>;
|
|
||||||
postOrganizationUpdateSubscription: (
|
|
||||||
id: string,
|
|
||||||
request: OrganizationSubscriptionUpdateRequest
|
|
||||||
) => Promise<void>;
|
|
||||||
postOrganizationSeat: (id: string, request: SeatRequest) => Promise<PaymentResponse>;
|
|
||||||
postOrganizationStorage: (id: string, request: StorageRequest) => Promise<any>;
|
|
||||||
postOrganizationPayment: (id: string, request: PaymentRequest) => Promise<any>;
|
|
||||||
postOrganizationVerifyBank: (id: string, request: VerifyBankRequest) => Promise<any>;
|
|
||||||
postOrganizationCancel: (id: string) => Promise<any>;
|
|
||||||
postOrganizationReinstate: (id: string) => Promise<any>;
|
|
||||||
deleteOrganization: (id: string, request: SecretVerificationRequest) => Promise<any>;
|
|
||||||
getPlans: () => Promise<ListResponse<PlanResponse>>;
|
|
||||||
getTaxRates: () => Promise<ListResponse<TaxRateResponse>>;
|
|
||||||
getOrganizationKeys: (id: string) => Promise<OrganizationKeysResponse>;
|
|
||||||
postOrganizationKeys: (
|
|
||||||
id: string,
|
|
||||||
request: OrganizationKeysRequest
|
|
||||||
) => Promise<OrganizationKeysResponse>;
|
|
||||||
|
|
||||||
postProviderSetup: (id: string, request: ProviderSetupRequest) => Promise<ProviderResponse>;
|
|
||||||
getProvider: (id: string) => Promise<ProviderResponse>;
|
|
||||||
putProvider: (id: string, request: ProviderUpdateRequest) => Promise<ProviderResponse>;
|
|
||||||
|
|
||||||
getProviderUsers: (providerId: string) => Promise<ListResponse<ProviderUserUserDetailsResponse>>;
|
|
||||||
getProviderUser: (providerId: string, id: string) => Promise<ProviderUserResponse>;
|
|
||||||
postProviderUserInvite: (providerId: string, request: ProviderUserInviteRequest) => Promise<any>;
|
|
||||||
postProviderUserReinvite: (providerId: string, id: string) => Promise<any>;
|
|
||||||
postManyProviderUserReinvite: (
|
|
||||||
providerId: string,
|
|
||||||
request: ProviderUserBulkRequest
|
|
||||||
) => Promise<ListResponse<ProviderUserBulkResponse>>;
|
|
||||||
postProviderUserAccept: (
|
|
||||||
providerId: string,
|
|
||||||
id: string,
|
|
||||||
request: ProviderUserAcceptRequest
|
|
||||||
) => Promise<any>;
|
|
||||||
postProviderUserConfirm: (
|
|
||||||
providerId: string,
|
|
||||||
id: string,
|
|
||||||
request: ProviderUserConfirmRequest
|
|
||||||
) => Promise<any>;
|
|
||||||
postProviderUsersPublicKey: (
|
|
||||||
providerId: string,
|
|
||||||
request: ProviderUserBulkRequest
|
|
||||||
) => Promise<ListResponse<ProviderUserBulkPublicKeyResponse>>;
|
|
||||||
postProviderUserBulkConfirm: (
|
|
||||||
providerId: string,
|
|
||||||
request: ProviderUserBulkConfirmRequest
|
|
||||||
) => Promise<ListResponse<ProviderUserBulkResponse>>;
|
|
||||||
putProviderUser: (
|
|
||||||
providerId: string,
|
|
||||||
id: string,
|
|
||||||
request: ProviderUserUpdateRequest
|
|
||||||
) => Promise<any>;
|
|
||||||
deleteProviderUser: (organizationId: string, id: string) => Promise<any>;
|
|
||||||
deleteManyProviderUsers: (
|
|
||||||
providerId: string,
|
|
||||||
request: ProviderUserBulkRequest
|
|
||||||
) => Promise<ListResponse<ProviderUserBulkResponse>>;
|
|
||||||
getProviderClients: (
|
|
||||||
providerId: string
|
|
||||||
) => Promise<ListResponse<ProviderOrganizationOrganizationDetailsResponse>>;
|
|
||||||
postProviderAddOrganization: (
|
|
||||||
providerId: string,
|
|
||||||
request: ProviderAddOrganizationRequest
|
|
||||||
) => Promise<any>;
|
|
||||||
postProviderCreateOrganization: (
|
|
||||||
providerId: string,
|
|
||||||
request: ProviderOrganizationCreateRequest
|
|
||||||
) => Promise<ProviderOrganizationResponse>;
|
|
||||||
deleteProviderOrganization: (providerId: string, organizationId: string) => Promise<any>;
|
|
||||||
|
|
||||||
getEvents: (start: string, end: string, token: string) => Promise<ListResponse<EventResponse>>;
|
|
||||||
getEventsCipher: (
|
|
||||||
id: string,
|
|
||||||
start: string,
|
|
||||||
end: string,
|
|
||||||
token: string
|
|
||||||
) => Promise<ListResponse<EventResponse>>;
|
|
||||||
getEventsOrganization: (
|
|
||||||
id: string,
|
|
||||||
start: string,
|
|
||||||
end: string,
|
|
||||||
token: string
|
|
||||||
) => Promise<ListResponse<EventResponse>>;
|
|
||||||
getEventsOrganizationUser: (
|
|
||||||
organizationId: string,
|
|
||||||
id: string,
|
|
||||||
start: string,
|
|
||||||
end: string,
|
|
||||||
token: string
|
|
||||||
) => Promise<ListResponse<EventResponse>>;
|
|
||||||
getEventsProvider: (
|
|
||||||
id: string,
|
|
||||||
start: string,
|
|
||||||
end: string,
|
|
||||||
token: string
|
|
||||||
) => Promise<ListResponse<EventResponse>>;
|
|
||||||
getEventsProviderUser: (
|
|
||||||
providerId: string,
|
|
||||||
id: string,
|
|
||||||
start: string,
|
|
||||||
end: string,
|
|
||||||
token: string
|
|
||||||
) => Promise<ListResponse<EventResponse>>;
|
|
||||||
postEventsCollect: (request: EventRequest[]) => Promise<any>;
|
|
||||||
|
|
||||||
deleteSsoUser: (organizationId: string) => Promise<any>;
|
|
||||||
getSsoUserIdentifier: () => Promise<string>;
|
|
||||||
|
|
||||||
getUserPublicKey: (id: string) => Promise<UserKeyResponse>;
|
|
||||||
|
|
||||||
getHibpBreach: (username: string) => Promise<BreachAccountResponse[]>;
|
|
||||||
|
|
||||||
postBitPayInvoice: (request: BitPayInvoiceRequest) => Promise<string>;
|
|
||||||
postSetupPayment: () => Promise<string>;
|
|
||||||
|
|
||||||
getActiveBearerToken: () => Promise<string>;
|
|
||||||
fetch: (request: Request) => Promise<Response>;
|
|
||||||
nativeFetch: (request: Request) => Promise<Response>;
|
|
||||||
|
|
||||||
preValidateSso: (identifier: string) => Promise<boolean>;
|
|
||||||
|
|
||||||
postCreateSponsorship: (
|
|
||||||
sponsorshipOrgId: string,
|
|
||||||
request: OrganizationSponsorshipCreateRequest
|
|
||||||
) => Promise<void>;
|
|
||||||
deleteRevokeSponsorship: (sponsoringOrganizationId: string) => Promise<void>;
|
|
||||||
deleteRemoveSponsorship: (sponsoringOrgId: string) => Promise<void>;
|
|
||||||
postPreValidateSponsorshipToken: (sponsorshipToken: string) => Promise<boolean>;
|
|
||||||
postRedeemSponsorship: (
|
|
||||||
sponsorshipToken: string,
|
|
||||||
request: OrganizationSponsorshipRedeemRequest
|
|
||||||
) => Promise<void>;
|
|
||||||
postResendSponsorshipOffer: (sponsoringOrgId: string) => Promise<void>;
|
|
||||||
|
|
||||||
getUserKeyFromKeyConnector: (keyConnectorUrl: string) => Promise<KeyConnectorUserKeyResponse>;
|
|
||||||
postUserKeyToKeyConnector: (
|
|
||||||
keyConnectorUrl: string,
|
|
||||||
request: KeyConnectorUserKeyRequest
|
|
||||||
) => Promise<void>;
|
|
||||||
getKeyConnectorAlive: (keyConnectorUrl: string) => Promise<void>;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
import { BreachAccountResponse } from "../models/response/breachAccountResponse";
|
|
||||||
|
|
||||||
export abstract class AuditService {
|
|
||||||
passwordLeaked: (password: string) => Promise<number>;
|
|
||||||
breachedAccounts: (username: string) => Promise<BreachAccountResponse[]>;
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { AuthResult } from "../models/domain/authResult";
|
|
||||||
import {
|
|
||||||
ApiLogInCredentials,
|
|
||||||
PasswordLogInCredentials,
|
|
||||||
SsoLogInCredentials,
|
|
||||||
} from "../models/domain/logInCredentials";
|
|
||||||
import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey";
|
|
||||||
import { TokenRequestTwoFactor } from "../models/request/identityToken/tokenRequestTwoFactor";
|
|
||||||
|
|
||||||
export abstract class AuthService {
|
|
||||||
masterPasswordHash: string;
|
|
||||||
email: string;
|
|
||||||
logIn: (
|
|
||||||
credentials: ApiLogInCredentials | PasswordLogInCredentials | SsoLogInCredentials
|
|
||||||
) => Promise<AuthResult>;
|
|
||||||
logInTwoFactor: (
|
|
||||||
twoFactor: TokenRequestTwoFactor,
|
|
||||||
captchaResponse: string
|
|
||||||
) => Promise<AuthResult>;
|
|
||||||
logOut: (callback: () => void) => void;
|
|
||||||
makePreloginKey: (masterPassword: string, email: string) => Promise<SymmetricCryptoKey>;
|
|
||||||
authingWithApiKey: () => boolean;
|
|
||||||
authingWithSso: () => boolean;
|
|
||||||
authingWithPassword: () => boolean;
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
import { CipherType } from "../enums/cipherType";
|
|
||||||
import { UriMatchType } from "../enums/uriMatchType";
|
|
||||||
import { CipherData } from "../models/data/cipherData";
|
|
||||||
import { Cipher } from "../models/domain/cipher";
|
|
||||||
import { Field } from "../models/domain/field";
|
|
||||||
import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey";
|
|
||||||
import { CipherView } from "../models/view/cipherView";
|
|
||||||
import { FieldView } from "../models/view/fieldView";
|
|
||||||
|
|
||||||
export abstract class CipherService {
|
|
||||||
clearCache: (userId?: string) => Promise<void>;
|
|
||||||
encrypt: (
|
|
||||||
model: CipherView,
|
|
||||||
key?: SymmetricCryptoKey,
|
|
||||||
originalCipher?: Cipher
|
|
||||||
) => Promise<Cipher>;
|
|
||||||
encryptFields: (fieldsModel: FieldView[], key: SymmetricCryptoKey) => Promise<Field[]>;
|
|
||||||
encryptField: (fieldModel: FieldView, key: SymmetricCryptoKey) => Promise<Field>;
|
|
||||||
get: (id: string) => Promise<Cipher>;
|
|
||||||
getAll: () => Promise<Cipher[]>;
|
|
||||||
getAllDecrypted: () => Promise<CipherView[]>;
|
|
||||||
getAllDecryptedForGrouping: (groupingId: string, folder?: boolean) => Promise<CipherView[]>;
|
|
||||||
getAllDecryptedForUrl: (
|
|
||||||
url: string,
|
|
||||||
includeOtherTypes?: CipherType[],
|
|
||||||
defaultMatch?: UriMatchType
|
|
||||||
) => Promise<CipherView[]>;
|
|
||||||
getAllFromApiForOrganization: (organizationId: string) => Promise<CipherView[]>;
|
|
||||||
getLastUsedForUrl: (url: string, autofillOnPageLoad: boolean) => Promise<CipherView>;
|
|
||||||
getLastLaunchedForUrl: (url: string, autofillOnPageLoad: boolean) => Promise<CipherView>;
|
|
||||||
getNextCipherForUrl: (url: string) => Promise<CipherView>;
|
|
||||||
updateLastUsedIndexForUrl: (url: string) => void;
|
|
||||||
updateLastUsedDate: (id: string) => Promise<void>;
|
|
||||||
updateLastLaunchedDate: (id: string) => Promise<void>;
|
|
||||||
saveNeverDomain: (domain: string) => Promise<void>;
|
|
||||||
saveWithServer: (cipher: Cipher) => Promise<any>;
|
|
||||||
shareWithServer: (
|
|
||||||
cipher: CipherView,
|
|
||||||
organizationId: string,
|
|
||||||
collectionIds: string[]
|
|
||||||
) => Promise<any>;
|
|
||||||
shareManyWithServer: (
|
|
||||||
ciphers: CipherView[],
|
|
||||||
organizationId: string,
|
|
||||||
collectionIds: string[]
|
|
||||||
) => Promise<any>;
|
|
||||||
saveAttachmentWithServer: (
|
|
||||||
cipher: Cipher,
|
|
||||||
unencryptedFile: any,
|
|
||||||
admin?: boolean
|
|
||||||
) => Promise<Cipher>;
|
|
||||||
saveAttachmentRawWithServer: (
|
|
||||||
cipher: Cipher,
|
|
||||||
filename: string,
|
|
||||||
data: ArrayBuffer,
|
|
||||||
admin?: boolean
|
|
||||||
) => Promise<Cipher>;
|
|
||||||
saveCollectionsWithServer: (cipher: Cipher) => Promise<any>;
|
|
||||||
upsert: (cipher: CipherData | CipherData[]) => Promise<any>;
|
|
||||||
replace: (ciphers: { [id: string]: CipherData }) => Promise<any>;
|
|
||||||
clear: (userId: string) => Promise<any>;
|
|
||||||
moveManyWithServer: (ids: string[], folderId: string) => Promise<any>;
|
|
||||||
delete: (id: string | string[]) => Promise<any>;
|
|
||||||
deleteWithServer: (id: string) => Promise<any>;
|
|
||||||
deleteManyWithServer: (ids: string[]) => Promise<any>;
|
|
||||||
deleteAttachment: (id: string, attachmentId: string) => Promise<void>;
|
|
||||||
deleteAttachmentWithServer: (id: string, attachmentId: string) => Promise<void>;
|
|
||||||
sortCiphersByLastUsed: (a: any, b: any) => number;
|
|
||||||
sortCiphersByLastUsedThenName: (a: any, b: any) => number;
|
|
||||||
getLocaleSortingFunction: () => (a: CipherView, b: CipherView) => number;
|
|
||||||
softDelete: (id: string | string[]) => Promise<any>;
|
|
||||||
softDeleteWithServer: (id: string) => Promise<any>;
|
|
||||||
softDeleteManyWithServer: (ids: string[]) => Promise<any>;
|
|
||||||
restore: (
|
|
||||||
cipher: { id: string; revisionDate: string } | { id: string; revisionDate: string }[]
|
|
||||||
) => Promise<any>;
|
|
||||||
restoreWithServer: (id: string) => Promise<any>;
|
|
||||||
restoreManyWithServer: (ids: string[]) => Promise<any>;
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import { CollectionData } from "../models/data/collectionData";
|
|
||||||
import { Collection } from "../models/domain/collection";
|
|
||||||
import { TreeNode } from "../models/domain/treeNode";
|
|
||||||
import { CollectionView } from "../models/view/collectionView";
|
|
||||||
|
|
||||||
export abstract class CollectionService {
|
|
||||||
clearCache: (userId?: string) => Promise<void>;
|
|
||||||
encrypt: (model: CollectionView) => Promise<Collection>;
|
|
||||||
decryptMany: (collections: Collection[]) => Promise<CollectionView[]>;
|
|
||||||
get: (id: string) => Promise<Collection>;
|
|
||||||
getAll: () => Promise<Collection[]>;
|
|
||||||
getAllDecrypted: () => Promise<CollectionView[]>;
|
|
||||||
getAllNested: (collections?: CollectionView[]) => Promise<TreeNode<CollectionView>[]>;
|
|
||||||
getNested: (id: string) => Promise<TreeNode<CollectionView>>;
|
|
||||||
upsert: (collection: CollectionData | CollectionData[]) => Promise<any>;
|
|
||||||
replace: (collections: { [id: string]: CollectionData }) => Promise<any>;
|
|
||||||
clear: (userId: string) => Promise<any>;
|
|
||||||
delete: (id: string | string[]) => Promise<any>;
|
|
||||||
}
|
|
||||||
@@ -15,7 +15,7 @@ export abstract class CryptoService {
|
|||||||
setEncPrivateKey: (encPrivateKey: string) => Promise<void>;
|
setEncPrivateKey: (encPrivateKey: string) => Promise<void>;
|
||||||
setOrgKeys: (
|
setOrgKeys: (
|
||||||
orgs: ProfileOrganizationResponse[],
|
orgs: ProfileOrganizationResponse[],
|
||||||
providerOrgs: ProfileProviderOrganizationResponse[]
|
providerOrgs: ProfileProviderOrganizationResponse[],
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
setProviderKeys: (orgs: ProfileProviderResponse[]) => Promise<void>;
|
setProviderKeys: (orgs: ProfileProviderResponse[]) => Promise<void>;
|
||||||
getKey: (keySuffix?: KeySuffixOptions, userId?: string) => Promise<SymmetricCryptoKey>;
|
getKey: (keySuffix?: KeySuffixOptions, userId?: string) => Promise<SymmetricCryptoKey>;
|
||||||
@@ -46,14 +46,14 @@ export abstract class CryptoService {
|
|||||||
password: string,
|
password: string,
|
||||||
salt: string,
|
salt: string,
|
||||||
kdf: KdfType,
|
kdf: KdfType,
|
||||||
kdfIterations: number
|
kdfIterations: number,
|
||||||
) => Promise<SymmetricCryptoKey>;
|
) => Promise<SymmetricCryptoKey>;
|
||||||
makeKeyFromPin: (
|
makeKeyFromPin: (
|
||||||
pin: string,
|
pin: string,
|
||||||
salt: string,
|
salt: string,
|
||||||
kdf: KdfType,
|
kdf: KdfType,
|
||||||
kdfIterations: number,
|
kdfIterations: number,
|
||||||
protectedKeyCs?: EncString
|
protectedKeyCs?: EncString,
|
||||||
) => Promise<SymmetricCryptoKey>;
|
) => Promise<SymmetricCryptoKey>;
|
||||||
makeShareKey: () => Promise<[EncString, SymmetricCryptoKey]>;
|
makeShareKey: () => Promise<[EncString, SymmetricCryptoKey]>;
|
||||||
makeKeyPair: (key?: SymmetricCryptoKey) => Promise<[string, EncString]>;
|
makeKeyPair: (key?: SymmetricCryptoKey) => Promise<[string, EncString]>;
|
||||||
@@ -61,18 +61,18 @@ export abstract class CryptoService {
|
|||||||
pin: string,
|
pin: string,
|
||||||
salt: string,
|
salt: string,
|
||||||
kdf: KdfType,
|
kdf: KdfType,
|
||||||
kdfIterations: number
|
kdfIterations: number,
|
||||||
) => Promise<SymmetricCryptoKey>;
|
) => Promise<SymmetricCryptoKey>;
|
||||||
makeSendKey: (keyMaterial: ArrayBuffer) => Promise<SymmetricCryptoKey>;
|
makeSendKey: (keyMaterial: ArrayBuffer) => Promise<SymmetricCryptoKey>;
|
||||||
hashPassword: (
|
hashPassword: (
|
||||||
password: string,
|
password: string,
|
||||||
key: SymmetricCryptoKey,
|
key: SymmetricCryptoKey,
|
||||||
hashPurpose?: HashPurpose
|
hashPurpose?: HashPurpose,
|
||||||
) => Promise<string>;
|
) => Promise<string>;
|
||||||
makeEncKey: (key: SymmetricCryptoKey) => Promise<[SymmetricCryptoKey, EncString]>;
|
makeEncKey: (key: SymmetricCryptoKey) => Promise<[SymmetricCryptoKey, EncString]>;
|
||||||
remakeEncKey: (
|
remakeEncKey: (
|
||||||
key: SymmetricCryptoKey,
|
key: SymmetricCryptoKey,
|
||||||
encKey?: SymmetricCryptoKey
|
encKey?: SymmetricCryptoKey,
|
||||||
) => Promise<[SymmetricCryptoKey, EncString]>;
|
) => Promise<[SymmetricCryptoKey, EncString]>;
|
||||||
encrypt: (plainValue: string | ArrayBuffer, key?: SymmetricCryptoKey) => Promise<EncString>;
|
encrypt: (plainValue: string | ArrayBuffer, key?: SymmetricCryptoKey) => Promise<EncString>;
|
||||||
encryptToBytes: (plainValue: ArrayBuffer, key?: SymmetricCryptoKey) => Promise<EncArrayBuffer>;
|
encryptToBytes: (plainValue: ArrayBuffer, key?: SymmetricCryptoKey) => Promise<EncArrayBuffer>;
|
||||||
|
|||||||
@@ -6,35 +6,35 @@ export abstract class CryptoFunctionService {
|
|||||||
password: string | ArrayBuffer,
|
password: string | ArrayBuffer,
|
||||||
salt: string | ArrayBuffer,
|
salt: string | ArrayBuffer,
|
||||||
algorithm: "sha256" | "sha512",
|
algorithm: "sha256" | "sha512",
|
||||||
iterations: number
|
iterations: number,
|
||||||
) => Promise<ArrayBuffer>;
|
) => Promise<ArrayBuffer>;
|
||||||
hkdf: (
|
hkdf: (
|
||||||
ikm: ArrayBuffer,
|
ikm: ArrayBuffer,
|
||||||
salt: string | ArrayBuffer,
|
salt: string | ArrayBuffer,
|
||||||
info: string | ArrayBuffer,
|
info: string | ArrayBuffer,
|
||||||
outputByteSize: number,
|
outputByteSize: number,
|
||||||
algorithm: "sha256" | "sha512"
|
algorithm: "sha256" | "sha512",
|
||||||
) => Promise<ArrayBuffer>;
|
) => Promise<ArrayBuffer>;
|
||||||
hkdfExpand: (
|
hkdfExpand: (
|
||||||
prk: ArrayBuffer,
|
prk: ArrayBuffer,
|
||||||
info: string | ArrayBuffer,
|
info: string | ArrayBuffer,
|
||||||
outputByteSize: number,
|
outputByteSize: number,
|
||||||
algorithm: "sha256" | "sha512"
|
algorithm: "sha256" | "sha512",
|
||||||
) => Promise<ArrayBuffer>;
|
) => Promise<ArrayBuffer>;
|
||||||
hash: (
|
hash: (
|
||||||
value: string | ArrayBuffer,
|
value: string | ArrayBuffer,
|
||||||
algorithm: "sha1" | "sha256" | "sha512" | "md5"
|
algorithm: "sha1" | "sha256" | "sha512" | "md5",
|
||||||
) => Promise<ArrayBuffer>;
|
) => Promise<ArrayBuffer>;
|
||||||
hmac: (
|
hmac: (
|
||||||
value: ArrayBuffer,
|
value: ArrayBuffer,
|
||||||
key: ArrayBuffer,
|
key: ArrayBuffer,
|
||||||
algorithm: "sha1" | "sha256" | "sha512"
|
algorithm: "sha1" | "sha256" | "sha512",
|
||||||
) => Promise<ArrayBuffer>;
|
) => Promise<ArrayBuffer>;
|
||||||
compare: (a: ArrayBuffer, b: ArrayBuffer) => Promise<boolean>;
|
compare: (a: ArrayBuffer, b: ArrayBuffer) => Promise<boolean>;
|
||||||
hmacFast: (
|
hmacFast: (
|
||||||
value: ArrayBuffer | string,
|
value: ArrayBuffer | string,
|
||||||
key: ArrayBuffer | string,
|
key: ArrayBuffer | string,
|
||||||
algorithm: "sha1" | "sha256" | "sha512"
|
algorithm: "sha1" | "sha256" | "sha512",
|
||||||
) => Promise<ArrayBuffer | string>;
|
) => Promise<ArrayBuffer | string>;
|
||||||
compareFast: (a: ArrayBuffer | string, b: ArrayBuffer | string) => Promise<boolean>;
|
compareFast: (a: ArrayBuffer | string, b: ArrayBuffer | string) => Promise<boolean>;
|
||||||
aesEncrypt: (data: ArrayBuffer, iv: ArrayBuffer, key: ArrayBuffer) => Promise<ArrayBuffer>;
|
aesEncrypt: (data: ArrayBuffer, iv: ArrayBuffer, key: ArrayBuffer) => Promise<ArrayBuffer>;
|
||||||
@@ -42,19 +42,19 @@ export abstract class CryptoFunctionService {
|
|||||||
data: string,
|
data: string,
|
||||||
iv: string,
|
iv: string,
|
||||||
mac: string,
|
mac: string,
|
||||||
key: SymmetricCryptoKey
|
key: SymmetricCryptoKey,
|
||||||
) => DecryptParameters<ArrayBuffer | string>;
|
) => DecryptParameters<ArrayBuffer | string>;
|
||||||
aesDecryptFast: (parameters: DecryptParameters<ArrayBuffer | string>) => Promise<string>;
|
aesDecryptFast: (parameters: DecryptParameters<ArrayBuffer | string>) => Promise<string>;
|
||||||
aesDecrypt: (data: ArrayBuffer, iv: ArrayBuffer, key: ArrayBuffer) => Promise<ArrayBuffer>;
|
aesDecrypt: (data: ArrayBuffer, iv: ArrayBuffer, key: ArrayBuffer) => Promise<ArrayBuffer>;
|
||||||
rsaEncrypt: (
|
rsaEncrypt: (
|
||||||
data: ArrayBuffer,
|
data: ArrayBuffer,
|
||||||
publicKey: ArrayBuffer,
|
publicKey: ArrayBuffer,
|
||||||
algorithm: "sha1" | "sha256"
|
algorithm: "sha1" | "sha256",
|
||||||
) => Promise<ArrayBuffer>;
|
) => Promise<ArrayBuffer>;
|
||||||
rsaDecrypt: (
|
rsaDecrypt: (
|
||||||
data: ArrayBuffer,
|
data: ArrayBuffer,
|
||||||
privateKey: ArrayBuffer,
|
privateKey: ArrayBuffer,
|
||||||
algorithm: "sha1" | "sha256"
|
algorithm: "sha1" | "sha256",
|
||||||
) => Promise<ArrayBuffer>;
|
) => Promise<ArrayBuffer>;
|
||||||
rsaExtractPublicKey: (privateKey: ArrayBuffer) => Promise<ArrayBuffer>;
|
rsaExtractPublicKey: (privateKey: ArrayBuffer) => Promise<ArrayBuffer>;
|
||||||
rsaGenerateKeyPair: (length: 1024 | 2048 | 4096) => Promise<[ArrayBuffer, ArrayBuffer]>;
|
rsaGenerateKeyPair: (length: 1024 | 2048 | 4096) => Promise<[ArrayBuffer, ArrayBuffer]>;
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
import { EventType } from "../enums/eventType";
|
|
||||||
|
|
||||||
export abstract class EventService {
|
|
||||||
collect: (eventType: EventType, cipherId?: string, uploadImmediately?: boolean) => Promise<any>;
|
|
||||||
uploadEvents: (userId?: string) => Promise<any>;
|
|
||||||
clearEvents: (userId?: string) => Promise<any>;
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import { EncArrayBuffer } from "../models/domain/encArrayBuffer";
|
|
||||||
import { EncString } from "../models/domain/encString";
|
|
||||||
import { AttachmentUploadDataResponse } from "../models/response/attachmentUploadDataResponse";
|
|
||||||
import { SendFileUploadDataResponse } from "../models/response/sendFileUploadDataResponse";
|
|
||||||
|
|
||||||
export abstract class FileUploadService {
|
|
||||||
uploadSendFile: (
|
|
||||||
uploadData: SendFileUploadDataResponse,
|
|
||||||
fileName: EncString,
|
|
||||||
encryptedFileData: EncArrayBuffer
|
|
||||||
) => Promise<any>;
|
|
||||||
uploadCipherAttachment: (
|
|
||||||
admin: boolean,
|
|
||||||
uploadData: AttachmentUploadDataResponse,
|
|
||||||
fileName: EncString,
|
|
||||||
encryptedFileData: EncArrayBuffer
|
|
||||||
) => Promise<any>;
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import { FolderData } from "../models/data/folderData";
|
|
||||||
import { Folder } from "../models/domain/folder";
|
|
||||||
import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey";
|
|
||||||
import { TreeNode } from "../models/domain/treeNode";
|
|
||||||
import { FolderView } from "../models/view/folderView";
|
|
||||||
|
|
||||||
export abstract class FolderService {
|
|
||||||
clearCache: (userId?: string) => Promise<void>;
|
|
||||||
encrypt: (model: FolderView, key?: SymmetricCryptoKey) => Promise<Folder>;
|
|
||||||
get: (id: string) => Promise<Folder>;
|
|
||||||
getAll: () => Promise<Folder[]>;
|
|
||||||
getAllDecrypted: () => Promise<FolderView[]>;
|
|
||||||
getAllNested: () => Promise<TreeNode<FolderView>[]>;
|
|
||||||
getNested: (id: string) => Promise<TreeNode<FolderView>>;
|
|
||||||
saveWithServer: (folder: Folder) => Promise<any>;
|
|
||||||
upsert: (folder: FolderData | FolderData[]) => Promise<any>;
|
|
||||||
replace: (folders: { [id: string]: FolderData }) => Promise<any>;
|
|
||||||
clear: (userId: string) => Promise<any>;
|
|
||||||
delete: (id: string | string[]) => Promise<any>;
|
|
||||||
deleteWithServer: (id: string) => Promise<any>;
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import { Organization } from "../models/domain/organization";
|
|
||||||
import { IdentityTokenResponse } from "../models/response/identityTokenResponse";
|
|
||||||
|
|
||||||
export abstract class KeyConnectorService {
|
|
||||||
getAndSetKey: (url?: string) => Promise<void>;
|
|
||||||
getManagingOrganization: () => Promise<Organization>;
|
|
||||||
getUsesKeyConnector: () => Promise<boolean>;
|
|
||||||
migrateUser: () => Promise<void>;
|
|
||||||
userNeedsMigration: () => Promise<boolean>;
|
|
||||||
convertNewSsoUserToKeyConnector: (
|
|
||||||
tokenResponse: IdentityTokenResponse,
|
|
||||||
orgId: string
|
|
||||||
) => Promise<void>;
|
|
||||||
setUsesKeyConnector: (enabled: boolean) => Promise<void>;
|
|
||||||
setConvertAccountRequired: (status: boolean) => Promise<void>;
|
|
||||||
getConvertAccountRequired: () => Promise<boolean>;
|
|
||||||
removeConvertAccountRequired: () => Promise<void>;
|
|
||||||
clear: () => Promise<void>;
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
export abstract class NotificationsService {
|
|
||||||
init: () => Promise<void>;
|
|
||||||
updateConnection: (sync?: boolean) => Promise<void>;
|
|
||||||
reconnectFromActivity: () => Promise<void>;
|
|
||||||
disconnectFromInactivity: () => Promise<void>;
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { OrganizationData } from "../models/data/organizationData";
|
|
||||||
import { Organization } from "../models/domain/organization";
|
|
||||||
|
|
||||||
export abstract class OrganizationService {
|
|
||||||
get: (id: string) => Promise<Organization>;
|
|
||||||
getByIdentifier: (identifier: string) => Promise<Organization>;
|
|
||||||
getAll: (userId?: string) => Promise<Organization[]>;
|
|
||||||
save: (orgs: { [id: string]: OrganizationData }) => Promise<any>;
|
|
||||||
canManageSponsorships: () => Promise<boolean>;
|
|
||||||
hasOrganizations: (userId?: string) => Promise<boolean>;
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import * as zxcvbn from "zxcvbn";
|
|
||||||
|
|
||||||
import { GeneratedPasswordHistory } from "../models/domain/generatedPasswordHistory";
|
|
||||||
import { PasswordGeneratorPolicyOptions } from "../models/domain/passwordGeneratorPolicyOptions";
|
|
||||||
|
|
||||||
export abstract class PasswordGenerationService {
|
|
||||||
generatePassword: (options: any) => Promise<string>;
|
|
||||||
generatePassphrase: (options: any) => Promise<string>;
|
|
||||||
getOptions: () => Promise<[any, PasswordGeneratorPolicyOptions]>;
|
|
||||||
enforcePasswordGeneratorPoliciesOnOptions: (
|
|
||||||
options: any
|
|
||||||
) => Promise<[any, PasswordGeneratorPolicyOptions]>;
|
|
||||||
getPasswordGeneratorPolicyOptions: () => Promise<PasswordGeneratorPolicyOptions>;
|
|
||||||
saveOptions: (options: any) => Promise<any>;
|
|
||||||
getHistory: () => Promise<GeneratedPasswordHistory[]>;
|
|
||||||
addHistory: (password: string) => Promise<any>;
|
|
||||||
clear: (userId?: string) => Promise<any>;
|
|
||||||
passwordStrength: (password: string, userInputs?: string[]) => zxcvbn.ZXCVBNResult;
|
|
||||||
normalizeOptions: (options: any, enforcedPolicyOptions: PasswordGeneratorPolicyOptions) => void;
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
export abstract class PasswordRepromptService {
|
|
||||||
protectedFields: () => string[];
|
|
||||||
showPasswordPrompt: () => Promise<boolean>;
|
|
||||||
enabled: () => Promise<boolean>;
|
|
||||||
}
|
|
||||||
@@ -27,7 +27,7 @@ export abstract class PlatformUtilsService {
|
|||||||
type: "error" | "success" | "warning" | "info",
|
type: "error" | "success" | "warning" | "info",
|
||||||
title: string,
|
title: string,
|
||||||
text: string | string[],
|
text: string | string[],
|
||||||
options?: ToastOptions
|
options?: ToastOptions,
|
||||||
) => void;
|
) => void;
|
||||||
showDialog: (
|
showDialog: (
|
||||||
body: string,
|
body: string,
|
||||||
@@ -35,7 +35,7 @@ export abstract class PlatformUtilsService {
|
|||||||
confirmText?: string,
|
confirmText?: string,
|
||||||
cancelText?: string,
|
cancelText?: string,
|
||||||
type?: string,
|
type?: string,
|
||||||
bodyIsHtml?: boolean
|
bodyIsHtml?: boolean,
|
||||||
) => Promise<boolean>;
|
) => Promise<boolean>;
|
||||||
isDev: () => boolean;
|
isDev: () => boolean;
|
||||||
isSelfHost: () => boolean;
|
isSelfHost: () => boolean;
|
||||||
@@ -45,7 +45,7 @@ export abstract class PlatformUtilsService {
|
|||||||
authenticateBiometric: () => Promise<boolean>;
|
authenticateBiometric: () => Promise<boolean>;
|
||||||
getDefaultSystemTheme: () => Promise<ThemeType.Light | ThemeType.Dark>;
|
getDefaultSystemTheme: () => Promise<ThemeType.Light | ThemeType.Dark>;
|
||||||
onDefaultSystemThemeChange: (
|
onDefaultSystemThemeChange: (
|
||||||
callback: (theme: ThemeType.Light | ThemeType.Dark) => unknown
|
callback: (theme: ThemeType.Light | ThemeType.Dark) => unknown,
|
||||||
) => unknown;
|
) => unknown;
|
||||||
getEffectiveTheme: () => Promise<ThemeType>;
|
getEffectiveTheme: () => Promise<ThemeType>;
|
||||||
supportsSecureStorage: () => boolean;
|
supportsSecureStorage: () => boolean;
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
import { PolicyType } from "../enums/policyType";
|
|
||||||
import { PolicyData } from "../models/data/policyData";
|
|
||||||
import { MasterPasswordPolicyOptions } from "../models/domain/masterPasswordPolicyOptions";
|
|
||||||
import { Policy } from "../models/domain/policy";
|
|
||||||
import { ResetPasswordPolicyOptions } from "../models/domain/resetPasswordPolicyOptions";
|
|
||||||
import { ListResponse } from "../models/response/listResponse";
|
|
||||||
import { PolicyResponse } from "../models/response/policyResponse";
|
|
||||||
|
|
||||||
export abstract class PolicyService {
|
|
||||||
clearCache: () => void;
|
|
||||||
getAll: (type?: PolicyType, userId?: string) => Promise<Policy[]>;
|
|
||||||
getPolicyForOrganization: (policyType: PolicyType, organizationId: string) => Promise<Policy>;
|
|
||||||
replace: (policies: { [id: string]: PolicyData }) => Promise<any>;
|
|
||||||
clear: (userId?: string) => Promise<any>;
|
|
||||||
getMasterPasswordPoliciesForInvitedUsers: (orgId: string) => Promise<MasterPasswordPolicyOptions>;
|
|
||||||
getMasterPasswordPolicyOptions: (policies?: Policy[]) => Promise<MasterPasswordPolicyOptions>;
|
|
||||||
evaluateMasterPassword: (
|
|
||||||
passwordStrength: number,
|
|
||||||
newPassword: string,
|
|
||||||
enforcedPolicyOptions?: MasterPasswordPolicyOptions
|
|
||||||
) => boolean;
|
|
||||||
getResetPasswordPolicyOptions: (
|
|
||||||
policies: Policy[],
|
|
||||||
orgId: string
|
|
||||||
) => [ResetPasswordPolicyOptions, boolean];
|
|
||||||
mapPoliciesFromToken: (policiesResponse: ListResponse<PolicyResponse>) => Policy[];
|
|
||||||
policyAppliesToUser: (
|
|
||||||
policyType: PolicyType,
|
|
||||||
policyFilter?: (policy: Policy) => boolean,
|
|
||||||
userId?: string
|
|
||||||
) => Promise<boolean>;
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
import { ProviderData } from "../models/data/providerData";
|
|
||||||
import { Provider } from "../models/domain/provider";
|
|
||||||
|
|
||||||
export abstract class ProviderService {
|
|
||||||
get: (id: string) => Promise<Provider>;
|
|
||||||
getAll: () => Promise<Provider[]>;
|
|
||||||
save: (providers: { [id: string]: ProviderData }) => Promise<any>;
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
import { CipherView } from "../models/view/cipherView";
|
|
||||||
import { SendView } from "../models/view/sendView";
|
|
||||||
|
|
||||||
export abstract class SearchService {
|
|
||||||
indexedEntityId?: string = null;
|
|
||||||
clearIndex: () => void;
|
|
||||||
isSearchable: (query: string) => boolean;
|
|
||||||
indexCiphers: (indexedEntityGuid?: string, ciphersToIndex?: CipherView[]) => Promise<void>;
|
|
||||||
searchCiphers: (
|
|
||||||
query: string,
|
|
||||||
filter?: ((cipher: CipherView) => boolean) | ((cipher: CipherView) => boolean)[],
|
|
||||||
ciphers?: CipherView[]
|
|
||||||
) => Promise<CipherView[]>;
|
|
||||||
searchCiphersBasic: (ciphers: CipherView[], query: string, deleted?: boolean) => CipherView[];
|
|
||||||
searchSends: (sends: SendView[], query: string) => SendView[];
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { SendData } from "../models/data/sendData";
|
|
||||||
import { EncArrayBuffer } from "../models/domain/encArrayBuffer";
|
|
||||||
import { Send } from "../models/domain/send";
|
|
||||||
import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey";
|
|
||||||
import { SendView } from "../models/view/sendView";
|
|
||||||
|
|
||||||
export abstract class SendService {
|
|
||||||
clearCache: () => Promise<void>;
|
|
||||||
encrypt: (
|
|
||||||
model: SendView,
|
|
||||||
file: File | ArrayBuffer,
|
|
||||||
password: string,
|
|
||||||
key?: SymmetricCryptoKey
|
|
||||||
) => Promise<[Send, EncArrayBuffer]>;
|
|
||||||
get: (id: string) => Promise<Send>;
|
|
||||||
getAll: () => Promise<Send[]>;
|
|
||||||
getAllDecrypted: () => Promise<SendView[]>;
|
|
||||||
saveWithServer: (sendData: [Send, EncArrayBuffer]) => Promise<any>;
|
|
||||||
upsert: (send: SendData | SendData[]) => Promise<any>;
|
|
||||||
replace: (sends: { [id: string]: SendData }) => Promise<any>;
|
|
||||||
clear: (userId: string) => Promise<any>;
|
|
||||||
delete: (id: string | string[]) => Promise<any>;
|
|
||||||
deleteWithServer: (id: string) => Promise<any>;
|
|
||||||
removePasswordWithServer: (id: string) => Promise<any>;
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
export abstract class SettingsService {
|
|
||||||
clearCache: () => Promise<void>;
|
|
||||||
getEquivalentDomains: () => Promise<any>;
|
|
||||||
setEquivalentDomains: (equivalentDomains: string[][]) => Promise<any>;
|
|
||||||
clear: (userId?: string) => Promise<void>;
|
|
||||||
}
|
|
||||||
@@ -3,26 +3,14 @@ import { Observable } from "rxjs";
|
|||||||
import { KdfType } from "../enums/kdfType";
|
import { KdfType } from "../enums/kdfType";
|
||||||
import { ThemeType } from "../enums/themeType";
|
import { ThemeType } from "../enums/themeType";
|
||||||
import { UriMatchType } from "../enums/uriMatchType";
|
import { UriMatchType } from "../enums/uriMatchType";
|
||||||
import { CipherData } from "../models/data/cipherData";
|
|
||||||
import { CollectionData } from "../models/data/collectionData";
|
|
||||||
import { EventData } from "../models/data/eventData";
|
|
||||||
import { FolderData } from "../models/data/folderData";
|
|
||||||
import { OrganizationData } from "../models/data/organizationData";
|
import { OrganizationData } from "../models/data/organizationData";
|
||||||
import { PolicyData } from "../models/data/policyData";
|
|
||||||
import { ProviderData } from "../models/data/providerData";
|
import { ProviderData } from "../models/data/providerData";
|
||||||
import { SendData } from "../models/data/sendData";
|
|
||||||
import { Account } from "../models/domain/account";
|
import { Account } from "../models/domain/account";
|
||||||
import { EncString } from "../models/domain/encString";
|
import { EncString } from "../models/domain/encString";
|
||||||
import { EnvironmentUrls } from "../models/domain/environmentUrls";
|
import { EnvironmentUrls } from "../models/domain/environmentUrls";
|
||||||
import { GeneratedPasswordHistory } from "../models/domain/generatedPasswordHistory";
|
|
||||||
import { Policy } from "../models/domain/policy";
|
|
||||||
import { StorageOptions } from "../models/domain/storageOptions";
|
import { StorageOptions } from "../models/domain/storageOptions";
|
||||||
import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey";
|
import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey";
|
||||||
import { WindowState } from "../models/domain/windowState";
|
import { WindowState } from "../models/domain/windowState";
|
||||||
import { CipherView } from "../models/view/cipherView";
|
|
||||||
import { CollectionView } from "../models/view/collectionView";
|
|
||||||
import { FolderView } from "../models/view/folderView";
|
|
||||||
import { SendView } from "../models/view/sendView";
|
|
||||||
|
|
||||||
export abstract class StateService<T extends Account = Account> {
|
export abstract class StateService<T extends Account = Account> {
|
||||||
accounts$: Observable<{ [userId: string]: T }>;
|
accounts$: Observable<{ [userId: string]: T }>;
|
||||||
@@ -45,8 +33,6 @@ export abstract class StateService<T extends Account = Account> {
|
|||||||
setApiKeyClientSecret: (value: string, options?: StorageOptions) => Promise<void>;
|
setApiKeyClientSecret: (value: string, options?: StorageOptions) => Promise<void>;
|
||||||
getAutoConfirmFingerPrints: (options?: StorageOptions) => Promise<boolean>;
|
getAutoConfirmFingerPrints: (options?: StorageOptions) => Promise<boolean>;
|
||||||
setAutoConfirmFingerprints: (value: boolean, options?: StorageOptions) => Promise<void>;
|
setAutoConfirmFingerprints: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||||
getAutoFillOnPageLoadDefault: (options?: StorageOptions) => Promise<boolean>;
|
|
||||||
setAutoFillOnPageLoadDefault: (value: boolean, options?: StorageOptions) => Promise<void>;
|
|
||||||
getBiometricAwaitingAcceptance: (options?: StorageOptions) => Promise<boolean>;
|
getBiometricAwaitingAcceptance: (options?: StorageOptions) => Promise<boolean>;
|
||||||
setBiometricAwaitingAcceptance: (value: boolean, options?: StorageOptions) => Promise<void>;
|
setBiometricAwaitingAcceptance: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||||
getBiometricFingerprintValidated: (options?: StorageOptions) => Promise<boolean>;
|
getBiometricFingerprintValidated: (options?: StorageOptions) => Promise<boolean>;
|
||||||
@@ -75,150 +61,75 @@ export abstract class StateService<T extends Account = Account> {
|
|||||||
setCryptoMasterKeyBiometric: (value: string, options?: StorageOptions) => Promise<void>;
|
setCryptoMasterKeyBiometric: (value: string, options?: StorageOptions) => Promise<void>;
|
||||||
getDecodedToken: (options?: StorageOptions) => Promise<any>;
|
getDecodedToken: (options?: StorageOptions) => Promise<any>;
|
||||||
setDecodedToken: (value: any, options?: StorageOptions) => Promise<void>;
|
setDecodedToken: (value: any, options?: StorageOptions) => Promise<void>;
|
||||||
getDecryptedCiphers: (options?: StorageOptions) => Promise<CipherView[]>;
|
|
||||||
setDecryptedCiphers: (value: CipherView[], options?: StorageOptions) => Promise<void>;
|
|
||||||
getDecryptedCollections: (options?: StorageOptions) => Promise<CollectionView[]>;
|
|
||||||
setDecryptedCollections: (value: CollectionView[], options?: StorageOptions) => Promise<void>;
|
|
||||||
getDecryptedCryptoSymmetricKey: (options?: StorageOptions) => Promise<SymmetricCryptoKey>;
|
getDecryptedCryptoSymmetricKey: (options?: StorageOptions) => Promise<SymmetricCryptoKey>;
|
||||||
setDecryptedCryptoSymmetricKey: (
|
setDecryptedCryptoSymmetricKey: (
|
||||||
value: SymmetricCryptoKey,
|
value: SymmetricCryptoKey,
|
||||||
options?: StorageOptions
|
options?: StorageOptions,
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
getDecryptedFolders: (options?: StorageOptions) => Promise<FolderView[]>;
|
|
||||||
setDecryptedFolders: (value: FolderView[], options?: StorageOptions) => Promise<void>;
|
|
||||||
getDecryptedOrganizationKeys: (
|
getDecryptedOrganizationKeys: (
|
||||||
options?: StorageOptions
|
options?: StorageOptions,
|
||||||
) => Promise<Map<string, SymmetricCryptoKey>>;
|
) => Promise<Map<string, SymmetricCryptoKey>>;
|
||||||
setDecryptedOrganizationKeys: (
|
setDecryptedOrganizationKeys: (
|
||||||
value: Map<string, SymmetricCryptoKey>,
|
value: Map<string, SymmetricCryptoKey>,
|
||||||
options?: StorageOptions
|
options?: StorageOptions,
|
||||||
) => Promise<void>;
|
|
||||||
getDecryptedPasswordGenerationHistory: (
|
|
||||||
options?: StorageOptions
|
|
||||||
) => Promise<GeneratedPasswordHistory[]>;
|
|
||||||
setDecryptedPasswordGenerationHistory: (
|
|
||||||
value: GeneratedPasswordHistory[],
|
|
||||||
options?: StorageOptions
|
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
getDecryptedPinProtected: (options?: StorageOptions) => Promise<EncString>;
|
getDecryptedPinProtected: (options?: StorageOptions) => Promise<EncString>;
|
||||||
setDecryptedPinProtected: (value: EncString, options?: StorageOptions) => Promise<void>;
|
setDecryptedPinProtected: (value: EncString, options?: StorageOptions) => Promise<void>;
|
||||||
getDecryptedPolicies: (options?: StorageOptions) => Promise<Policy[]>;
|
|
||||||
setDecryptedPolicies: (value: Policy[], options?: StorageOptions) => Promise<void>;
|
|
||||||
getDecryptedPrivateKey: (options?: StorageOptions) => Promise<ArrayBuffer>;
|
getDecryptedPrivateKey: (options?: StorageOptions) => Promise<ArrayBuffer>;
|
||||||
setDecryptedPrivateKey: (value: ArrayBuffer, options?: StorageOptions) => Promise<void>;
|
setDecryptedPrivateKey: (value: ArrayBuffer, options?: StorageOptions) => Promise<void>;
|
||||||
getDecryptedProviderKeys: (options?: StorageOptions) => Promise<Map<string, SymmetricCryptoKey>>;
|
getDecryptedProviderKeys: (options?: StorageOptions) => Promise<Map<string, SymmetricCryptoKey>>;
|
||||||
setDecryptedProviderKeys: (
|
setDecryptedProviderKeys: (
|
||||||
value: Map<string, SymmetricCryptoKey>,
|
value: Map<string, SymmetricCryptoKey>,
|
||||||
options?: StorageOptions
|
options?: StorageOptions,
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
getDecryptedSends: (options?: StorageOptions) => Promise<SendView[]>;
|
|
||||||
setDecryptedSends: (value: SendView[], options?: StorageOptions) => Promise<void>;
|
|
||||||
getDefaultUriMatch: (options?: StorageOptions) => Promise<UriMatchType>;
|
getDefaultUriMatch: (options?: StorageOptions) => Promise<UriMatchType>;
|
||||||
setDefaultUriMatch: (value: UriMatchType, options?: StorageOptions) => Promise<void>;
|
setDefaultUriMatch: (value: UriMatchType, options?: StorageOptions) => Promise<void>;
|
||||||
getDisableAddLoginNotification: (options?: StorageOptions) => Promise<boolean>;
|
|
||||||
setDisableAddLoginNotification: (value: boolean, options?: StorageOptions) => Promise<void>;
|
|
||||||
getDisableAutoBiometricsPrompt: (options?: StorageOptions) => Promise<boolean>;
|
getDisableAutoBiometricsPrompt: (options?: StorageOptions) => Promise<boolean>;
|
||||||
setDisableAutoBiometricsPrompt: (value: boolean, options?: StorageOptions) => Promise<void>;
|
setDisableAutoBiometricsPrompt: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||||
getDisableAutoTotpCopy: (options?: StorageOptions) => Promise<boolean>;
|
getDisableAutoTotpCopy: (options?: StorageOptions) => Promise<boolean>;
|
||||||
setDisableAutoTotpCopy: (value: boolean, options?: StorageOptions) => Promise<void>;
|
setDisableAutoTotpCopy: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||||
getDisableBadgeCounter: (options?: StorageOptions) => Promise<boolean>;
|
getDisableBadgeCounter: (options?: StorageOptions) => Promise<boolean>;
|
||||||
setDisableBadgeCounter: (value: boolean, options?: StorageOptions) => Promise<void>;
|
setDisableBadgeCounter: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||||
getDisableChangedPasswordNotification: (options?: StorageOptions) => Promise<boolean>;
|
|
||||||
setDisableChangedPasswordNotification: (
|
|
||||||
value: boolean,
|
|
||||||
options?: StorageOptions
|
|
||||||
) => Promise<void>;
|
|
||||||
getDisableContextMenuItem: (options?: StorageOptions) => Promise<boolean>;
|
getDisableContextMenuItem: (options?: StorageOptions) => Promise<boolean>;
|
||||||
setDisableContextMenuItem: (value: boolean, options?: StorageOptions) => Promise<void>;
|
setDisableContextMenuItem: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||||
getDisableFavicon: (options?: StorageOptions) => Promise<boolean>;
|
|
||||||
setDisableFavicon: (value: boolean, options?: StorageOptions) => Promise<void>;
|
|
||||||
getDisableGa: (options?: StorageOptions) => Promise<boolean>;
|
getDisableGa: (options?: StorageOptions) => Promise<boolean>;
|
||||||
setDisableGa: (value: boolean, options?: StorageOptions) => Promise<void>;
|
setDisableGa: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||||
getDontShowCardsCurrentTab: (options?: StorageOptions) => Promise<boolean>;
|
|
||||||
setDontShowCardsCurrentTab: (value: boolean, options?: StorageOptions) => Promise<void>;
|
|
||||||
getDontShowIdentitiesCurrentTab: (options?: StorageOptions) => Promise<boolean>;
|
|
||||||
setDontShowIdentitiesCurrentTab: (value: boolean, options?: StorageOptions) => Promise<void>;
|
|
||||||
getEmail: (options?: StorageOptions) => Promise<string>;
|
getEmail: (options?: StorageOptions) => Promise<string>;
|
||||||
setEmail: (value: string, options?: StorageOptions) => Promise<void>;
|
setEmail: (value: string, options?: StorageOptions) => Promise<void>;
|
||||||
getEmailVerified: (options?: StorageOptions) => Promise<boolean>;
|
getEmailVerified: (options?: StorageOptions) => Promise<boolean>;
|
||||||
setEmailVerified: (value: boolean, options?: StorageOptions) => Promise<void>;
|
setEmailVerified: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||||
getEnableAlwaysOnTop: (options?: StorageOptions) => Promise<boolean>;
|
getEnableAlwaysOnTop: (options?: StorageOptions) => Promise<boolean>;
|
||||||
setEnableAlwaysOnTop: (value: boolean, options?: StorageOptions) => Promise<void>;
|
setEnableAlwaysOnTop: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||||
getEnableAutoFillOnPageLoad: (options?: StorageOptions) => Promise<boolean>;
|
|
||||||
setEnableAutoFillOnPageLoad: (value: boolean, options?: StorageOptions) => Promise<void>;
|
|
||||||
getEnableBiometric: (options?: StorageOptions) => Promise<boolean>;
|
getEnableBiometric: (options?: StorageOptions) => Promise<boolean>;
|
||||||
setEnableBiometric: (value: boolean, options?: StorageOptions) => Promise<void>;
|
setEnableBiometric: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||||
getEnableBrowserIntegration: (options?: StorageOptions) => Promise<boolean>;
|
|
||||||
setEnableBrowserIntegration: (value: boolean, options?: StorageOptions) => Promise<void>;
|
|
||||||
getEnableBrowserIntegrationFingerprint: (options?: StorageOptions) => Promise<boolean>;
|
|
||||||
setEnableBrowserIntegrationFingerprint: (
|
|
||||||
value: boolean,
|
|
||||||
options?: StorageOptions
|
|
||||||
) => Promise<void>;
|
|
||||||
getEnableCloseToTray: (options?: StorageOptions) => Promise<boolean>;
|
getEnableCloseToTray: (options?: StorageOptions) => Promise<boolean>;
|
||||||
setEnableCloseToTray: (value: boolean, options?: StorageOptions) => Promise<void>;
|
setEnableCloseToTray: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||||
getEnableFullWidth: (options?: StorageOptions) => Promise<boolean>;
|
getEnableFullWidth: (options?: StorageOptions) => Promise<boolean>;
|
||||||
setEnableFullWidth: (value: boolean, options?: StorageOptions) => Promise<void>;
|
setEnableFullWidth: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||||
getEnableGravitars: (options?: StorageOptions) => Promise<boolean>;
|
|
||||||
setEnableGravitars: (value: boolean, options?: StorageOptions) => Promise<void>;
|
|
||||||
getEnableMinimizeToTray: (options?: StorageOptions) => Promise<boolean>;
|
getEnableMinimizeToTray: (options?: StorageOptions) => Promise<boolean>;
|
||||||
setEnableMinimizeToTray: (value: boolean, options?: StorageOptions) => Promise<void>;
|
setEnableMinimizeToTray: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||||
getEnableStartToTray: (options?: StorageOptions) => Promise<boolean>;
|
getEnableStartToTray: (options?: StorageOptions) => Promise<boolean>;
|
||||||
setEnableStartToTray: (value: boolean, options?: StorageOptions) => Promise<void>;
|
setEnableStartToTray: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||||
getEnableTray: (options?: StorageOptions) => Promise<boolean>;
|
getEnableTray: (options?: StorageOptions) => Promise<boolean>;
|
||||||
setEnableTray: (value: boolean, options?: StorageOptions) => Promise<void>;
|
setEnableTray: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||||
getEncryptedCiphers: (options?: StorageOptions) => Promise<{ [id: string]: CipherData }>;
|
|
||||||
setEncryptedCiphers: (
|
|
||||||
value: { [id: string]: CipherData },
|
|
||||||
options?: StorageOptions
|
|
||||||
) => Promise<void>;
|
|
||||||
getEncryptedCollections: (options?: StorageOptions) => Promise<{ [id: string]: CollectionData }>;
|
|
||||||
setEncryptedCollections: (
|
|
||||||
value: { [id: string]: CollectionData },
|
|
||||||
options?: StorageOptions
|
|
||||||
) => Promise<void>;
|
|
||||||
getEncryptedCryptoSymmetricKey: (options?: StorageOptions) => Promise<string>;
|
getEncryptedCryptoSymmetricKey: (options?: StorageOptions) => Promise<string>;
|
||||||
setEncryptedCryptoSymmetricKey: (value: string, options?: StorageOptions) => Promise<void>;
|
setEncryptedCryptoSymmetricKey: (value: string, options?: StorageOptions) => Promise<void>;
|
||||||
getEncryptedFolders: (options?: StorageOptions) => Promise<{ [id: string]: FolderData }>;
|
|
||||||
setEncryptedFolders: (
|
|
||||||
value: { [id: string]: FolderData },
|
|
||||||
options?: StorageOptions
|
|
||||||
) => Promise<void>;
|
|
||||||
getEncryptedOrganizationKeys: (options?: StorageOptions) => Promise<any>;
|
getEncryptedOrganizationKeys: (options?: StorageOptions) => Promise<any>;
|
||||||
setEncryptedOrganizationKeys: (
|
setEncryptedOrganizationKeys: (
|
||||||
value: Map<string, SymmetricCryptoKey>,
|
value: Map<string, SymmetricCryptoKey>,
|
||||||
options?: StorageOptions
|
options?: StorageOptions,
|
||||||
) => Promise<void>;
|
|
||||||
getEncryptedPasswordGenerationHistory: (
|
|
||||||
options?: StorageOptions
|
|
||||||
) => Promise<GeneratedPasswordHistory[]>;
|
|
||||||
setEncryptedPasswordGenerationHistory: (
|
|
||||||
value: GeneratedPasswordHistory[],
|
|
||||||
options?: StorageOptions
|
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
getEncryptedPinProtected: (options?: StorageOptions) => Promise<string>;
|
getEncryptedPinProtected: (options?: StorageOptions) => Promise<string>;
|
||||||
setEncryptedPinProtected: (value: string, options?: StorageOptions) => Promise<void>;
|
setEncryptedPinProtected: (value: string, options?: StorageOptions) => Promise<void>;
|
||||||
getEncryptedPolicies: (options?: StorageOptions) => Promise<{ [id: string]: PolicyData }>;
|
|
||||||
setEncryptedPolicies: (
|
|
||||||
value: { [id: string]: PolicyData },
|
|
||||||
options?: StorageOptions
|
|
||||||
) => Promise<void>;
|
|
||||||
getEncryptedPrivateKey: (options?: StorageOptions) => Promise<string>;
|
getEncryptedPrivateKey: (options?: StorageOptions) => Promise<string>;
|
||||||
setEncryptedPrivateKey: (value: string, options?: StorageOptions) => Promise<void>;
|
setEncryptedPrivateKey: (value: string, options?: StorageOptions) => Promise<void>;
|
||||||
getEncryptedProviderKeys: (options?: StorageOptions) => Promise<any>;
|
getEncryptedProviderKeys: (options?: StorageOptions) => Promise<any>;
|
||||||
setEncryptedProviderKeys: (value: any, options?: StorageOptions) => Promise<void>;
|
setEncryptedProviderKeys: (value: any, options?: StorageOptions) => Promise<void>;
|
||||||
getEncryptedSends: (options?: StorageOptions) => Promise<{ [id: string]: SendData }>;
|
|
||||||
setEncryptedSends: (value: { [id: string]: SendData }, options?: StorageOptions) => Promise<void>;
|
|
||||||
getEntityId: (options?: StorageOptions) => Promise<string>;
|
getEntityId: (options?: StorageOptions) => Promise<string>;
|
||||||
setEntityId: (value: string, options?: StorageOptions) => Promise<void>;
|
|
||||||
getEntityType: (options?: StorageOptions) => Promise<any>;
|
|
||||||
setEntityType: (value: string, options?: StorageOptions) => Promise<void>;
|
|
||||||
getEnvironmentUrls: (options?: StorageOptions) => Promise<EnvironmentUrls>;
|
getEnvironmentUrls: (options?: StorageOptions) => Promise<EnvironmentUrls>;
|
||||||
setEnvironmentUrls: (value: EnvironmentUrls, options?: StorageOptions) => Promise<void>;
|
setEnvironmentUrls: (value: EnvironmentUrls, options?: StorageOptions) => Promise<void>;
|
||||||
getEquivalentDomains: (options?: StorageOptions) => Promise<any>;
|
getEquivalentDomains: (options?: StorageOptions) => Promise<any>;
|
||||||
setEquivalentDomains: (value: string, options?: StorageOptions) => Promise<void>;
|
setEquivalentDomains: (value: string, options?: StorageOptions) => Promise<void>;
|
||||||
getEventCollection: (options?: StorageOptions) => Promise<EventData[]>;
|
|
||||||
setEventCollection: (value: EventData[], options?: StorageOptions) => Promise<void>;
|
|
||||||
getEverBeenUnlocked: (options?: StorageOptions) => Promise<boolean>;
|
getEverBeenUnlocked: (options?: StorageOptions) => Promise<boolean>;
|
||||||
setEverBeenUnlocked: (value: boolean, options?: StorageOptions) => Promise<void>;
|
setEverBeenUnlocked: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||||
getForcePasswordReset: (options?: StorageOptions) => Promise<boolean>;
|
getForcePasswordReset: (options?: StorageOptions) => Promise<boolean>;
|
||||||
@@ -261,7 +172,7 @@ export abstract class StateService<T extends Account = Account> {
|
|||||||
getOrganizations: (options?: StorageOptions) => Promise<{ [id: string]: OrganizationData }>;
|
getOrganizations: (options?: StorageOptions) => Promise<{ [id: string]: OrganizationData }>;
|
||||||
setOrganizations: (
|
setOrganizations: (
|
||||||
value: { [id: string]: OrganizationData },
|
value: { [id: string]: OrganizationData },
|
||||||
options?: StorageOptions
|
options?: StorageOptions,
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
getPasswordGenerationOptions: (options?: StorageOptions) => Promise<any>;
|
getPasswordGenerationOptions: (options?: StorageOptions) => Promise<any>;
|
||||||
setPasswordGenerationOptions: (value: any, options?: StorageOptions) => Promise<void>;
|
setPasswordGenerationOptions: (value: any, options?: StorageOptions) => Promise<void>;
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
import {
|
|
||||||
SyncCipherNotification,
|
|
||||||
SyncFolderNotification,
|
|
||||||
SyncSendNotification,
|
|
||||||
} from "../models/response/notificationResponse";
|
|
||||||
|
|
||||||
export abstract class SyncService {
|
|
||||||
syncInProgress: boolean;
|
|
||||||
|
|
||||||
getLastSync: () => Promise<Date>;
|
|
||||||
setLastSync: (date: Date, userId?: string) => Promise<any>;
|
|
||||||
fullSync: (forceSync: boolean, allowThrowOnError?: boolean) => Promise<boolean>;
|
|
||||||
syncUpsertFolder: (notification: SyncFolderNotification, isEdit: boolean) => Promise<boolean>;
|
|
||||||
syncDeleteFolder: (notification: SyncFolderNotification) => Promise<boolean>;
|
|
||||||
syncUpsertCipher: (notification: SyncCipherNotification, isEdit: boolean) => Promise<boolean>;
|
|
||||||
syncDeleteCipher: (notification: SyncFolderNotification) => Promise<boolean>;
|
|
||||||
syncUpsertSend: (notification: SyncSendNotification, isEdit: boolean) => Promise<boolean>;
|
|
||||||
syncDeleteSend: (notification: SyncSendNotification) => Promise<boolean>;
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
export abstract class SystemService {
|
|
||||||
startProcessReload: () => Promise<void>;
|
|
||||||
cancelProcessReload: () => void;
|
|
||||||
clearClipboard: (clipboardValue: string, timeoutMs?: number) => Promise<void>;
|
|
||||||
clearPendingClipboard: () => Promise<any>;
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,7 @@ export abstract class TokenService {
|
|||||||
setTokens: (
|
setTokens: (
|
||||||
accessToken: string,
|
accessToken: string,
|
||||||
refreshToken: string,
|
refreshToken: string,
|
||||||
clientIdClientSecret: [string, string]
|
clientIdClientSecret: [string, string],
|
||||||
) => Promise<any>;
|
) => Promise<any>;
|
||||||
setToken: (token: string) => Promise<any>;
|
setToken: (token: string) => Promise<any>;
|
||||||
getToken: () => Promise<string>;
|
getToken: () => Promise<string>;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user