mirror of
https://github.com/bitwarden/android.git
synced 2026-06-10 00:28:29 -05:00
Compare commits
4 Commits
languages/
...
release-no
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf2ac7cac9 | ||
|
|
5bbbf7c5e4 | ||
|
|
39d10fa77d | ||
|
|
f0f240f8e5 |
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@@ -5,7 +5,7 @@
|
|||||||
# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
|
# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
|
||||||
|
|
||||||
# Default file owners.
|
# Default file owners.
|
||||||
* @bitwarden/team-android @brian-livefront @david-livefront
|
* @bitwarden/team-android @brian-livefront @david-livefront @dseverns-livefront @ahaisting-livefront @phil-livefront
|
||||||
|
|
||||||
# Actions and workflow changes.
|
# Actions and workflow changes.
|
||||||
.github/ @bitwarden/dept-development-mobile
|
.github/ @bitwarden/dept-development-mobile
|
||||||
|
|||||||
64
.github/ISSUE_TEMPLATE/bug-passkey.yml
vendored
64
.github/ISSUE_TEMPLATE/bug-passkey.yml
vendored
@@ -1,64 +0,0 @@
|
|||||||
name: Passkey Bug Report
|
|
||||||
description: File a Passkey / FIDO2 related bug report
|
|
||||||
labels: [ "app:password-manager", "bug-passkey" ]
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
Thanks for taking the time to fill out this Passkey-related bug report!
|
|
||||||
|
|
||||||
Please provide as much detail as possible to help us investigate the issue.
|
|
||||||
|
|
||||||
- type: dropdown
|
|
||||||
id: origin
|
|
||||||
attributes:
|
|
||||||
label: Origin
|
|
||||||
description: Are you using a web browser or a native application?
|
|
||||||
options:
|
|
||||||
- Web (Browser)
|
|
||||||
- Native Application (non-browser app)
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
id: rp-id
|
|
||||||
attributes:
|
|
||||||
label: Web URL or App name
|
|
||||||
description: The website domain or app name you were trying to use the Passkey with
|
|
||||||
placeholder: "e.g. example.com or ExampleApp"
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: checkboxes
|
|
||||||
id: operation-type
|
|
||||||
attributes:
|
|
||||||
label: Passkey Action
|
|
||||||
description: What passkey related action(s) were you trying to perform?
|
|
||||||
options:
|
|
||||||
- label: Creating new passkey (Registration)
|
|
||||||
- label: Signing in (Authentication)
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: build-info
|
|
||||||
attributes:
|
|
||||||
label: Build Information
|
|
||||||
description: Please retrieve the build information from the About screen by tapping the Version number field
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: additional-info
|
|
||||||
attributes:
|
|
||||||
label: Additional Information
|
|
||||||
description: Any additional context, steps to reproduce, error messages, or relevant information about the issue
|
|
||||||
|
|
||||||
- type: checkboxes
|
|
||||||
id: issue-tracking-info
|
|
||||||
attributes:
|
|
||||||
label: Issue Tracking Info
|
|
||||||
description: |
|
|
||||||
Issue tracking information
|
|
||||||
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.
|
|
||||||
51
.github/renovate.json
vendored
51
.github/renovate.json
vendored
@@ -1,56 +1,33 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
"extends": [
|
"extends": ["github>bitwarden/renovate-config"],
|
||||||
"github>bitwarden/renovate-config"
|
"enabledManagers": ["github-actions", "gradle", "bundler"],
|
||||||
],
|
|
||||||
"enabledManagers": [
|
|
||||||
"github-actions",
|
|
||||||
"gradle",
|
|
||||||
"bundler"
|
|
||||||
],
|
|
||||||
"packageRules": [
|
"packageRules": [
|
||||||
{
|
{
|
||||||
"groupName": "gh minor",
|
"groupName": "gh minor",
|
||||||
"matchManagers": [
|
"matchManagers": ["github-actions"],
|
||||||
"github-actions"
|
"matchUpdateTypes": ["minor", "patch"]
|
||||||
],
|
|
||||||
"matchUpdateTypes": [
|
|
||||||
"minor",
|
|
||||||
"patch"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"groupName": "gradle minor",
|
"groupName": "gradle minor",
|
||||||
"matchUpdateTypes": [
|
"matchUpdateTypes": ["minor", "patch"],
|
||||||
"minor",
|
"matchManagers": ["gradle"]
|
||||||
"patch"
|
|
||||||
],
|
|
||||||
"matchManagers": [
|
|
||||||
"gradle"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"groupName": "kotlin",
|
"groupName": "kotlin",
|
||||||
"description": "Kotlin and Compose dependencies that must be updated together to maintain compatibility.",
|
"description": "Kotlin and Compose dependencies that must be updated together to maintain compatibility.",
|
||||||
"matchManagers": [
|
"matchPackagePatterns": [
|
||||||
"gradle"
|
"androidx.compose:compose-bom",
|
||||||
|
"androidx.lifecycle:*",
|
||||||
|
"org.jetbrains.kotlin.*",
|
||||||
|
"com.google.devtools.ksp"
|
||||||
],
|
],
|
||||||
"matchPackageNames": [
|
"matchManagers": ["gradle"]
|
||||||
"/androidx.compose:compose-bom/",
|
|
||||||
"/androidx.lifecycle:*/",
|
|
||||||
"/org.jetbrains.kotlin.*/",
|
|
||||||
"/com.google.devtools.ksp/"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"groupName": "bundler minor",
|
"groupName": "bundler minor",
|
||||||
"matchUpdateTypes": [
|
"matchUpdateTypes": ["minor", "patch"],
|
||||||
"minor",
|
"matchManagers": ["bundler"]
|
||||||
"patch"
|
|
||||||
],
|
|
||||||
"matchManagers": [
|
|
||||||
"bundler"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
64
.github/scripts/release-notes/linked_issues.py
vendored
Normal file
64
.github/scripts/release-notes/linked_issues.py
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
def create_linked_issue_comment(repo_owner: str, repo_name: str, release_name: str, release_link: str, pr_numbers: List[int]) -> str:
|
||||||
|
if len(pr_numbers) == 0:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
pr_links = [f"* https://github.com/{repo_owner}/{repo_name}/pull/{pr_number}" for pr_number in pr_numbers]
|
||||||
|
|
||||||
|
return f":shipit: Pull Request(s) linked to this issue released in [{release_name}]({release_link}):\n\n"+ "\n".join(pr_links)
|
||||||
|
|
||||||
|
def comment_linked_issues_in_pr(owner: str, repo: str, pr_number: int) -> None:
|
||||||
|
"""Use GitHub CLI to comment all issues linked to a PR.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
linked_issues = get_linked_issues(owner, repo, pr_number)
|
||||||
|
for issue_number in linked_issues:
|
||||||
|
comment_github_issue(owner, repo, issue_number, comment)
|
||||||
|
|
||||||
|
def comment_github_issue(owner: str, repo: str, issue_number: int, comment: str) -> None:
|
||||||
|
"""Use GitHub CLI to comment on an issue.
|
||||||
|
"""
|
||||||
|
subprocess.run([
|
||||||
|
'gh', 'issue', 'comment', str(issue_number), '--body', comment, '--repo', f'{owner}/{repo}'
|
||||||
|
], check=True)
|
||||||
|
|
||||||
|
def get_linked_issues(owner: str, repo: str, pr_number: int) -> List[int]:
|
||||||
|
"""Use GitHub CLI to retrieve linked issue numbers for a PR.
|
||||||
|
"""
|
||||||
|
|
||||||
|
query = """
|
||||||
|
query ($owner: String!, $repo: String!, $pr: Int!) {
|
||||||
|
repository(owner: $owner, name: $repo) {
|
||||||
|
pullRequest(number: $pr) {
|
||||||
|
closingIssuesReferences(first: 100) {
|
||||||
|
nodes {
|
||||||
|
number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = subprocess.run([
|
||||||
|
'gh', 'api', 'graphql',
|
||||||
|
'-F', f'owner={owner}',
|
||||||
|
'-F', f'repo={repo}',
|
||||||
|
'-F', f'pr={pr_number}',
|
||||||
|
'-f', f'query={query}',
|
||||||
|
'--jq', '.data.repository.pullRequest.closingIssuesReferences.nodes[].number'
|
||||||
|
], capture_output=True, text=True, check=True)
|
||||||
|
|
||||||
|
# Split output into lines and convert to integers
|
||||||
|
if result.stdout.strip():
|
||||||
|
return [int(num) for num in result.stdout.strip().split('\n')]
|
||||||
|
return []
|
||||||
|
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
print(f"Error fetching linked issues for PR #{pr_number}")
|
||||||
|
return []
|
||||||
112
.github/scripts/release-notes/process_release_notes.py
vendored
Normal file
112
.github/scripts/release-notes/process_release_notes.py
vendored
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import json
|
||||||
|
from typing import List, Tuple
|
||||||
|
|
||||||
|
def extract_jira_tickets(line: str) -> List[str]:
|
||||||
|
# Find all Jira tickets in format ABC-123 (with any prefix/suffix)
|
||||||
|
return re.findall(r'[A-Z]+-\d+', line)
|
||||||
|
|
||||||
|
def extract_pr_numbers(line: str) -> List[str]:
|
||||||
|
# Match PR numbers from GitHub format (#123)
|
||||||
|
return re.findall(r'#(\d+)', line)
|
||||||
|
|
||||||
|
def process_line(line: str) -> str:
|
||||||
|
"""Process a single line from release notes by removing Jira tickets, conventional commit prefixes and other common patterns.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
line: A single line from release notes
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Processed line with tickets and prefixes removed
|
||||||
|
|
||||||
|
Example:
|
||||||
|
>>> process_line("[ABC-123] feat(ui): Add new button")
|
||||||
|
"Add new button"
|
||||||
|
"""
|
||||||
|
original = line
|
||||||
|
|
||||||
|
# Remove Jira ticket patterns:
|
||||||
|
# line = re.sub(r'\[[A-Z]+-\d+\]', '', line) # [ABC-123] -> ""
|
||||||
|
# line = re.sub(r'[A-Z]+-\d+:\s', '', line) # ABC-123: -> ""
|
||||||
|
# line = re.sub(r'[A-Z]+-\d+\s-\s', '', line) # ABC-123 - -> ""
|
||||||
|
|
||||||
|
# Remove keywords and their variations
|
||||||
|
patterns = [
|
||||||
|
r'BACKPORT', # BACKPORT -> ""
|
||||||
|
r'[deps]:', # [deps]: -> ""
|
||||||
|
r'feat(?:\([^)]*\))?:', # feat: or feat(ui): -> ""
|
||||||
|
r'bug(?:\([^)]*\))?:', # bug: or bug(core): -> ""
|
||||||
|
r'ci(?:\([^)]*\))?:' # ci: or ci(workflow): -> ""
|
||||||
|
]
|
||||||
|
for pattern in patterns:
|
||||||
|
line = re.sub(pattern, '', line)
|
||||||
|
|
||||||
|
cleaned = line.strip()
|
||||||
|
if cleaned != original.strip():
|
||||||
|
print(f"Processed: {original.strip()} -> {cleaned}")
|
||||||
|
return cleaned
|
||||||
|
|
||||||
|
def process_file(input_file: str) -> Tuple[List[str], List[str], List[str]]:
|
||||||
|
jira_tickets: List[str] = []
|
||||||
|
pr_numbers: List[str] = []
|
||||||
|
processed_lines: List[str] = []
|
||||||
|
|
||||||
|
print("Processing file: ", input_file)
|
||||||
|
|
||||||
|
with open(input_file, 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
line = line.strip()
|
||||||
|
should_process = line and not line.endswith(':')
|
||||||
|
|
||||||
|
if should_process:
|
||||||
|
tickets = extract_jira_tickets(line)
|
||||||
|
jira_tickets.extend(tickets)
|
||||||
|
|
||||||
|
prs = extract_pr_numbers(line)
|
||||||
|
pr_numbers.extend(prs)
|
||||||
|
processed_lines.append(process_line(line))
|
||||||
|
else:
|
||||||
|
processed_lines.append(line)
|
||||||
|
|
||||||
|
|
||||||
|
# Remove duplicates while preserving order
|
||||||
|
jira_tickets = list(dict.fromkeys(jira_tickets))
|
||||||
|
pr_numbers = list(dict.fromkeys(pr_numbers))
|
||||||
|
|
||||||
|
print("Jira tickets:", ",".join(jira_tickets))
|
||||||
|
print("PR numbers:", ",".join(pr_numbers))
|
||||||
|
print("Finished processing file: ", input_file)
|
||||||
|
return jira_tickets, pr_numbers, processed_lines
|
||||||
|
|
||||||
|
def save_results(jira_tickets: List[str], pr_numbers: List[str], processed_lines: List[str],
|
||||||
|
jira_file: str = 'jira_tickets.txt',
|
||||||
|
pr_file: str = 'pr_numbers.txt',
|
||||||
|
processed_file: str = 'processed_notes.txt') -> None:
|
||||||
|
with open(jira_file, 'w') as f:
|
||||||
|
f.write('\n'.join(jira_tickets))
|
||||||
|
|
||||||
|
with open(pr_file, 'w') as f:
|
||||||
|
f.write('\n'.join(pr_numbers))
|
||||||
|
|
||||||
|
with open(processed_file, 'w') as f:
|
||||||
|
f.write('\n'.join(processed_lines))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
input_file = 'release_notes.txt'
|
||||||
|
jira_file = 'jira_tickets.txt'
|
||||||
|
pr_file = 'pr_numbers.txt'
|
||||||
|
processed_file = 'processed_notes.txt'
|
||||||
|
|
||||||
|
if len(sys.argv) >= 2:
|
||||||
|
input_file = sys.argv[1]
|
||||||
|
if len(sys.argv) >= 3:
|
||||||
|
jira_file = sys.argv[2]
|
||||||
|
if len(sys.argv) >= 4:
|
||||||
|
pr_file = sys.argv[3]
|
||||||
|
if len(sys.argv) >= 5:
|
||||||
|
processed_file = sys.argv[4]
|
||||||
|
|
||||||
|
jira_tickets, pr_numbers, processed_lines = process_file(input_file)
|
||||||
|
save_results(jira_tickets, pr_numbers, processed_lines, jira_file, pr_file, processed_file)
|
||||||
4
.github/scripts/release-notes/pyproject.toml
vendored
Normal file
4
.github/scripts/release-notes/pyproject.toml
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[project]
|
||||||
|
name = "release-notes-processor"
|
||||||
|
description = "Process GitHub release notes to clean up formatting and extract relevant IDs."
|
||||||
|
requires-python = ">=3.13"
|
||||||
30
.github/scripts/release-notes/test_linked_issues.py
vendored
Normal file
30
.github/scripts/release-notes/test_linked_issues.py
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import unittest
|
||||||
|
from linked_issues import get_linked_issues, create_linked_issue_comment
|
||||||
|
|
||||||
|
class TestLinkedIssues(unittest.TestCase):
|
||||||
|
def test_create_linked_issue_comment(self):
|
||||||
|
test_cases = [
|
||||||
|
("bitwarden", "android", "v2025.1.0", "https://github.com/bitwarden/android/releases/tag/v2025.1.0", [4696]),
|
||||||
|
("bitwarden", "android", "v2025.2.0", "https://github.com/bitwarden/android/releases/tag/v2025.2.0", [4809, 1, 2, 3]),
|
||||||
|
("bitwarden", "android", "v2025.3.0", "https://github.com/bitwarden/android/releases/tag/v2025.3.0", []),
|
||||||
|
]
|
||||||
|
|
||||||
|
for owner, repo, release_name, release_link, pr_numbers in test_cases:
|
||||||
|
with self.subTest(msg=f"Creating comment for issue in release {release_name}"):
|
||||||
|
comment = create_linked_issue_comment(owner, repo, release_name, release_link, pr_numbers)
|
||||||
|
print(comment + "\n")
|
||||||
|
|
||||||
|
def test_get_linked_issues(self):
|
||||||
|
test_cases = [
|
||||||
|
("bitwarden", "android", 4696, [4659]),
|
||||||
|
("bitwarden", "android", 4809, [])
|
||||||
|
]
|
||||||
|
|
||||||
|
for owner, repo, pr_id, expected_linked_issues in test_cases:
|
||||||
|
with self.subTest(msg=f"Testing PR #{pr_id} for {owner}/{repo}"):
|
||||||
|
result = get_linked_issues(owner, repo, pr_id)
|
||||||
|
self.assertEqual(sorted(result), sorted(expected_linked_issues))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
95
.github/scripts/release-notes/test_process_release_notes.py
vendored
Normal file
95
.github/scripts/release-notes/test_process_release_notes.py
vendored
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
import unittest
|
||||||
|
import tempfile
|
||||||
|
import os
|
||||||
|
from process_release_notes import extract_jira_tickets, extract_pr_numbers, process_line, process_file, get_linked_issues
|
||||||
|
|
||||||
|
class TestProcessReleaseNotes(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.test_file = tempfile.NamedTemporaryFile(delete=False)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
os.unlink(self.test_file.name)
|
||||||
|
|
||||||
|
def test_extract_jira_tickets(self):
|
||||||
|
test_cases = [
|
||||||
|
("[ABC-123] Some text", ["ABC-123"]),
|
||||||
|
("DEF-456: Some text", ["DEF-456"]),
|
||||||
|
("GHI-789 - Some text", ["GHI-789"]),
|
||||||
|
("Multiple [ABC-123] and DEF-456: tickets", ["ABC-123", "DEF-456"]),
|
||||||
|
("No tickets here", []),
|
||||||
|
("Mixed formats ABC-123 [DEF-456] GHI-789:", ["ABC-123", "DEF-456", "GHI-789"])
|
||||||
|
]
|
||||||
|
for input_text, expected in test_cases:
|
||||||
|
with self.subTest(input_text=input_text):
|
||||||
|
result = extract_jira_tickets(input_text)
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
def test_extract_pr_numbers(self):
|
||||||
|
test_cases = [
|
||||||
|
("PR #123 text", ["123"]),
|
||||||
|
("Multiple PRs #456 and #789", ["456", "789"]),
|
||||||
|
("No PR numbers", [])
|
||||||
|
]
|
||||||
|
for input_text, expected in test_cases:
|
||||||
|
with self.subTest(input_text=input_text):
|
||||||
|
result = extract_pr_numbers(input_text)
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
def test_process_line(self):
|
||||||
|
test_cases = [
|
||||||
|
("[ABC-123] BACKPORT Some text", "Some text"),
|
||||||
|
("DEF-456: feat(component): Some text", "Some text"),
|
||||||
|
("GHI-789 - bug(fix): Some text", "Some text"),
|
||||||
|
("ci: Some text", "Some text"),
|
||||||
|
("ci(workflow): Some text", "Some text"),
|
||||||
|
("feat: Direct feature", "Direct feature"),
|
||||||
|
("bug: Simple bugfix", "Simple bugfix"),
|
||||||
|
("Normal text", "Normal text")
|
||||||
|
]
|
||||||
|
for input_text, expected in test_cases:
|
||||||
|
with self.subTest(input_text=input_text):
|
||||||
|
result = process_line(input_text)
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
def test_process_file(self):
|
||||||
|
content = """
|
||||||
|
### Features:
|
||||||
|
[ABC-123] feat(comp): Feature 1 #123
|
||||||
|
DEF-456: bug(fix): Bug fix #456
|
||||||
|
GHI-789 - BACKPORT Some text #789
|
||||||
|
|
||||||
|
### Bug Fixes:
|
||||||
|
Another line without changes
|
||||||
|
"""
|
||||||
|
with open(self.test_file.name, 'w') as f:
|
||||||
|
f.write(content)
|
||||||
|
|
||||||
|
jira_tickets, pr_numbers, processed_lines = process_file(self.test_file.name)
|
||||||
|
|
||||||
|
self.assertEqual(jira_tickets, ["ABC-123", "DEF-456", "GHI-789"])
|
||||||
|
self.assertEqual(pr_numbers, ["123", "456", "789"])
|
||||||
|
self.assertEqual(processed_lines, [
|
||||||
|
'',
|
||||||
|
'### Features:',
|
||||||
|
'Feature 1 #123',
|
||||||
|
'Bug fix #456',
|
||||||
|
'Some text #789',
|
||||||
|
'',
|
||||||
|
'### Bug Fixes:',
|
||||||
|
'Another line without changes'
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_get_linked_issues(self):
|
||||||
|
test_cases = [
|
||||||
|
("bitwarden", "android", 4696, [4659]),
|
||||||
|
("bitwarden", "android", 4809, [])
|
||||||
|
]
|
||||||
|
|
||||||
|
for owner, repo, pr_id, expected_linked_issues in test_cases:
|
||||||
|
with self.subTest(msg=f"Testing PR #{pr_id} for {owner}/{repo}"):
|
||||||
|
result = get_linked_issues(owner, repo, pr_id)
|
||||||
|
self.assertEqual(sorted(result), sorted(expected_linked_issues))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
@@ -1 +0,0 @@
|
|||||||
3.13
|
|
||||||
39
.github/scripts/validate-json/README.md
vendored
39
.github/scripts/validate-json/README.md
vendored
@@ -1,39 +0,0 @@
|
|||||||
# JSON Validation Scripts
|
|
||||||
|
|
||||||
Utility scripts for validating JSON files and checking for duplicate package names between Google and Community privileged browser lists.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### Validate a JSON file
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python validate_json.py validate <json_file>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Check for duplicates between two JSON files
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python validate_json.py duplicates <json_file1> <json_file2> [output_file]
|
|
||||||
```
|
|
||||||
|
|
||||||
If `output_file` is not specified, duplicates will be saved to `duplicates.txt`.
|
|
||||||
|
|
||||||
## Running Tests
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Run all tests
|
|
||||||
python -m unittest test_validate_json.py
|
|
||||||
|
|
||||||
# Run the invalid JSON test individually
|
|
||||||
python -m unittest test_validate_json.TestValidateJson.test_validate_json_invalid
|
|
||||||
```
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Validate Google privileged browsers list
|
|
||||||
python validate_json.py validate ../../app/src/main/assets/fido2_privileged_google.json
|
|
||||||
|
|
||||||
# Check for duplicates between Google and Community lists
|
|
||||||
python validate_json.py duplicates ../../app/src/main/assets/fido2_privileged_google.json ../../app/src/main/assets/fido2_privileged_community.json duplicates.txt
|
|
||||||
```
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"apps": [
|
|
||||||
|
|
||||||
"type": "android",
|
|
||||||
"info": {
|
|
||||||
"package_name": "com.android.chrome",
|
|
||||||
"signatures": [
|
|
||||||
{
|
|
||||||
"build": "release",
|
|
||||||
"cert_fingerprint_sha256": "F0:FD:6C:5B:41:0F:25:CB:25:C3:B5:33:46:C8:97:2F:AE:30:F8:EE:74:11:DF:91:04:80:AD:6B:2D:60:DB:83"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"build": "userdebug",
|
|
||||||
"cert_fingerprint_sha256": "19:75:B2:F1:71:77:BC:89:A5:DF:F3:1F:9E:64:A6:CA:E2:81:A5:3D:C1:D1:D5:9B:1D:14:7F:E1:C8:2A:FA:00"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
{
|
|
||||||
"apps": [
|
|
||||||
{
|
|
||||||
"type": "android",
|
|
||||||
"info": {
|
|
||||||
"package_name": "com.android.chrome",
|
|
||||||
"signatures": [
|
|
||||||
{
|
|
||||||
"build": "release",
|
|
||||||
"cert_fingerprint_sha256": "F0:FD:6C:5B:41:0F:25:CB:25:C3:B5:33:46:C8:97:2F:AE:30:F8:EE:74:11:DF:91:04:80:AD:6B:2D:60:DB:83"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"build": "userdebug",
|
|
||||||
"cert_fingerprint_sha256": "19:75:B2:F1:71:77:BC:89:A5:DF:F3:1F:9E:64:A6:CA:E2:81:A5:3D:C1:D1:D5:9B:1D:14:7F:E1:C8:2A:FA:00"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "android",
|
|
||||||
"info": {
|
|
||||||
"package_name": "com.chrome.dev",
|
|
||||||
"signatures": [
|
|
||||||
{
|
|
||||||
"build": "release",
|
|
||||||
"cert_fingerprint_sha256": "90:44:EE:5F:EE:4B:BC:5E:21:DD:44:66:54:31:C4:EB:1F:1F:71:A3:27:16:A0:BC:92:7B:CB:B3:92:33:CA:BF"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"build": "release",
|
|
||||||
"cert_fingerprint_sha256": "3D:7A:12:23:01:9A:A3:9D:9E:A0:E3:43:6A:B7:C0:89:6B:FB:4F:B6:79:F4:DE:5F:E7:C2:3F:32:6C:8F:99:4A"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "android",
|
|
||||||
"info": {
|
|
||||||
"package_name": "com.chrome.canary",
|
|
||||||
"signatures": [
|
|
||||||
{
|
|
||||||
"build": "release",
|
|
||||||
"cert_fingerprint_sha256": "DF:A1:FB:23:EF:BF:70:C5:BC:D1:44:3C:5B:EA:B0:4F:3F:2F:F4:36:6E:9A:C1:E3:45:76:39:A2:4C:FC"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"apps": [
|
|
||||||
{
|
|
||||||
"type": "android",
|
|
||||||
"info": {
|
|
||||||
"package_name": "org.chromium.chrome",
|
|
||||||
"signatures": [
|
|
||||||
{
|
|
||||||
"build": "release",
|
|
||||||
"cert_fingerprint_sha256": "C6:AD:B8:B8:3C:6D:4C:17:D2:92:AF:DE:56:FD:48:8A:51:D3:16:FF:8F:2C:11:C5:41:02:23:BF:F8:A7:DB:B3"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"build": "userdebug",
|
|
||||||
"cert_fingerprint_sha256": "19:75:B2:F1:71:77:BC:89:A5:DF:F3:1F:9E:64:A6:CA:E2:81:A5:3D:C1:D1:D5:9B:1D:14:7F:E1:C8:2A:FA:00"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
import unittest
|
|
||||||
import os
|
|
||||||
import json
|
|
||||||
from validate_json import validate_json, find_duplicates, get_package_names
|
|
||||||
from unittest.mock import patch
|
|
||||||
import io
|
|
||||||
|
|
||||||
|
|
||||||
class TestValidateJson(unittest.TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.valid_file = os.path.join(os.path.dirname(__file__), "fixtures/sample-valid1.json")
|
|
||||||
self.valid_file2 = os.path.join(os.path.dirname(__file__), "fixtures/sample-valid2.json")
|
|
||||||
self.invalid_file = os.path.join(os.path.dirname(__file__), "fixtures/sample-invalid.json")
|
|
||||||
|
|
||||||
# Suppress stdout
|
|
||||||
self.stdout_patcher = patch('sys.stdout', new=io.StringIO())
|
|
||||||
self.stdout_patcher.start()
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
self.stdout_patcher.stop()
|
|
||||||
|
|
||||||
def test_validate_json_valid(self):
|
|
||||||
"""Test validation of valid JSON file"""
|
|
||||||
self.assertTrue(validate_json(self.valid_file))
|
|
||||||
|
|
||||||
def test_validate_json_invalid(self):
|
|
||||||
"""Test validation of invalid JSON file"""
|
|
||||||
self.assertFalse(validate_json(self.invalid_file))
|
|
||||||
|
|
||||||
def test_find_duplicates(self):
|
|
||||||
"""Test when using the same file (should find duplicates)"""
|
|
||||||
expected_package_names = get_package_names(self.valid_file)
|
|
||||||
|
|
||||||
duplicates = find_duplicates(self.valid_file, self.valid_file)
|
|
||||||
|
|
||||||
self.assertEqual(len(duplicates), len(expected_package_names))
|
|
||||||
for package_name in expected_package_names:
|
|
||||||
self.assertIn(package_name, duplicates)
|
|
||||||
|
|
||||||
def test_find_duplicates_returns_empty_list_when_no_duplicates(self):
|
|
||||||
"""Test when using different files (should not find duplicates)"""
|
|
||||||
duplicates = find_duplicates(self.valid_file, self.valid_file2)
|
|
||||||
self.assertEqual(len(duplicates), 0)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
unittest.main()
|
|
||||||
145
.github/scripts/validate-json/validate_json.py
vendored
145
.github/scripts/validate-json/validate_json.py
vendored
@@ -1,145 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
import json
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
from typing import List, Dict, Any, Set
|
|
||||||
|
|
||||||
|
|
||||||
def get_package_names(file_path: str) -> Set[str]:
|
|
||||||
"""
|
|
||||||
Extracts package names from a JSON file.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
file_path: Path to the JSON file
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Set of package names
|
|
||||||
"""
|
|
||||||
with open(file_path, 'r') as f:
|
|
||||||
data = json.load(f)
|
|
||||||
|
|
||||||
package_names = set()
|
|
||||||
for app in data["apps"]:
|
|
||||||
package_names.add(app["info"]["package_name"])
|
|
||||||
|
|
||||||
return package_names
|
|
||||||
|
|
||||||
|
|
||||||
def validate_json(file_path: str) -> bool:
|
|
||||||
"""
|
|
||||||
Validates if a JSON file is correctly formatted by attempting to deserialize it.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
file_path: Path to the JSON file to validate
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
True if valid, False otherwise
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
if not os.path.exists(file_path):
|
|
||||||
print(f"Error: File {file_path} does not exist")
|
|
||||||
return False
|
|
||||||
|
|
||||||
with open(file_path, 'r') as f:
|
|
||||||
json.load(f)
|
|
||||||
print(f"✅ JSON file {file_path} is valid")
|
|
||||||
return True
|
|
||||||
except json.JSONDecodeError as e:
|
|
||||||
print(f"❌ Invalid JSON in {file_path}: {str(e)}")
|
|
||||||
return False
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ Error validating {file_path}: {str(e)}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def find_duplicates(file1_path: str, file2_path: str) -> List[str]:
|
|
||||||
"""
|
|
||||||
Checks for duplicate package_name entries between two JSON files.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
file1_path: Path to the first JSON file
|
|
||||||
file2_path: Path to the second JSON file
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
List of duplicate package names, empty list if none found
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
# Get package names from both files
|
|
||||||
packages1 = get_package_names(file1_path)
|
|
||||||
packages2 = get_package_names(file2_path)
|
|
||||||
|
|
||||||
# Find duplicates
|
|
||||||
duplicates = list(packages1.intersection(packages2))
|
|
||||||
|
|
||||||
if duplicates:
|
|
||||||
print(f"❌ Found {len(duplicates)} duplicate package names between {file1_path} and {file2_path}:")
|
|
||||||
for dup in duplicates:
|
|
||||||
print(f" - {dup}")
|
|
||||||
return duplicates
|
|
||||||
else:
|
|
||||||
print(f"✅ No duplicate package names found between {file1_path} and {file2_path}")
|
|
||||||
return []
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ Error checking duplicates: {str(e)}")
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
|
||||||
def save_duplicates_to_file(duplicates: List[str], output_file: str) -> None:
|
|
||||||
"""
|
|
||||||
Saves the list of duplicates to a file.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
duplicates: List of duplicate package names
|
|
||||||
output_file: Path to save the list of duplicates
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
with open(output_file, 'w') as f:
|
|
||||||
for dup in duplicates:
|
|
||||||
f.write(f"{dup}\n")
|
|
||||||
print(f"Duplicates saved to {output_file}")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ Error saving duplicates to file: {str(e)}")
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
if len(sys.argv) < 2:
|
|
||||||
print("Usage:")
|
|
||||||
print(" Validate JSON: python validate_json.py validate <json_file>")
|
|
||||||
print(" Check duplicates: python validate_json.py duplicates <json_file1> <json_file2> [output_file]")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
command = sys.argv[1]
|
|
||||||
|
|
||||||
match command:
|
|
||||||
case "validate":
|
|
||||||
if len(sys.argv) < 3:
|
|
||||||
print("Error: Missing JSON file path")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
file_path = sys.argv[2]
|
|
||||||
success = validate_json(file_path)
|
|
||||||
sys.exit(0 if success else 1)
|
|
||||||
|
|
||||||
case "duplicates":
|
|
||||||
if len(sys.argv) < 4:
|
|
||||||
print("Error: Missing JSON file paths")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
file1_path = sys.argv[2]
|
|
||||||
file2_path = sys.argv[3]
|
|
||||||
output_file = sys.argv[4] if len(sys.argv) > 4 else "duplicates.txt"
|
|
||||||
|
|
||||||
duplicates = find_duplicates(file1_path, file2_path)
|
|
||||||
if duplicates:
|
|
||||||
save_duplicates_to_file(duplicates, output_file)
|
|
||||||
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
case _:
|
|
||||||
print(f"Unknown command: {command}")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
2
.github/workflows/build-authenticator.yml
vendored
2
.github/workflows/build-authenticator.yml
vendored
@@ -78,7 +78,7 @@ jobs:
|
|||||||
bundle install --jobs 4 --retry 3
|
bundle install --jobs 4 --retry 3
|
||||||
|
|
||||||
- name: Check Authenticator
|
- name: Check Authenticator
|
||||||
run: bundle exec fastlane check
|
run: bundle exec fastlane checkAuthenticator
|
||||||
|
|
||||||
- name: Build Authenticator
|
- name: Build Authenticator
|
||||||
run: bundle exec fastlane buildAuthenticatorDebug
|
run: bundle exec fastlane buildAuthenticatorDebug
|
||||||
|
|||||||
@@ -1,98 +0,0 @@
|
|||||||
name: Cron / Sync Google Privileged Browsers List
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
# Run weekly on Monday at 00:00 UTC
|
|
||||||
- cron: '0 0 * * 1'
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
env:
|
|
||||||
SOURCE_URL: https://www.gstatic.com/gpm-passkeys-privileged-apps/apps.json
|
|
||||||
GOOGLE_FILE: app/src/main/assets/fido2_privileged_google.json
|
|
||||||
COMMUNITY_FILE: app/src/main/assets/fido2_privileged_community.json
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
sync-privileged-browsers:
|
|
||||||
name: Sync Google Privileged Browsers List
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2
|
|
||||||
|
|
||||||
- name: Download Google Privileged Browsers List
|
|
||||||
run: curl -s $SOURCE_URL -o $GOOGLE_FILE
|
|
||||||
|
|
||||||
- name: Check for changes
|
|
||||||
id: check-changes
|
|
||||||
run: |
|
|
||||||
if git diff --quiet -- $GOOGLE_FILE; then
|
|
||||||
echo "👀 No changes detected, skipping..."
|
|
||||||
echo "has_changes=false" >> $GITHUB_OUTPUT
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "has_changes=true" >> $GITHUB_OUTPUT
|
|
||||||
echo "👀 Changes detected, validating fido2_privileged_google.json..."
|
|
||||||
|
|
||||||
python .github/scripts/validate-json/validate_json.py validate $GOOGLE_FILE
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "::error::JSON validation failed for $GOOGLE_FILE"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "👀 fido2_privileged_google.json is valid, checking for duplicates..."
|
|
||||||
|
|
||||||
# Check for duplicates between Google and Community files
|
|
||||||
python .github/scripts/validate-json/validate_json.py duplicates $GOOGLE_FILE $COMMUNITY_FILE duplicates.txt
|
|
||||||
|
|
||||||
if [ -f duplicates.txt ]; then
|
|
||||||
echo "::warning::Duplicate package names found between Google and Community files."
|
|
||||||
echo "duplicates_found=true" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo "✅ No duplicate package names found between Google and Community files"
|
|
||||||
echo "duplicates_found=false" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Create branch and commit
|
|
||||||
if: steps.check-changes.outputs.has_changes == 'true'
|
|
||||||
run: |
|
|
||||||
echo "👀 Committing fido2_privileged_google.json..."
|
|
||||||
|
|
||||||
BRANCH_NAME="cron-sync-privileged-browsers/$GITHUB_RUN_NUMBER-sync"
|
|
||||||
git config user.name "GitHub Actions Bot"
|
|
||||||
git config user.email "actions@github.com"
|
|
||||||
git checkout -b $BRANCH_NAME
|
|
||||||
git add $GOOGLE_FILE
|
|
||||||
git commit -m "Update Google privileged browsers list"
|
|
||||||
git push origin $BRANCH_NAME
|
|
||||||
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
|
|
||||||
echo "🌱 Branch created: $BRANCH_NAME"
|
|
||||||
|
|
||||||
- name: Create Pull Request
|
|
||||||
if: steps.check-changes.outputs.has_changes == 'true'
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
DUPLICATES_FOUND: ${{ steps.check-changes.outputs.duplicates_found }}
|
|
||||||
BASE_PR_URL: ${{ github.server_url }}/${{ github.repository }}/pull/
|
|
||||||
run: |
|
|
||||||
PR_BODY="Updates the Google privileged browsers list with the latest data from $SOURCE_URL"
|
|
||||||
|
|
||||||
if [ "$DUPLICATES_FOUND" = "true" ]; then
|
|
||||||
PR_BODY="$PR_BODY\n\n> [!WARNING]\n> :suspect: The following package(s) appear in both Google and Community files:"
|
|
||||||
while IFS= read -r line; do
|
|
||||||
PR_BODY="$PR_BODY\n> - $line"
|
|
||||||
done < duplicates.txt
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Use echo -e to interpret escape sequences and pipe to gh pr create
|
|
||||||
PR_URL=$(echo -e "$PR_BODY" | gh pr create \
|
|
||||||
--title "Update Google privileged browsers list" \
|
|
||||||
--body-file - \
|
|
||||||
--base main \
|
|
||||||
--head $BRANCH_NAME \
|
|
||||||
--label "automated-pr" \
|
|
||||||
--label "t:ci")
|
|
||||||
76
.github/workflows/scan-authenticator.yml
vendored
Normal file
76
.github/workflows/scan-authenticator.yml
vendored
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
name: Scan Authenticator
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "main"
|
||||||
|
- "rc"
|
||||||
|
- "hotfix-rc"
|
||||||
|
pull_request_target:
|
||||||
|
types: [opened, synchronize]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-run:
|
||||||
|
name: Check PR run
|
||||||
|
uses: bitwarden/gh-actions/.github/workflows/check-run.yml@main
|
||||||
|
|
||||||
|
sast:
|
||||||
|
name: SAST scan
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
needs: check-run
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Check out repo
|
||||||
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
|
|
||||||
|
- name: Scan with Checkmarx
|
||||||
|
uses: checkmarx/ast-github-action@184bf2f64f55d1c93fd6636d539edf274703e434 # 2.0.41
|
||||||
|
env:
|
||||||
|
INCREMENTAL: "${{ contains(github.event_name, 'pull_request') && '--sast-incremental' || '' }}"
|
||||||
|
with:
|
||||||
|
project_name: ${{ github.repository }}
|
||||||
|
cx_tenant: ${{ secrets.CHECKMARX_TENANT }}
|
||||||
|
base_uri: https://ast.checkmarx.net/
|
||||||
|
cx_client_id: ${{ secrets.CHECKMARX_CLIENT_ID }}
|
||||||
|
cx_client_secret: ${{ secrets.CHECKMARX_SECRET }}
|
||||||
|
additional_params: |
|
||||||
|
--report-format sarif \
|
||||||
|
--filter "state=TO_VERIFY;PROPOSED_NOT_EXPLOITABLE;CONFIRMED;URGENT" \
|
||||||
|
--output-path . ${{ env.INCREMENTAL }}
|
||||||
|
|
||||||
|
- name: Upload Checkmarx results to GitHub
|
||||||
|
uses: github/codeql-action/upload-sarif@d68b2d4edb4189fd2a5366ac14e72027bd4b37dd # v3.28.2
|
||||||
|
with:
|
||||||
|
sarif_file: cx_result.sarif
|
||||||
|
|
||||||
|
quality:
|
||||||
|
name: Quality scan
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
needs: check-run
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Check out repo
|
||||||
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
|
|
||||||
|
- name: Scan with SonarCloud
|
||||||
|
uses: sonarsource/sonarqube-scan-action@bfd4e558cda28cda6b5defafb9232d191be8c203 # v4.2.1
|
||||||
|
env:
|
||||||
|
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||||
|
with:
|
||||||
|
args: >
|
||||||
|
-Dsonar.organization=${{ github.repository_owner }}
|
||||||
|
-Dsonar.projectKey=${{ github.repository_owner }}_${{ github.event.repository.name }}
|
||||||
|
-Dsonar.pullrequest.key=${{ github.event.pull_request.number }}
|
||||||
1
.github/workflows/scan-ci.yml
vendored
1
.github/workflows/scan-ci.yml
vendored
@@ -58,3 +58,4 @@ jobs:
|
|||||||
args: >
|
args: >
|
||||||
-Dsonar.organization=${{ github.repository_owner }}
|
-Dsonar.organization=${{ github.repository_owner }}
|
||||||
-Dsonar.projectKey=${{ github.repository_owner }}_${{ github.event.repository.name }}
|
-Dsonar.projectKey=${{ github.repository_owner }}_${{ github.event.repository.name }}
|
||||||
|
-Dsonar.pullrequest.key=${{ github.event.pull_request.number }}
|
||||||
|
|||||||
2
.github/workflows/scan.yml
vendored
2
.github/workflows/scan.yml
vendored
@@ -44,8 +44,6 @@ jobs:
|
|||||||
uses: github/codeql-action/upload-sarif@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1
|
uses: github/codeql-action/upload-sarif@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1
|
||||||
with:
|
with:
|
||||||
sarif_file: cx_result.sarif
|
sarif_file: cx_result.sarif
|
||||||
sha: ${{ contains(github.event_name, 'pull_request') && github.event.pull_request.head.sha || github.sha }}
|
|
||||||
ref: ${{ contains(github.event_name, 'pull_request') && format('refs/pull/{0}/head', github.event.pull_request.number) || github.ref }}
|
|
||||||
|
|
||||||
quality:
|
quality:
|
||||||
name: Quality scan
|
name: Quality scan
|
||||||
|
|||||||
82
.github/workflows/test-authenticator.yml
vendored
Normal file
82
.github/workflows/test-authenticator.yml
vendored
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
name: Test Authenticator
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "main"
|
||||||
|
- "rc"
|
||||||
|
- "hotfix-rc"
|
||||||
|
pull_request_target:
|
||||||
|
types: [opened, synchronize]
|
||||||
|
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
JAVA_VERSION: 17
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-run:
|
||||||
|
name: Check PR run
|
||||||
|
uses: bitwarden/gh-actions/.github/workflows/check-run.yml@main
|
||||||
|
|
||||||
|
test:
|
||||||
|
name: Test
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
needs: check-run
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: read
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Check out repo
|
||||||
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
|
|
||||||
|
- name: Validate Gradle wrapper
|
||||||
|
uses: gradle/actions/wrapper-validation@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2
|
||||||
|
|
||||||
|
- name: Cache Gradle files
|
||||||
|
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.gradle/caches
|
||||||
|
~/.gradle/wrapper
|
||||||
|
key: ${{ runner.os }}-gradle-v2-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', '**/libs.versions.toml') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-gradle-v2-
|
||||||
|
|
||||||
|
- name: Cache build output
|
||||||
|
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
${{ github.workspace }}/build-cache
|
||||||
|
key: ${{ runner.os }}-build-cache-${{ github.sha }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-build-
|
||||||
|
|
||||||
|
- name: Configure Ruby
|
||||||
|
uses: ruby/setup-ruby@28c4deda893d5a96a6b2d958c5b47fc18d65c9d3 # v1.213.0
|
||||||
|
with:
|
||||||
|
bundler-cache: true
|
||||||
|
|
||||||
|
- name: Configure JDK
|
||||||
|
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0
|
||||||
|
with:
|
||||||
|
distribution: "temurin"
|
||||||
|
java-version: ${{ env.JAVA_VERSION }}
|
||||||
|
|
||||||
|
- name: Install Fastlane
|
||||||
|
run: |
|
||||||
|
gem install bundler:2.2.27
|
||||||
|
bundle config path vendor/bundle
|
||||||
|
bundle install --jobs 4 --retry 3
|
||||||
|
|
||||||
|
- name: Build and test Authenticator
|
||||||
|
run: |
|
||||||
|
bundle exec fastlane checkAuthenticator
|
||||||
|
|
||||||
|
- name: Upload to codecov.io
|
||||||
|
uses: codecov/codecov-action@1e68e06f1dbfde0e4cefc87efeba9e4643565303 # v5.1.2
|
||||||
|
with:
|
||||||
|
files: authenticator/build/reports/kover/reportDebug.xml
|
||||||
29
.github/workflows/test.yml
vendored
29
.github/workflows/test.yml
vendored
@@ -23,7 +23,6 @@ jobs:
|
|||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
packages: read
|
packages: read
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out repo
|
- name: Check out repo
|
||||||
@@ -80,14 +79,25 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: test-reports
|
name: test-reports
|
||||||
path: |
|
path: |
|
||||||
build/reports/kover/reportMergedCoverage.xml
|
|
||||||
app/build/reports/tests/
|
app/build/reports/tests/
|
||||||
authenticator/build/reports/tests/
|
app/build/reports/kover/reportStandardDebug.xml
|
||||||
authenticatorbridge/build/reports/tests/
|
|
||||||
core/build/reports/tests/
|
report:
|
||||||
data/build/reports/tests/
|
name: Process Test Reports
|
||||||
network/build/reports/tests/
|
needs: test
|
||||||
ui/build/reports/tests/
|
runs-on: ubuntu-24.04
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
|
if: success()
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Download test artifacts
|
||||||
|
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
||||||
|
if: github.event_name == 'push' || github.event_name == 'pull_request'
|
||||||
|
with:
|
||||||
|
name: test-reports
|
||||||
|
|
||||||
- name: Upload to codecov.io
|
- name: Upload to codecov.io
|
||||||
id: upload-to-codecov
|
id: upload-to-codecov
|
||||||
@@ -96,9 +106,8 @@ jobs:
|
|||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
os: linux
|
os: linux
|
||||||
files: build/reports/kover/reportMergedCoverage.xml
|
files: kover/reportStandardDebug.xml
|
||||||
fail_ci_if_error: true
|
fail_ci_if_error: true
|
||||||
disable_search: true
|
|
||||||
|
|
||||||
- name: Comment PR if tests failed
|
- name: Comment PR if tests failed
|
||||||
if: steps.upload-to-codecov.outcome == 'failure' && (github.event_name == 'push' || github.event_name == 'pull_request')
|
if: steps.upload-to-codecov.outcome == 'failure' && (github.event_name == 'push' || github.event_name == 'pull_request')
|
||||||
|
|||||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -29,9 +29,8 @@ user.properties
|
|||||||
/app/src/standardRelease/google-services.json
|
/app/src/standardRelease/google-services.json
|
||||||
/authenticator/src/google-services.json
|
/authenticator/src/google-services.json
|
||||||
|
|
||||||
# Python
|
# python
|
||||||
.python-version
|
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
# Generated by .github/scripts/validate-json/validate-json.py
|
*$py.class
|
||||||
duplicates.txt
|
*.so
|
||||||
|
|||||||
35
Gemfile.lock
35
Gemfile.lock
@@ -9,19 +9,17 @@ GEM
|
|||||||
public_suffix (>= 2.0.2, < 7.0)
|
public_suffix (>= 2.0.2, < 7.0)
|
||||||
artifactory (3.0.17)
|
artifactory (3.0.17)
|
||||||
atomos (0.1.3)
|
atomos (0.1.3)
|
||||||
aws-eventstream (1.3.2)
|
aws-eventstream (1.3.0)
|
||||||
aws-partitions (1.1084.0)
|
aws-partitions (1.1040.0)
|
||||||
aws-sdk-core (3.222.1)
|
aws-sdk-core (3.216.0)
|
||||||
aws-eventstream (~> 1, >= 1.3.0)
|
aws-eventstream (~> 1, >= 1.3.0)
|
||||||
aws-partitions (~> 1, >= 1.992.0)
|
aws-partitions (~> 1, >= 1.992.0)
|
||||||
aws-sigv4 (~> 1.9)
|
aws-sigv4 (~> 1.9)
|
||||||
base64
|
|
||||||
jmespath (~> 1, >= 1.6.1)
|
jmespath (~> 1, >= 1.6.1)
|
||||||
logger
|
aws-sdk-kms (1.97.0)
|
||||||
aws-sdk-kms (1.99.0)
|
|
||||||
aws-sdk-core (~> 3, >= 3.216.0)
|
aws-sdk-core (~> 3, >= 3.216.0)
|
||||||
aws-sigv4 (~> 1.5)
|
aws-sigv4 (~> 1.5)
|
||||||
aws-sdk-s3 (1.183.0)
|
aws-sdk-s3 (1.178.0)
|
||||||
aws-sdk-core (~> 3, >= 3.216.0)
|
aws-sdk-core (~> 3, >= 3.216.0)
|
||||||
aws-sdk-kms (~> 1)
|
aws-sdk-kms (~> 1)
|
||||||
aws-sigv4 (~> 1.5)
|
aws-sigv4 (~> 1.5)
|
||||||
@@ -36,7 +34,7 @@ GEM
|
|||||||
highline (~> 2.0.0)
|
highline (~> 2.0.0)
|
||||||
date (3.4.1)
|
date (3.4.1)
|
||||||
declarative (0.0.20)
|
declarative (0.0.20)
|
||||||
digest-crc (0.7.0)
|
digest-crc (0.6.5)
|
||||||
rake (>= 12.0.0, < 14.0.0)
|
rake (>= 12.0.0, < 14.0.0)
|
||||||
domain_name (0.6.20240107)
|
domain_name (0.6.20240107)
|
||||||
dotenv (2.8.1)
|
dotenv (2.8.1)
|
||||||
@@ -71,7 +69,7 @@ GEM
|
|||||||
faraday_middleware (1.2.1)
|
faraday_middleware (1.2.1)
|
||||||
faraday (~> 1.0)
|
faraday (~> 1.0)
|
||||||
fastimage (2.4.0)
|
fastimage (2.4.0)
|
||||||
fastlane (2.227.1)
|
fastlane (2.226.0)
|
||||||
CFPropertyList (>= 2.3, < 4.0.0)
|
CFPropertyList (>= 2.3, < 4.0.0)
|
||||||
addressable (>= 2.8, < 3.0.0)
|
addressable (>= 2.8, < 3.0.0)
|
||||||
artifactory (~> 3.0)
|
artifactory (~> 3.0)
|
||||||
@@ -111,7 +109,7 @@ GEM
|
|||||||
tty-spinner (>= 0.8.0, < 1.0.0)
|
tty-spinner (>= 0.8.0, < 1.0.0)
|
||||||
word_wrap (~> 1.0.0)
|
word_wrap (~> 1.0.0)
|
||||||
xcodeproj (>= 1.13.0, < 2.0.0)
|
xcodeproj (>= 1.13.0, < 2.0.0)
|
||||||
xcpretty (~> 0.4.1)
|
xcpretty (~> 0.4.0)
|
||||||
xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
|
xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
|
||||||
fastlane-plugin-firebase_app_distribution (0.10.0)
|
fastlane-plugin-firebase_app_distribution (0.10.0)
|
||||||
google-apis-firebaseappdistribution_v1 (~> 0.3.0)
|
google-apis-firebaseappdistribution_v1 (~> 0.3.0)
|
||||||
@@ -139,12 +137,12 @@ GEM
|
|||||||
google-apis-core (>= 0.11.0, < 2.a)
|
google-apis-core (>= 0.11.0, < 2.a)
|
||||||
google-apis-storage_v1 (0.31.0)
|
google-apis-storage_v1 (0.31.0)
|
||||||
google-apis-core (>= 0.11.0, < 2.a)
|
google-apis-core (>= 0.11.0, < 2.a)
|
||||||
google-cloud-core (1.8.0)
|
google-cloud-core (1.7.1)
|
||||||
google-cloud-env (>= 1.0, < 3.a)
|
google-cloud-env (>= 1.0, < 3.a)
|
||||||
google-cloud-errors (~> 1.0)
|
google-cloud-errors (~> 1.0)
|
||||||
google-cloud-env (1.6.0)
|
google-cloud-env (1.6.0)
|
||||||
faraday (>= 0.17.3, < 3.0)
|
faraday (>= 0.17.3, < 3.0)
|
||||||
google-cloud-errors (1.5.0)
|
google-cloud-errors (1.4.0)
|
||||||
google-cloud-storage (1.47.0)
|
google-cloud-storage (1.47.0)
|
||||||
addressable (~> 2.8)
|
addressable (~> 2.8)
|
||||||
digest-crc (~> 0.4)
|
digest-crc (~> 0.4)
|
||||||
@@ -162,18 +160,15 @@ GEM
|
|||||||
highline (2.0.3)
|
highline (2.0.3)
|
||||||
http-cookie (1.0.8)
|
http-cookie (1.0.8)
|
||||||
domain_name (~> 0.5)
|
domain_name (~> 0.5)
|
||||||
httpclient (2.9.0)
|
httpclient (2.8.3)
|
||||||
mutex_m
|
|
||||||
jmespath (1.6.2)
|
jmespath (1.6.2)
|
||||||
json (2.10.2)
|
json (2.9.1)
|
||||||
jwt (2.10.1)
|
jwt (2.10.1)
|
||||||
base64
|
base64
|
||||||
logger (1.7.0)
|
|
||||||
mini_magick (4.13.2)
|
mini_magick (4.13.2)
|
||||||
mini_mime (1.1.5)
|
mini_mime (1.1.5)
|
||||||
multi_json (1.15.0)
|
multi_json (1.15.0)
|
||||||
multipart-post (2.4.1)
|
multipart-post (2.4.1)
|
||||||
mutex_m (0.3.0)
|
|
||||||
nanaimo (0.4.0)
|
nanaimo (0.4.0)
|
||||||
naturally (2.2.1)
|
naturally (2.2.1)
|
||||||
nkf (0.2.0)
|
nkf (0.2.0)
|
||||||
@@ -187,7 +182,7 @@ GEM
|
|||||||
trailblazer-option (>= 0.1.1, < 0.2.0)
|
trailblazer-option (>= 0.1.1, < 0.2.0)
|
||||||
uber (< 0.2.0)
|
uber (< 0.2.0)
|
||||||
retriable (3.1.2)
|
retriable (3.1.2)
|
||||||
rexml (3.4.1)
|
rexml (3.4.0)
|
||||||
rouge (3.28.0)
|
rouge (3.28.0)
|
||||||
ruby2_keywords (0.0.5)
|
ruby2_keywords (0.0.5)
|
||||||
rubyzip (2.4.1)
|
rubyzip (2.4.1)
|
||||||
@@ -221,7 +216,7 @@ GEM
|
|||||||
colored2 (~> 3.1)
|
colored2 (~> 3.1)
|
||||||
nanaimo (~> 0.4.0)
|
nanaimo (~> 0.4.0)
|
||||||
rexml (>= 3.3.6, < 4.0)
|
rexml (>= 3.3.6, < 4.0)
|
||||||
xcpretty (0.4.1)
|
xcpretty (0.4.0)
|
||||||
rouge (~> 3.28.0)
|
rouge (~> 3.28.0)
|
||||||
xcpretty-travis-formatter (1.0.1)
|
xcpretty-travis-formatter (1.0.1)
|
||||||
xcpretty (~> 0.2, >= 0.0.7)
|
xcpretty (~> 0.2, >= 0.0.7)
|
||||||
@@ -238,4 +233,4 @@ RUBY VERSION
|
|||||||
ruby 3.3.1p55
|
ruby 3.3.1p55
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
2.6.6
|
2.5.9
|
||||||
|
|||||||
58
README.md
58
README.md
@@ -58,11 +58,6 @@
|
|||||||
|
|
||||||
The following is a list of all third-party dependencies included as part of the application beyond the standard Android SDK.
|
The following is a list of all third-party dependencies included as part of the application beyond the standard Android SDK.
|
||||||
|
|
||||||
- **AndroidX Activity**
|
|
||||||
- https://developer.android.com/jetpack/androidx/releases/activity
|
|
||||||
- Purpose: Allows access composable APIs built on top of Activity.
|
|
||||||
- License: Apache 2.0
|
|
||||||
|
|
||||||
- **AndroidX Appcompat**
|
- **AndroidX Appcompat**
|
||||||
- https://developer.android.com/jetpack/androidx/releases/appcompat
|
- https://developer.android.com/jetpack/androidx/releases/appcompat
|
||||||
- Purpose: Allows access to new APIs on older API versions.
|
- Purpose: Allows access to new APIs on older API versions.
|
||||||
@@ -83,7 +78,7 @@ The following is a list of all third-party dependencies included as part of the
|
|||||||
- Purpose: Displays webpages with the user's default browser.
|
- Purpose: Displays webpages with the user's default browser.
|
||||||
- License: Apache 2.0
|
- License: Apache 2.0
|
||||||
|
|
||||||
- **AndroidX Camera**
|
- **AndroidX CameraX Camera2**
|
||||||
- https://developer.android.com/jetpack/androidx/releases/camera
|
- https://developer.android.com/jetpack/androidx/releases/camera
|
||||||
- Purpose: Display and capture images for barcode scanning.
|
- Purpose: Display and capture images for barcode scanning.
|
||||||
- License: Apache 2.0
|
- License: Apache 2.0
|
||||||
@@ -93,9 +88,9 @@ The following is a list of all third-party dependencies included as part of the
|
|||||||
- Purpose: A Kotlin-based declarative UI framework.
|
- Purpose: A Kotlin-based declarative UI framework.
|
||||||
- License: Apache 2.0
|
- License: Apache 2.0
|
||||||
|
|
||||||
- **AndroidX Core**
|
- **AndroidX Core SplashScreen**
|
||||||
- https://developer.android.com/jetpack/androidx/releases/core
|
- https://developer.android.com/jetpack/androidx/releases/core
|
||||||
- Purpose: Backwards compatible platform features and APIs.
|
- Purpose: Backwards compatible SplashScreen API implementation.
|
||||||
- License: Apache 2.0
|
- License: Apache 2.0
|
||||||
|
|
||||||
- **AndroidX Credentials**
|
- **AndroidX Credentials**
|
||||||
@@ -108,11 +103,6 @@ The following is a list of all third-party dependencies included as part of the
|
|||||||
- Purpose: Lifecycle aware components and tooling.
|
- Purpose: Lifecycle aware components and tooling.
|
||||||
- License: Apache 2.0
|
- License: Apache 2.0
|
||||||
|
|
||||||
- **AndroidX Navigation**
|
|
||||||
- https://developer.android.com/jetpack/androidx/releases/navigation
|
|
||||||
- Purpose: Provides a consistent API for navigating between Android components.
|
|
||||||
- License: Apache 2.0
|
|
||||||
|
|
||||||
- **AndroidX Room**
|
- **AndroidX Room**
|
||||||
- https://developer.android.com/jetpack/androidx/releases/room
|
- https://developer.android.com/jetpack/androidx/releases/room
|
||||||
- Purpose: A convenient SQLite-based persistence layer for Android.
|
- Purpose: A convenient SQLite-based persistence layer for Android.
|
||||||
@@ -133,6 +123,21 @@ The following is a list of all third-party dependencies included as part of the
|
|||||||
- Purpose: Dependency injection framework.
|
- Purpose: Dependency injection framework.
|
||||||
- License: Apache 2.0
|
- License: Apache 2.0
|
||||||
|
|
||||||
|
- **Firebase Cloud Messaging**
|
||||||
|
- https://github.com/firebase/firebase-android-sdk
|
||||||
|
- Purpose: Allows for push notification support. (**NOTE:** This dependency is not included in builds distributed via F-Droid.)
|
||||||
|
- License: Apache 2.0
|
||||||
|
|
||||||
|
- **Firebase Crashlytics**
|
||||||
|
- https://github.com/firebase/firebase-android-sdk
|
||||||
|
- Purpose: SDK for crash and non-fatal error reporting. (**NOTE:** This dependency is not included in builds distributed via F-Droid.)
|
||||||
|
- License: Apache 2.0
|
||||||
|
|
||||||
|
- **Google Play Reviews**
|
||||||
|
- https://developer.android.com/reference/com/google/android/play/core/release-notes
|
||||||
|
- Purpose: On standard builds provide an interface to add a review for the password manager application in Google Play.
|
||||||
|
- License: Apache 2.0
|
||||||
|
|
||||||
- **Glide**
|
- **Glide**
|
||||||
- https://github.com/bumptech/glide
|
- https://github.com/bumptech/glide
|
||||||
- Purpose: Image loading and caching.
|
- Purpose: Image loading and caching.
|
||||||
@@ -153,6 +158,11 @@ The following is a list of all third-party dependencies included as part of the
|
|||||||
- Purpose: JSON serialization library for Kotlin.
|
- Purpose: JSON serialization library for Kotlin.
|
||||||
- License: Apache 2.0
|
- License: Apache 2.0
|
||||||
|
|
||||||
|
- **kotlinx.serialization converter**
|
||||||
|
- https://github.com/square/retrofit/tree/trunk/retrofit-converters/kotlinx-serialization
|
||||||
|
- Purpose: Converter for Retrofit 2 and kotlinx.serialization.
|
||||||
|
- License: Apache 2.0
|
||||||
|
|
||||||
- **OkHttp 3**
|
- **OkHttp 3**
|
||||||
- https://github.com/square/okhttp
|
- https://github.com/square/okhttp
|
||||||
- Purpose: An HTTP client used by the library to intercept and log traffic.
|
- Purpose: An HTTP client used by the library to intercept and log traffic.
|
||||||
@@ -168,28 +178,16 @@ The following is a list of all third-party dependencies included as part of the
|
|||||||
- Purpose: Extensible logging library for Android.
|
- Purpose: Extensible logging library for Android.
|
||||||
- License: Apache 2.0
|
- License: Apache 2.0
|
||||||
|
|
||||||
|
- **zxcvbn4j**
|
||||||
|
- https://github.com/nulab/zxcvbn4j
|
||||||
|
- Purpose: Password strength estimation.
|
||||||
|
- License: MIT
|
||||||
|
|
||||||
- **ZXing**
|
- **ZXing**
|
||||||
- https://github.com/zxing/zxing
|
- https://github.com/zxing/zxing
|
||||||
- Purpose: Barcode scanning and generation.
|
- Purpose: Barcode scanning and generation.
|
||||||
- License: Apache 2.0
|
- License: Apache 2.0
|
||||||
|
|
||||||
The following is an additional list of third-party dependencies that are only included in the non-F-Droid build variants of the application.
|
|
||||||
|
|
||||||
- **Firebase Cloud Messaging**
|
|
||||||
- https://github.com/firebase/firebase-android-sdk
|
|
||||||
- Purpose: Allows for push notification support.
|
|
||||||
- License: Apache 2.0
|
|
||||||
|
|
||||||
- **Firebase Crashlytics**
|
|
||||||
- https://github.com/firebase/firebase-android-sdk
|
|
||||||
- Purpose: SDK for crash and non-fatal error reporting.
|
|
||||||
- License: Apache 2.0
|
|
||||||
|
|
||||||
- **Google Play Reviews**
|
|
||||||
- https://developer.android.com/reference/com/google/android/play/core/release-notes
|
|
||||||
- Purpose: On standard builds provide an interface to add a review for the password manager application in Google Play.
|
|
||||||
- License: Apache 2.0
|
|
||||||
|
|
||||||
### Development Environment Dependencies
|
### Development Environment Dependencies
|
||||||
|
|
||||||
The following is a list of additional third-party dependencies used as part of the local development environment. This includes test-related artifacts as well as tools related to code quality and linting. These are not present in the final packaged application.
|
The following is a list of additional third-party dependencies used as part of the local development environment. This includes test-related artifacts as well as tools related to code quality and linting. These are not present in the final packaged application.
|
||||||
|
|||||||
@@ -13,13 +13,16 @@ plugins {
|
|||||||
// Crashlytics is enabled for all builds initially but removed for FDroid builds in gradle and
|
// Crashlytics is enabled for all builds initially but removed for FDroid builds in gradle and
|
||||||
// standardDebug builds in the merged manifest.
|
// standardDebug builds in the merged manifest.
|
||||||
alias(libs.plugins.crashlytics)
|
alias(libs.plugins.crashlytics)
|
||||||
|
alias(libs.plugins.detekt)
|
||||||
alias(libs.plugins.hilt)
|
alias(libs.plugins.hilt)
|
||||||
alias(libs.plugins.kotlin.android)
|
alias(libs.plugins.kotlin.android)
|
||||||
alias(libs.plugins.kotlin.compose.compiler)
|
alias(libs.plugins.kotlin.compose.compiler)
|
||||||
alias(libs.plugins.kotlin.parcelize)
|
alias(libs.plugins.kotlin.parcelize)
|
||||||
alias(libs.plugins.kotlin.serialization)
|
alias(libs.plugins.kotlin.serialization)
|
||||||
|
alias(libs.plugins.kotlinx.kover)
|
||||||
alias(libs.plugins.ksp)
|
alias(libs.plugins.ksp)
|
||||||
alias(libs.plugins.google.services)
|
alias(libs.plugins.google.services)
|
||||||
|
alias(libs.plugins.sonarqube)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,7 +54,7 @@ android {
|
|||||||
minSdk = libs.versions.minSdk.get().toInt()
|
minSdk = libs.versions.minSdk.get().toInt()
|
||||||
targetSdk = libs.versions.targetSdk.get().toInt()
|
targetSdk = libs.versions.targetSdk.get().toInt()
|
||||||
versionCode = 1
|
versionCode = 1
|
||||||
versionName = "2025.4.0"
|
versionName = "2024.9.0"
|
||||||
|
|
||||||
setProperty("archivesBaseName", "com.x8bit.bitwarden")
|
setProperty("archivesBaseName", "com.x8bit.bitwarden")
|
||||||
|
|
||||||
@@ -65,7 +68,7 @@ android {
|
|||||||
buildConfigField(
|
buildConfigField(
|
||||||
type = "String",
|
type = "String",
|
||||||
name = "CI_INFO",
|
name = "CI_INFO",
|
||||||
value = "${ciProperties.getOrDefault("ci.info", "\"local\"")}",
|
value = "${ciProperties.getOrDefault("ci.info", "\"local\"")}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,10 +102,9 @@ android {
|
|||||||
applicationIdSuffix = ".beta"
|
applicationIdSuffix = ".beta"
|
||||||
isDebuggable = false
|
isDebuggable = false
|
||||||
isMinifyEnabled = true
|
isMinifyEnabled = true
|
||||||
matchingFallbacks += listOf("release")
|
|
||||||
proguardFiles(
|
proguardFiles(
|
||||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
"proguard-rules.pro",
|
"proguard-rules.pro"
|
||||||
)
|
)
|
||||||
|
|
||||||
buildConfigField(type = "boolean", name = "HAS_DEBUG_MENU", value = "false")
|
buildConfigField(type = "boolean", name = "HAS_DEBUG_MENU", value = "false")
|
||||||
@@ -113,7 +115,7 @@ android {
|
|||||||
isMinifyEnabled = true
|
isMinifyEnabled = true
|
||||||
proguardFiles(
|
proguardFiles(
|
||||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
"proguard-rules.pro",
|
"proguard-rules.pro"
|
||||||
)
|
)
|
||||||
|
|
||||||
buildConfigField(type = "boolean", name = "HAS_DEBUG_MENU", value = "false")
|
buildConfigField(type = "boolean", name = "HAS_DEBUG_MENU", value = "false")
|
||||||
@@ -178,6 +180,7 @@ android {
|
|||||||
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Suppress("UnstableApiUsage")
|
||||||
testOptions {
|
testOptions {
|
||||||
// Required for Robolectric
|
// Required for Robolectric
|
||||||
unitTests.isIncludeAndroidResources = true
|
unitTests.isIncludeAndroidResources = true
|
||||||
@@ -213,11 +216,6 @@ dependencies {
|
|||||||
|
|
||||||
implementation(files("libs/authenticatorbridge-1.0.0-release.aar"))
|
implementation(files("libs/authenticatorbridge-1.0.0-release.aar"))
|
||||||
|
|
||||||
implementation(project(":core"))
|
|
||||||
implementation(project(":data"))
|
|
||||||
implementation(project(":network"))
|
|
||||||
implementation(project(":ui"))
|
|
||||||
|
|
||||||
implementation(libs.androidx.activity.compose)
|
implementation(libs.androidx.activity.compose)
|
||||||
implementation(libs.androidx.appcompat)
|
implementation(libs.androidx.appcompat)
|
||||||
implementation(libs.androidx.autofill)
|
implementation(libs.androidx.autofill)
|
||||||
@@ -229,7 +227,6 @@ dependencies {
|
|||||||
implementation(platform(libs.androidx.compose.bom))
|
implementation(platform(libs.androidx.compose.bom))
|
||||||
implementation(libs.androidx.compose.animation)
|
implementation(libs.androidx.compose.animation)
|
||||||
implementation(libs.androidx.compose.material3)
|
implementation(libs.androidx.compose.material3)
|
||||||
implementation(libs.androidx.compose.material3.adaptive)
|
|
||||||
implementation(libs.androidx.compose.runtime)
|
implementation(libs.androidx.compose.runtime)
|
||||||
implementation(libs.androidx.compose.ui)
|
implementation(libs.androidx.compose.ui)
|
||||||
implementation(libs.androidx.compose.ui.graphics)
|
implementation(libs.androidx.compose.ui.graphics)
|
||||||
@@ -254,6 +251,7 @@ dependencies {
|
|||||||
implementation(libs.kotlinx.collections.immutable)
|
implementation(libs.kotlinx.collections.immutable)
|
||||||
implementation(libs.kotlinx.coroutines.android)
|
implementation(libs.kotlinx.coroutines.android)
|
||||||
implementation(libs.kotlinx.serialization)
|
implementation(libs.kotlinx.serialization)
|
||||||
|
implementation(libs.nulab.zxcvbn4j)
|
||||||
implementation(libs.square.okhttp)
|
implementation(libs.square.okhttp)
|
||||||
implementation(libs.square.okhttp.logging)
|
implementation(libs.square.okhttp.logging)
|
||||||
implementation(platform(libs.square.retrofit.bom))
|
implementation(platform(libs.square.retrofit.bom))
|
||||||
@@ -272,14 +270,8 @@ dependencies {
|
|||||||
standardImplementation(libs.google.firebase.crashlytics)
|
standardImplementation(libs.google.firebase.crashlytics)
|
||||||
standardImplementation(libs.google.play.review)
|
standardImplementation(libs.google.play.review)
|
||||||
|
|
||||||
// Pull in test fixtures from other modules
|
|
||||||
testImplementation(testFixtures(project(":data")))
|
|
||||||
testImplementation(testFixtures(project(":network")))
|
|
||||||
|
|
||||||
testImplementation(libs.androidx.compose.ui.test)
|
testImplementation(libs.androidx.compose.ui.test)
|
||||||
testImplementation(libs.google.hilt.android.testing)
|
testImplementation(libs.google.hilt.android.testing)
|
||||||
testImplementation(platform(libs.junit.bom))
|
|
||||||
testRuntimeOnly(libs.junit.platform.launcher)
|
|
||||||
testImplementation(libs.junit.junit5)
|
testImplementation(libs.junit.junit5)
|
||||||
testImplementation(libs.junit.vintage)
|
testImplementation(libs.junit.vintage)
|
||||||
testImplementation(libs.kotlinx.coroutines.test)
|
testImplementation(libs.kotlinx.coroutines.test)
|
||||||
@@ -287,9 +279,90 @@ dependencies {
|
|||||||
testImplementation(libs.robolectric.robolectric)
|
testImplementation(libs.robolectric.robolectric)
|
||||||
testImplementation(libs.square.okhttp.mockwebserver)
|
testImplementation(libs.square.okhttp.mockwebserver)
|
||||||
testImplementation(libs.square.turbine)
|
testImplementation(libs.square.turbine)
|
||||||
|
|
||||||
|
detektPlugins(libs.detekt.detekt.formatting)
|
||||||
|
detektPlugins(libs.detekt.detekt.rules)
|
||||||
|
}
|
||||||
|
|
||||||
|
detekt {
|
||||||
|
autoCorrect = true
|
||||||
|
config.from(files("$rootDir/detekt-config.yml"))
|
||||||
|
}
|
||||||
|
|
||||||
|
kover {
|
||||||
|
currentProject {
|
||||||
|
sources {
|
||||||
|
excludeJava = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reports {
|
||||||
|
filters {
|
||||||
|
excludes {
|
||||||
|
androidGeneratedClasses()
|
||||||
|
annotatedBy(
|
||||||
|
// Compose previews
|
||||||
|
"androidx.compose.ui.tooling.preview.Preview",
|
||||||
|
"androidx.compose.ui.tooling.preview.PreviewScreenSizes",
|
||||||
|
// Manually excluded classes/files/etc.
|
||||||
|
"com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage",
|
||||||
|
)
|
||||||
|
classes(
|
||||||
|
// Navigation helpers
|
||||||
|
"*.*NavigationKt*",
|
||||||
|
// Composable singletons
|
||||||
|
"*.*ComposableSingletons*",
|
||||||
|
// Generated classes related to interfaces with default values
|
||||||
|
"*.*DefaultImpls*",
|
||||||
|
// Databases
|
||||||
|
"*.database.*Database*",
|
||||||
|
"*.dao.*Dao*",
|
||||||
|
// Dagger Hilt
|
||||||
|
"dagger.hilt.*",
|
||||||
|
"hilt_aggregated_deps.*",
|
||||||
|
"*_Factory",
|
||||||
|
"*_Factory\$*",
|
||||||
|
"*_*Factory",
|
||||||
|
"*_*Factory\$*",
|
||||||
|
"*.Hilt_*",
|
||||||
|
"*_HiltModules",
|
||||||
|
"*_HiltModules*",
|
||||||
|
"*_HiltModules\$*",
|
||||||
|
"*_Impl",
|
||||||
|
"*_Impl\$*",
|
||||||
|
"*_MembersInjector",
|
||||||
|
)
|
||||||
|
packages(
|
||||||
|
// Dependency injection
|
||||||
|
"*.di",
|
||||||
|
// Models
|
||||||
|
"*.model",
|
||||||
|
// Custom UI components
|
||||||
|
"com.x8bit.bitwarden.ui.platform.components",
|
||||||
|
// Theme-related code
|
||||||
|
"com.x8bit.bitwarden.ui.platform.theme",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
|
getByName("check") {
|
||||||
|
// Add detekt with type resolution to check
|
||||||
|
dependsOn("detekt")
|
||||||
|
}
|
||||||
|
|
||||||
|
getByName("sonar") {
|
||||||
|
dependsOn("check")
|
||||||
|
}
|
||||||
|
|
||||||
|
withType<io.gitlab.arturbosch.detekt.Detekt>().configureEach {
|
||||||
|
jvmTarget = libs.versions.jvmTarget.get()
|
||||||
|
}
|
||||||
|
withType<io.gitlab.arturbosch.detekt.DetektCreateBaselineTask>().configureEach {
|
||||||
|
jvmTarget = libs.versions.jvmTarget.get()
|
||||||
|
}
|
||||||
|
|
||||||
withType<Test> {
|
withType<Test> {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
maxHeapSize = "2g"
|
maxHeapSize = "2g"
|
||||||
@@ -309,6 +382,18 @@ afterEvaluate {
|
|||||||
.forEach { it.enabled = false }
|
.forEach { it.enabled = false }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sonar {
|
||||||
|
properties {
|
||||||
|
property("sonar.projectKey", "bitwarden_android")
|
||||||
|
property("sonar.organization", "bitwarden")
|
||||||
|
property("sonar.host.url", "https://sonarcloud.io")
|
||||||
|
property("sonar.sources", "app/src/")
|
||||||
|
property("sonar.tests", "app/src/")
|
||||||
|
property("sonar.test.inclusions", "app/src/test/")
|
||||||
|
property("sonar.exclusions", "app/src/test/")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun renameFile(path: String, newName: String) {
|
private fun renameFile(path: String, newName: String) {
|
||||||
val originalFile = File(path)
|
val originalFile = File(path)
|
||||||
if (!originalFile.exists()) {
|
if (!originalFile.exists()) {
|
||||||
|
|||||||
@@ -12,6 +12,20 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "android",
|
||||||
|
"info": {
|
||||||
|
"package_name": "net.quetta.browser",
|
||||||
|
"signatures": [
|
||||||
|
{
|
||||||
|
"build": "release",
|
||||||
|
"cert_fingerprint_sha256": "BE:FE:E7:31:12:6A:A5:6E:7E:FD:AE:AF:5E:F3:FA:EA:44:1C:19:CC:E0:CA:EC:42:6B:65:BB:F8:2C:59:46:80"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"type": "android",
|
"type": "android",
|
||||||
"info": {
|
"info": {
|
||||||
@@ -48,6 +62,18 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "android",
|
||||||
|
"info": {
|
||||||
|
"package_name": "org.mozilla.fenix",
|
||||||
|
"signatures": [
|
||||||
|
{
|
||||||
|
"build": "release",
|
||||||
|
"cert_fingerprint_sha256": "50:04:77:90:88:E7:F9:88:D5:BC:5C:C5:F8:79:8F:EB:F4:F8:CD:08:4A:1B:2A:46:EF:D4:C8:EE:4A:EA:F2:11"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "android",
|
"type": "android",
|
||||||
"info": {
|
"info": {
|
||||||
|
|||||||
@@ -160,78 +160,6 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "android",
|
|
||||||
"info": {
|
|
||||||
"package_name": "org.mozilla.fenix",
|
|
||||||
"signatures": [
|
|
||||||
{
|
|
||||||
"build": "release",
|
|
||||||
"cert_fingerprint_sha256": "50:04:77:90:88:E7:F9:88:D5:BC:5C:C5:F8:79:8F:EB:F4:F8:CD:08:4A:1B:2A:46:EF:D4:C8:EE:4A:EA:F2:11"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "android",
|
|
||||||
"info": {
|
|
||||||
"package_name": "org.mozilla.fenix.debug",
|
|
||||||
"signatures": [
|
|
||||||
{
|
|
||||||
"build": "userdebug",
|
|
||||||
"cert_fingerprint_sha256": "BD:AE:82:02:80:D2:AF:B7:74:94:EF:22:58:AA:78:A9:AE:A1:36:41:7E:8B:C2:3D:C9:87:75:2E:6F:48:E8:48"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "android",
|
|
||||||
"info": {
|
|
||||||
"package_name": "org.mozilla.focus.beta",
|
|
||||||
"signatures": [
|
|
||||||
{
|
|
||||||
"build": "release",
|
|
||||||
"cert_fingerprint_sha256": "62:03:A4:73:BE:36:D6:4E:E3:7F:87:FA:50:0E:DB:C7:9E:AB:93:06:10:AB:9B:9F:A4:CA:7D:5C:1F:1B:4F:FC"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "android",
|
|
||||||
"info": {
|
|
||||||
"package_name": "org.mozilla.focus.nightly",
|
|
||||||
"signatures": [
|
|
||||||
{
|
|
||||||
"build": "release",
|
|
||||||
"cert_fingerprint_sha256": "62:03:A4:73:BE:36:D6:4E:E3:7F:87:FA:50:0E:DB:C7:9E:AB:93:06:10:AB:9B:9F:A4:CA:7D:5C:1F:1B:4F:FC"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "android",
|
|
||||||
"info": {
|
|
||||||
"package_name": "org.mozilla.klar",
|
|
||||||
"signatures": [
|
|
||||||
{
|
|
||||||
"build": "release",
|
|
||||||
"cert_fingerprint_sha256": "62:03:A4:73:BE:36:D6:4E:E3:7F:87:FA:50:0E:DB:C7:9E:AB:93:06:10:AB:9B:9F:A4:CA:7D:5C:1F:1B:4F:FC"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "android",
|
|
||||||
"info": {
|
|
||||||
"package_name": "org.mozilla.reference.browser",
|
|
||||||
"signatures": [
|
|
||||||
{
|
|
||||||
"build": "release",
|
|
||||||
"cert_fingerprint_sha256": "B0:09:90:E3:0F:9D:81:5D:2E:BC:7B:9B:B2:21:CE:47:E5:C9:D5:17:AA:C7:0E:7F:D5:95:B1:E5:3E:9A:4B:14"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "android",
|
"type": "android",
|
||||||
"info": {
|
"info": {
|
||||||
@@ -643,142 +571,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "android",
|
|
||||||
"info": {
|
|
||||||
"package_name": "io.island.Island",
|
|
||||||
"signatures": [
|
|
||||||
{
|
|
||||||
"build": "release",
|
|
||||||
"cert_fingerprint_sha256": "D9:C3:39:AC:9C:3A:EE:E1:75:1D:85:8C:35:D9:BA:C5:CC:87:B3:CE:76:30:93:F0:F5:10:64:F5:A2:F6:9B:04"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"build": "userdebug",
|
|
||||||
"cert_fingerprint_sha256": "6C:65:BD:B0:33:F5:CE:B1:74:09:EF:F9:99:48:D5:58:9F:55:63:9A:63:78:D5:A5:00:EB:95:FC:01:BC:6D:44"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "android",
|
|
||||||
"info": {
|
|
||||||
"package_name": "io.island.IslandCanary",
|
|
||||||
"signatures": [
|
|
||||||
{
|
|
||||||
"build": "release",
|
|
||||||
"cert_fingerprint_sha256": "90:17:13:23:45:6E:6F:39:CB:FD:CF:B2:56:BE:1D:CF:F3:BC:1C:59:8A:15:93:30:E4:97:73:D0:4C:B9:C9:05"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"build": "userdebug",
|
|
||||||
"cert_fingerprint_sha256": "6C:65:BD:B0:33:F5:CE:B1:74:09:EF:F9:99:48:D5:58:9F:55:63:9A:63:78:D5:A5:00:EB:95:FC:01:BC:6D:44"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "android",
|
|
||||||
"info": {
|
|
||||||
"package_name": "io.island.IslandBeta",
|
|
||||||
"signatures": [
|
|
||||||
{
|
|
||||||
"build": "release",
|
|
||||||
"cert_fingerprint_sha256": "35:31:83:1A:9E:2B:21:1D:E6:AA:C3:69:4B:45:83:6E:56:09:B9:D7:D0:04:C3:1B:21:87:40:FB:77:17:38:D1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"build": "userdebug",
|
|
||||||
"cert_fingerprint_sha256": "6C:65:BD:B0:33:F5:CE:B1:74:09:EF:F9:99:48:D5:58:9F:55:63:9A:63:78:D5:A5:00:EB:95:FC:01:BC:6D:44"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "android",
|
|
||||||
"info": {
|
|
||||||
"package_name": "io.island.IslandDev",
|
|
||||||
"signatures": [
|
|
||||||
{
|
|
||||||
"build": "userdebug",
|
|
||||||
"cert_fingerprint_sha256": "6C:65:BD:B0:33:F5:CE:B1:74:09:EF:F9:99:48:D5:58:9F:55:63:9A:63:78:D5:A5:00:EB:95:FC:01:BC:6D:44"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "android",
|
|
||||||
"info": {
|
|
||||||
"package_name": "io.island.island.intune",
|
|
||||||
"signatures": [
|
|
||||||
{
|
|
||||||
"build": "release",
|
|
||||||
"cert_fingerprint_sha256": "C2:38:24:15:41:20:A0:8F:C3:95:42:AC:D8:2A:E9:24:94:78:80:1E:47:FD:6C:66:2B:18:1C:28:CA:7E:59:4E"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"build": "userdebug",
|
|
||||||
"cert_fingerprint_sha256": "6C:65:BD:B0:33:F5:CE:B1:74:09:EF:F9:99:48:D5:58:9F:55:63:9A:63:78:D5:A5:00:EB:95:FC:01:BC:6D:44"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "android",
|
|
||||||
"info": {
|
|
||||||
"package_name": "io.island.island.canary.intune",
|
|
||||||
"signatures": [
|
|
||||||
{
|
|
||||||
"build": "release",
|
|
||||||
"cert_fingerprint_sha256": "1E:16:74:BB:79:EA:09:FB:37:CF:9F:1B:07:1B:1D:51:8D:46:03:0E:D3:EE:F2:C1:4E:AD:93:9E:C6:EE:3A:4C"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"build": "userdebug",
|
|
||||||
"cert_fingerprint_sha256": "6C:65:BD:B0:33:F5:CE:B1:74:09:EF:F9:99:48:D5:58:9F:55:63:9A:63:78:D5:A5:00:EB:95:FC:01:BC:6D:44"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "android",
|
|
||||||
"info": {
|
|
||||||
"package_name": "io.island.island.beta.intune",
|
|
||||||
"signatures": [
|
|
||||||
{
|
|
||||||
"build": "release",
|
|
||||||
"cert_fingerprint_sha256": "D2:5E:AD:F6:1C:E6:36:6C:A4:23:A4:7F:C4:DB:9B:8C:9C:8A:35:B4:B0:19:E8:D9:82:FB:D0:8A:D9:DB:49:5A"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"build": "userdebug",
|
|
||||||
"cert_fingerprint_sha256": "6C:65:BD:B0:33:F5:CE:B1:74:09:EF:F9:99:48:D5:58:9F:55:63:9A:63:78:D5:A5:00:EB:95:FC:01:BC:6D:44"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "android",
|
|
||||||
"info": {
|
|
||||||
"package_name": "io.island.island.dev.intune",
|
|
||||||
"signatures": [
|
|
||||||
{
|
|
||||||
"build": "userdebug",
|
|
||||||
"cert_fingerprint_sha256": "6C:65:BD:B0:33:F5:CE:B1:74:09:EF:F9:99:48:D5:58:9F:55:63:9A:63:78:D5:A5:00:EB:95:FC:01:BC:6D:44"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "android",
|
|
||||||
"info": {
|
|
||||||
"package_name": "net.quetta.browser",
|
|
||||||
"signatures": [
|
|
||||||
{
|
|
||||||
"build": "release",
|
|
||||||
"cert_fingerprint_sha256": "BE:FE:E7:31:12:6A:A5:6E:7E:FD:AE:AF:5E:F3:FA:EA:44:1C:19:CC:E0:CA:EC:42:6B:65:BB:F8:2C:59:46:80"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"build": "userdebug",
|
|
||||||
"cert_fingerprint_sha256": "F1:38:00:4F:38:04:51:D4:8A:05:2B:B3:A3:EF:17:24:23:D4:B0:D0:C8:A3:AA:DD:FB:DB:66:30:31:48:EC:A4"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package com.x8bit.bitwarden
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import com.bitwarden.core.annotation.OmitFromCoverage
|
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An activity to be launched and then immediately closed so that the OS Shade can be collapsed
|
* An activity to be launched and then immediately closed so that the OS Shade can be collapsed
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import android.content.Intent
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import com.bitwarden.core.annotation.OmitFromCoverage
|
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import android.os.Bundle
|
|||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.bitwarden.core.annotation.OmitFromCoverage
|
|
||||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillCompletionManager
|
import com.x8bit.bitwarden.data.autofill.manager.AutofillCompletionManager
|
||||||
|
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import android.content.Intent
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.annotation.Keep
|
import androidx.annotation.Keep
|
||||||
import androidx.core.app.AppComponentFactory
|
import androidx.core.app.AppComponentFactory
|
||||||
import com.bitwarden.core.annotation.OmitFromCoverage
|
|
||||||
import com.x8bit.bitwarden.data.autofill.BitwardenAutofillService
|
import com.x8bit.bitwarden.data.autofill.BitwardenAutofillService
|
||||||
import com.x8bit.bitwarden.data.autofill.accessibility.BitwardenAccessibilityService
|
import com.x8bit.bitwarden.data.autofill.accessibility.BitwardenAccessibilityService
|
||||||
import com.x8bit.bitwarden.data.autofill.fido2.BitwardenFido2ProviderService
|
import com.x8bit.bitwarden.data.autofill.fido2.BitwardenFido2ProviderService
|
||||||
|
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
||||||
import com.x8bit.bitwarden.data.tiles.BitwardenAutofillTileService
|
import com.x8bit.bitwarden.data.tiles.BitwardenAutofillTileService
|
||||||
import com.x8bit.bitwarden.data.tiles.BitwardenGeneratorTileService
|
import com.x8bit.bitwarden.data.tiles.BitwardenGeneratorTileService
|
||||||
import com.x8bit.bitwarden.data.tiles.BitwardenVaultTileService
|
import com.x8bit.bitwarden.data.tiles.BitwardenVaultTileService
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.x8bit.bitwarden
|
package com.x8bit.bitwarden
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import com.bitwarden.core.annotation.OmitFromCoverage
|
|
||||||
import com.x8bit.bitwarden.data.auth.manager.AuthRequestNotificationManager
|
import com.x8bit.bitwarden.data.auth.manager.AuthRequestNotificationManager
|
||||||
|
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
||||||
import com.x8bit.bitwarden.data.platform.manager.LogsManager
|
import com.x8bit.bitwarden.data.platform.manager.LogsManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.event.OrganizationEventManager
|
import com.x8bit.bitwarden.data.platform.manager.event.OrganizationEventManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.network.NetworkConfigManager
|
import com.x8bit.bitwarden.data.platform.manager.network.NetworkConfigManager
|
||||||
|
|||||||
@@ -6,11 +6,6 @@ package com.x8bit.bitwarden
|
|||||||
const val LEGACY_ACCESSIBILITY_SERVICE_NAME: String =
|
const val LEGACY_ACCESSIBILITY_SERVICE_NAME: String =
|
||||||
"com.x8bit.bitwarden.Accessibility.AccessibilityService"
|
"com.x8bit.bitwarden.Accessibility.AccessibilityService"
|
||||||
|
|
||||||
/**
|
|
||||||
* The short form legacy name for the accessibility service.
|
|
||||||
*/
|
|
||||||
const val LEGACY_SHORT_ACCESSIBILITY_SERVICE_NAME: String = ".Accessibility.AccessibilityService"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The legacy name for the autofill service.
|
* The legacy name for the autofill service.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.x8bit.bitwarden
|
package com.x8bit.bitwarden
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
@@ -16,31 +15,25 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.core.os.LocaleListCompat
|
import androidx.core.os.LocaleListCompat
|
||||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import androidx.navigation.compose.NavHost
|
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import com.bitwarden.core.annotation.OmitFromCoverage
|
|
||||||
import com.x8bit.bitwarden.data.autofill.accessibility.manager.AccessibilityCompletionManager
|
import com.x8bit.bitwarden.data.autofill.accessibility.manager.AccessibilityCompletionManager
|
||||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillActivityManager
|
import com.x8bit.bitwarden.data.autofill.manager.AutofillActivityManager
|
||||||
import com.x8bit.bitwarden.data.autofill.manager.AutofillCompletionManager
|
import com.x8bit.bitwarden.data.autofill.manager.AutofillCompletionManager
|
||||||
|
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
||||||
import com.x8bit.bitwarden.data.platform.manager.util.ObserveScreenDataEffect
|
import com.x8bit.bitwarden.data.platform.manager.util.ObserveScreenDataEffect
|
||||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||||
import com.x8bit.bitwarden.ui.platform.composition.LocalManagerProvider
|
import com.x8bit.bitwarden.ui.platform.composition.LocalManagerProvider
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.debugmenu.debugMenuDestination
|
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.debugmenu.manager.DebugMenuLaunchManager
|
import com.x8bit.bitwarden.ui.platform.feature.debugmenu.manager.DebugMenuLaunchManager
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.debugmenu.navigateToDebugMenuScreen
|
import com.x8bit.bitwarden.ui.platform.feature.debugmenu.navigateToDebugMenuScreen
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.rootnav.ROOT_ROUTE
|
import com.x8bit.bitwarden.ui.platform.feature.rootnav.RootNavScreen
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.rootnav.rootNavDestination
|
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppLanguage
|
|
||||||
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
||||||
import com.x8bit.bitwarden.ui.platform.util.appLanguage
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Primary entry point for the application.
|
* Primary entry point for the application.
|
||||||
*/
|
*/
|
||||||
@Suppress("TooManyFunctions")
|
|
||||||
@OmitFromCoverage
|
@OmitFromCoverage
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity() {
|
||||||
@@ -76,9 +69,13 @@ class MainActivity : AppCompatActivity() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Within the app the theme will change dynamically and will be managed by the
|
// Within the app the language and theme will change dynamically and will be managed by the
|
||||||
// OS, but we need to ensure we properly set the values when upgrading from older versions
|
// OS, but we need to ensure we properly set the values when upgrading from older versions
|
||||||
// that handle this differently or when the activity restarts.
|
// that handle this differently or when the activity restarts.
|
||||||
|
settingsRepository.appLanguage.localeName?.let { localeName ->
|
||||||
|
val localeList = LocaleListCompat.forLanguageTags(localeName)
|
||||||
|
AppCompatDelegate.setApplicationLocales(localeList)
|
||||||
|
}
|
||||||
AppCompatDelegate.setDefaultNightMode(settingsRepository.appTheme.osValue)
|
AppCompatDelegate.setDefaultNightMode(settingsRepository.appTheme.osValue)
|
||||||
setContent {
|
setContent {
|
||||||
val state by mainViewModel.stateFlow.collectAsStateWithLifecycle()
|
val state by mainViewModel.stateFlow.collectAsStateWithLifecycle()
|
||||||
@@ -114,7 +111,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateScreenCapture(isScreenCaptureAllowed = state.isScreenCaptureAllowed)
|
updateScreenCapture(isScreenCaptureAllowed = state.isScreenCaptureAllowed)
|
||||||
LocalManagerProvider(featureFlagsState = state.featureFlagsState) {
|
LocalManagerProvider {
|
||||||
ObserveScreenDataEffect(
|
ObserveScreenDataEffect(
|
||||||
onDataUpdate = remember(mainViewModel) {
|
onDataUpdate = remember(mainViewModel) {
|
||||||
{
|
{
|
||||||
@@ -125,19 +122,10 @@ class MainActivity : AppCompatActivity() {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
BitwardenTheme(theme = state.theme) {
|
BitwardenTheme(theme = state.theme) {
|
||||||
NavHost(
|
RootNavScreen(
|
||||||
|
onSplashScreenRemoved = { shouldShowSplashScreen = false },
|
||||||
navController = navController,
|
navController = navController,
|
||||||
startDestination = ROOT_ROUTE,
|
)
|
||||||
) {
|
|
||||||
// Nothing else should end up at this top level, we just want the ability
|
|
||||||
// to have the debug menu appear on top of the rest of the app without
|
|
||||||
// interacting with the state-based navigation used by the RootNavScreen.
|
|
||||||
rootNavDestination { shouldShowSplashScreen = false }
|
|
||||||
debugMenuDestination(
|
|
||||||
onNavigateBack = { navController.popBackStack() },
|
|
||||||
onSplashScreenRemoved = { shouldShowSplashScreen = false },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,33 +140,6 @@ class MainActivity : AppCompatActivity() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
// When the app resumes check for any app specific language which may have been
|
|
||||||
// set via the device settings. Similar to the theme setting in onCreate this
|
|
||||||
// ensures we properly set the values when upgrading from older versions
|
|
||||||
// that handle this differently or when the activity restarts.
|
|
||||||
val appSpecificLanguage = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
||||||
val locales: LocaleListCompat = AppCompatDelegate.getApplicationLocales()
|
|
||||||
if (locales.isEmpty) {
|
|
||||||
// App is using the system language
|
|
||||||
null
|
|
||||||
} else {
|
|
||||||
// App has specific language settings
|
|
||||||
locales.get(0)?.appLanguage
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// For older versions, use what ever language is available from the repository.
|
|
||||||
settingsRepository.appLanguage
|
|
||||||
}
|
|
||||||
|
|
||||||
mainViewModel.trySendAction(
|
|
||||||
action = MainAction.AppSpecificLanguageUpdate(
|
|
||||||
appLanguage = appSpecificLanguage ?: AppLanguage.DEFAULT,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
super.onStop()
|
super.onStop()
|
||||||
// In some scenarios on an emulator the Activity can leak when recreated
|
// In some scenarios on an emulator the Activity can leak when recreated
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import android.content.Intent
|
|||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import androidx.lifecycle.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.bitwarden.ui.util.Text
|
|
||||||
import com.bitwarden.ui.util.asText
|
|
||||||
import com.bitwarden.vault.CipherView
|
import com.bitwarden.vault.CipherView
|
||||||
import com.x8bit.bitwarden.data.auth.manager.AddTotpItemFromAuthenticatorManager
|
import com.x8bit.bitwarden.data.auth.manager.AddTotpItemFromAuthenticatorManager
|
||||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||||
@@ -21,12 +19,10 @@ import com.x8bit.bitwarden.data.autofill.manager.AutofillSelectionManager
|
|||||||
import com.x8bit.bitwarden.data.autofill.util.getAutofillSaveItemOrNull
|
import com.x8bit.bitwarden.data.autofill.util.getAutofillSaveItemOrNull
|
||||||
import com.x8bit.bitwarden.data.autofill.util.getAutofillSelectionDataOrNull
|
import com.x8bit.bitwarden.data.autofill.util.getAutofillSelectionDataOrNull
|
||||||
import com.x8bit.bitwarden.data.platform.manager.AppResumeManager
|
import com.x8bit.bitwarden.data.platform.manager.AppResumeManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
|
||||||
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.garbage.GarbageCollectionManager
|
import com.x8bit.bitwarden.data.platform.manager.garbage.GarbageCollectionManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.model.AppResumeScreenData
|
import com.x8bit.bitwarden.data.platform.manager.model.AppResumeScreenData
|
||||||
import com.x8bit.bitwarden.data.platform.manager.model.CompleteRegistrationData
|
import com.x8bit.bitwarden.data.platform.manager.model.CompleteRegistrationData
|
||||||
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
|
|
||||||
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
||||||
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
||||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||||
@@ -34,10 +30,10 @@ import com.x8bit.bitwarden.data.platform.util.isAddTotpLoginItemFromAuthenticato
|
|||||||
import com.x8bit.bitwarden.data.vault.manager.model.VaultStateEvent
|
import com.x8bit.bitwarden.data.vault.manager.model.VaultStateEvent
|
||||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppLanguage
|
import com.x8bit.bitwarden.ui.platform.base.util.Text
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppTheme
|
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppTheme
|
||||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||||
import com.x8bit.bitwarden.ui.platform.model.FeatureFlagsState
|
|
||||||
import com.x8bit.bitwarden.ui.platform.util.isAccountSecurityShortcut
|
import com.x8bit.bitwarden.ui.platform.util.isAccountSecurityShortcut
|
||||||
import com.x8bit.bitwarden.ui.platform.util.isMyVaultShortcut
|
import com.x8bit.bitwarden.ui.platform.util.isMyVaultShortcut
|
||||||
import com.x8bit.bitwarden.ui.platform.util.isPasswordGeneratorShortcut
|
import com.x8bit.bitwarden.ui.platform.util.isPasswordGeneratorShortcut
|
||||||
@@ -58,7 +54,6 @@ import java.time.Clock
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
private const val SPECIAL_CIRCUMSTANCE_KEY = "special-circumstance"
|
private const val SPECIAL_CIRCUMSTANCE_KEY = "special-circumstance"
|
||||||
private const val ANIMATION_REFRESH_DELAY = 500L
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A view model that helps launch actions for the [MainActivity].
|
* A view model that helps launch actions for the [MainActivity].
|
||||||
@@ -68,13 +63,12 @@ private const val ANIMATION_REFRESH_DELAY = 500L
|
|||||||
class MainViewModel @Inject constructor(
|
class MainViewModel @Inject constructor(
|
||||||
accessibilitySelectionManager: AccessibilitySelectionManager,
|
accessibilitySelectionManager: AccessibilitySelectionManager,
|
||||||
autofillSelectionManager: AutofillSelectionManager,
|
autofillSelectionManager: AutofillSelectionManager,
|
||||||
featureFlagManager: FeatureFlagManager,
|
|
||||||
private val addTotpItemFromAuthenticatorManager: AddTotpItemFromAuthenticatorManager,
|
private val addTotpItemFromAuthenticatorManager: AddTotpItemFromAuthenticatorManager,
|
||||||
private val specialCircumstanceManager: SpecialCircumstanceManager,
|
private val specialCircumstanceManager: SpecialCircumstanceManager,
|
||||||
private val garbageCollectionManager: GarbageCollectionManager,
|
private val garbageCollectionManager: GarbageCollectionManager,
|
||||||
private val fido2CredentialManager: Fido2CredentialManager,
|
private val fido2CredentialManager: Fido2CredentialManager,
|
||||||
private val intentManager: IntentManager,
|
private val intentManager: IntentManager,
|
||||||
private val settingsRepository: SettingsRepository,
|
settingsRepository: SettingsRepository,
|
||||||
private val vaultRepository: VaultRepository,
|
private val vaultRepository: VaultRepository,
|
||||||
private val authRepository: AuthRepository,
|
private val authRepository: AuthRepository,
|
||||||
private val environmentRepository: EnvironmentRepository,
|
private val environmentRepository: EnvironmentRepository,
|
||||||
@@ -85,9 +79,6 @@ class MainViewModel @Inject constructor(
|
|||||||
initialState = MainState(
|
initialState = MainState(
|
||||||
theme = settingsRepository.appTheme,
|
theme = settingsRepository.appTheme,
|
||||||
isScreenCaptureAllowed = settingsRepository.isScreenCaptureAllowed,
|
isScreenCaptureAllowed = settingsRepository.isScreenCaptureAllowed,
|
||||||
isErrorReportingDialogEnabled = featureFlagManager.getFeatureFlag(
|
|
||||||
key = FlagKey.MobileErrorReporting,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
private var specialCircumstance: SpecialCircumstance?
|
private var specialCircumstance: SpecialCircumstance?
|
||||||
@@ -105,12 +96,6 @@ class MainViewModel @Inject constructor(
|
|||||||
.onEach { specialCircumstance = it }
|
.onEach { specialCircumstance = it }
|
||||||
.launchIn(viewModelScope)
|
.launchIn(viewModelScope)
|
||||||
|
|
||||||
featureFlagManager
|
|
||||||
.getFeatureFlagFlow(key = FlagKey.MobileErrorReporting)
|
|
||||||
.map { MainAction.Internal.OnMobileErrorReportingReceive(it) }
|
|
||||||
.onEach(::sendAction)
|
|
||||||
.launchIn(viewModelScope)
|
|
||||||
|
|
||||||
accessibilitySelectionManager
|
accessibilitySelectionManager
|
||||||
.accessibilitySelectionFlow
|
.accessibilitySelectionFlow
|
||||||
.map { MainAction.Internal.AccessibilitySelectionReceive(it) }
|
.map { MainAction.Internal.AccessibilitySelectionReceive(it) }
|
||||||
@@ -149,7 +134,8 @@ class MainViewModel @Inject constructor(
|
|||||||
// Switching between account states often involves some kind of animation (ex:
|
// Switching between account states often involves some kind of animation (ex:
|
||||||
// account switcher) that we might want to give time to finish before triggering
|
// account switcher) that we might want to give time to finish before triggering
|
||||||
// a refresh.
|
// a refresh.
|
||||||
delay(ANIMATION_REFRESH_DELAY)
|
@Suppress("MagicNumber")
|
||||||
|
delay(500)
|
||||||
trySendAction(MainAction.Internal.CurrentUserStateChange)
|
trySendAction(MainAction.Internal.CurrentUserStateChange)
|
||||||
}
|
}
|
||||||
.launchIn(viewModelScope)
|
.launchIn(viewModelScope)
|
||||||
@@ -161,7 +147,8 @@ class MainViewModel @Inject constructor(
|
|||||||
is VaultStateEvent.Locked -> {
|
is VaultStateEvent.Locked -> {
|
||||||
// Similar to account switching, triggering this action too soon can
|
// Similar to account switching, triggering this action too soon can
|
||||||
// interfere with animations or navigation logic, so we will delay slightly.
|
// interfere with animations or navigation logic, so we will delay slightly.
|
||||||
delay(ANIMATION_REFRESH_DELAY)
|
@Suppress("MagicNumber")
|
||||||
|
delay(500)
|
||||||
trySendAction(MainAction.Internal.VaultUnlockStateChange)
|
trySendAction(MainAction.Internal.VaultUnlockStateChange)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,17 +172,6 @@ class MainViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun handleAction(action: MainAction) {
|
override fun handleAction(action: MainAction) {
|
||||||
when (action) {
|
|
||||||
is MainAction.ReceiveFirstIntent -> handleFirstIntentReceived(action)
|
|
||||||
is MainAction.ReceiveNewIntent -> handleNewIntentReceived(action)
|
|
||||||
MainAction.OpenDebugMenu -> handleOpenDebugMenu()
|
|
||||||
is MainAction.ResumeScreenDataReceived -> handleAppResumeDataUpdated(action)
|
|
||||||
is MainAction.AppSpecificLanguageUpdate -> handleAppSpecificLanguageUpdate(action)
|
|
||||||
is MainAction.Internal -> handleInternalAction(action)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleInternalAction(action: MainAction.Internal) {
|
|
||||||
when (action) {
|
when (action) {
|
||||||
is MainAction.Internal.AccessibilitySelectionReceive -> {
|
is MainAction.Internal.AccessibilitySelectionReceive -> {
|
||||||
handleAccessibilitySelectionReceive(action)
|
handleAccessibilitySelectionReceive(action)
|
||||||
@@ -209,24 +185,13 @@ class MainViewModel @Inject constructor(
|
|||||||
is MainAction.Internal.ScreenCaptureUpdate -> handleScreenCaptureUpdate(action)
|
is MainAction.Internal.ScreenCaptureUpdate -> handleScreenCaptureUpdate(action)
|
||||||
is MainAction.Internal.ThemeUpdate -> handleAppThemeUpdated(action)
|
is MainAction.Internal.ThemeUpdate -> handleAppThemeUpdated(action)
|
||||||
is MainAction.Internal.VaultUnlockStateChange -> handleVaultUnlockStateChange()
|
is MainAction.Internal.VaultUnlockStateChange -> handleVaultUnlockStateChange()
|
||||||
is MainAction.Internal.OnMobileErrorReportingReceive -> {
|
is MainAction.ReceiveFirstIntent -> handleFirstIntentReceived(action)
|
||||||
handleOnMobileErrorReportingReceive(action)
|
is MainAction.ReceiveNewIntent -> handleNewIntentReceived(action)
|
||||||
}
|
MainAction.OpenDebugMenu -> handleOpenDebugMenu()
|
||||||
|
is MainAction.ResumeScreenDataReceived -> handleAppResumeDataUpdated(action)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleOnMobileErrorReportingReceive(
|
|
||||||
action: MainAction.Internal.OnMobileErrorReportingReceive,
|
|
||||||
) {
|
|
||||||
mutableStateFlow.update {
|
|
||||||
it.copy(isErrorReportingDialogEnabled = action.isErrorReportingEnabled)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleAppSpecificLanguageUpdate(action: MainAction.AppSpecificLanguageUpdate) {
|
|
||||||
settingsRepository.appLanguage = action.appLanguage
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleAppResumeDataUpdated(action: MainAction.ResumeScreenDataReceived) {
|
private fun handleAppResumeDataUpdated(action: MainAction.ResumeScreenDataReceived) {
|
||||||
when (val data = action.screenResumeData) {
|
when (val data = action.screenResumeData) {
|
||||||
null -> appResumeManager.clearResumeScreen()
|
null -> appResumeManager.clearResumeScreen()
|
||||||
@@ -309,10 +274,10 @@ class MainViewModel @Inject constructor(
|
|||||||
val hasGeneratorShortcut = intent.isPasswordGeneratorShortcut
|
val hasGeneratorShortcut = intent.isPasswordGeneratorShortcut
|
||||||
val hasVaultShortcut = intent.isMyVaultShortcut
|
val hasVaultShortcut = intent.isMyVaultShortcut
|
||||||
val hasAccountSecurityShortcut = intent.isAccountSecurityShortcut
|
val hasAccountSecurityShortcut = intent.isAccountSecurityShortcut
|
||||||
|
val fido2CreateCredentialRequestData = intent.getFido2CreateCredentialRequestOrNull()
|
||||||
val completeRegistrationData = intent.getCompleteRegistrationDataIntentOrNull()
|
val completeRegistrationData = intent.getCompleteRegistrationDataIntentOrNull()
|
||||||
val fido2CreateCredentialRequest = intent.getFido2CreateCredentialRequestOrNull()
|
val fido2CredentialAssertionRequest = intent.getFido2AssertionRequestOrNull()
|
||||||
val fido2GetCredentialsRequest = intent.getFido2GetCredentialsRequestOrNull()
|
val fido2GetCredentialsRequest = intent.getFido2GetCredentialsRequestOrNull()
|
||||||
val fido2AssertCredentialRequest = intent.getFido2AssertionRequestOrNull()
|
|
||||||
when {
|
when {
|
||||||
passwordlessRequestData != null -> {
|
passwordlessRequestData != null -> {
|
||||||
authRepository.activeUserId?.let {
|
authRepository.activeUserId?.let {
|
||||||
@@ -370,39 +335,34 @@ class MainViewModel @Inject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fido2CreateCredentialRequest != null -> {
|
fido2CreateCredentialRequestData != null -> {
|
||||||
// Set the user's verification status when a new FIDO 2 request is received to force
|
// Set the user's verification status when a new FIDO 2 request is received to force
|
||||||
// explicit verification if the user's vault is unlocked when the request is
|
// explicit verification if the user's vault is unlocked when the request is
|
||||||
// received.
|
// received.
|
||||||
fido2CreateCredentialRequest.providerRequest
|
fido2CreateCredentialRequestData.isUserVerified
|
||||||
.biometricPromptResult
|
|
||||||
?.isSuccessful
|
|
||||||
?.let { isVerified -> fido2CredentialManager.isUserVerified = isVerified }
|
?.let { isVerified -> fido2CredentialManager.isUserVerified = isVerified }
|
||||||
|
|
||||||
specialCircumstanceManager.specialCircumstance =
|
specialCircumstanceManager.specialCircumstance =
|
||||||
SpecialCircumstance.Fido2Save(
|
SpecialCircumstance.Fido2Save(
|
||||||
fido2CreateCredentialRequest = fido2CreateCredentialRequest,
|
fido2CreateCredentialRequest = fido2CreateCredentialRequestData,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Switch accounts if the selected user is not the active user.
|
// Switch accounts if the selected user is not the active user.
|
||||||
if (authRepository.activeUserId != null &&
|
if (authRepository.activeUserId != null &&
|
||||||
authRepository.activeUserId != fido2CreateCredentialRequest.userId
|
authRepository.activeUserId != fido2CreateCredentialRequestData.userId
|
||||||
) {
|
) {
|
||||||
authRepository.switchAccount(fido2CreateCredentialRequest.userId)
|
authRepository.switchAccount(fido2CreateCredentialRequestData.userId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fido2AssertCredentialRequest != null -> {
|
fido2CredentialAssertionRequest != null -> {
|
||||||
// If device biometric verification was performed as part of single-tap
|
// If device biometric verification was performed as part of single-tap
|
||||||
// authentication, set the user's verification state to the device result.
|
// authentication, set the user's verification state to the device result.
|
||||||
// Otherwise, retain the verification state as-is.
|
// Otherwise, retain the verification state as-is.
|
||||||
fido2AssertCredentialRequest.providerRequest.biometricPromptResult
|
fido2CredentialAssertionRequest.isUserVerified
|
||||||
?.isSuccessful
|
|
||||||
?.let { isVerified -> fido2CredentialManager.isUserVerified = isVerified }
|
?.let { isVerified -> fido2CredentialManager.isUserVerified = isVerified }
|
||||||
|
|
||||||
specialCircumstanceManager.specialCircumstance =
|
specialCircumstanceManager.specialCircumstance =
|
||||||
SpecialCircumstance.Fido2Assertion(
|
SpecialCircumstance.Fido2Assertion(
|
||||||
fido2AssertionRequest = fido2AssertCredentialRequest,
|
fido2AssertionRequest = fido2CredentialAssertionRequest,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -485,16 +445,7 @@ class MainViewModel @Inject constructor(
|
|||||||
data class MainState(
|
data class MainState(
|
||||||
val theme: AppTheme,
|
val theme: AppTheme,
|
||||||
val isScreenCaptureAllowed: Boolean,
|
val isScreenCaptureAllowed: Boolean,
|
||||||
private val isErrorReportingDialogEnabled: Boolean,
|
) : Parcelable
|
||||||
) : Parcelable {
|
|
||||||
/**
|
|
||||||
* Contains all feature flags that are available to the UI.
|
|
||||||
*/
|
|
||||||
val featureFlagsState: FeatureFlagsState
|
|
||||||
get() = FeatureFlagsState(
|
|
||||||
isErrorReportingDialogEnabled = isErrorReportingDialogEnabled,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Models actions for the [MainActivity].
|
* Models actions for the [MainActivity].
|
||||||
@@ -520,12 +471,6 @@ sealed class MainAction {
|
|||||||
*/
|
*/
|
||||||
data class ResumeScreenDataReceived(val screenResumeData: AppResumeScreenData?) : MainAction()
|
data class ResumeScreenDataReceived(val screenResumeData: AppResumeScreenData?) : MainAction()
|
||||||
|
|
||||||
/**
|
|
||||||
* Receive if there is an app specific locale selection made by user
|
|
||||||
* in the device's settings.
|
|
||||||
*/
|
|
||||||
data class AppSpecificLanguageUpdate(val appLanguage: AppLanguage) : MainAction()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actions for internal use by the ViewModel.
|
* Actions for internal use by the ViewModel.
|
||||||
*/
|
*/
|
||||||
@@ -538,13 +483,6 @@ sealed class MainAction {
|
|||||||
val cipherView: CipherView,
|
val cipherView: CipherView,
|
||||||
) : Internal()
|
) : Internal()
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates the Mobile Error Reporting feature flag has been updated.
|
|
||||||
*/
|
|
||||||
data class OnMobileErrorReportingReceive(
|
|
||||||
val isErrorReportingEnabled: Boolean,
|
|
||||||
) : Internal()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates the user has manually selected the given [cipherView] for autofill.
|
* Indicates the user has manually selected the given [cipherView] for autofill.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
package com.x8bit.bitwarden.data.auth.datasource.disk
|
package com.x8bit.bitwarden.data.auth.datasource.disk
|
||||||
|
|
||||||
import com.bitwarden.network.model.SyncResponseJson
|
|
||||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.AccountTokensJson
|
import com.x8bit.bitwarden.data.auth.datasource.disk.model.AccountTokensJson
|
||||||
|
import com.x8bit.bitwarden.data.auth.datasource.disk.model.NewDeviceNoticeState
|
||||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.OnboardingStatus
|
import com.x8bit.bitwarden.data.auth.datasource.disk.model.OnboardingStatus
|
||||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.PendingAuthRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.disk.model.PendingAuthRequestJson
|
||||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.UserStateJson
|
import com.x8bit.bitwarden.data.auth.datasource.disk.model.UserStateJson
|
||||||
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
@@ -343,6 +344,16 @@ interface AuthDiskSource {
|
|||||||
*/
|
*/
|
||||||
fun getShowImportLoginsFlow(userId: String): Flow<Boolean?>
|
fun getShowImportLoginsFlow(userId: String): Flow<Boolean?>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the new device notice state for the given [userId].
|
||||||
|
*/
|
||||||
|
fun getNewDeviceNoticeState(userId: String): NewDeviceNoticeState
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the new device notice state for the given [userId].
|
||||||
|
*/
|
||||||
|
fun storeNewDeviceNoticeState(userId: String, newState: NewDeviceNoticeState?)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the last lock timestamp for the given [userId].
|
* Gets the last lock timestamp for the given [userId].
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
package com.x8bit.bitwarden.data.auth.datasource.disk
|
package com.x8bit.bitwarden.data.auth.datasource.disk
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
|
|
||||||
import com.bitwarden.core.data.util.decodeFromStringOrNull
|
|
||||||
import com.bitwarden.data.datasource.disk.BaseEncryptedDiskSource
|
|
||||||
import com.bitwarden.network.model.SyncResponseJson
|
|
||||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.AccountTokensJson
|
import com.x8bit.bitwarden.data.auth.datasource.disk.model.AccountTokensJson
|
||||||
|
import com.x8bit.bitwarden.data.auth.datasource.disk.model.NewDeviceNoticeDisplayStatus
|
||||||
|
import com.x8bit.bitwarden.data.auth.datasource.disk.model.NewDeviceNoticeState
|
||||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.OnboardingStatus
|
import com.x8bit.bitwarden.data.auth.datasource.disk.model.OnboardingStatus
|
||||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.PendingAuthRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.disk.model.PendingAuthRequestJson
|
||||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.UserStateJson
|
import com.x8bit.bitwarden.data.auth.datasource.disk.model.UserStateJson
|
||||||
|
import com.x8bit.bitwarden.data.platform.datasource.disk.BaseEncryptedDiskSource
|
||||||
import com.x8bit.bitwarden.data.platform.datasource.disk.legacy.LegacySecureStorageMigrator
|
import com.x8bit.bitwarden.data.platform.datasource.disk.legacy.LegacySecureStorageMigrator
|
||||||
|
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
||||||
|
import com.x8bit.bitwarden.data.platform.util.decodeFromStringOrNull
|
||||||
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.onSubscription
|
import kotlinx.coroutines.flow.onSubscription
|
||||||
@@ -47,6 +49,7 @@ private const val TDE_LOGIN_COMPLETE = "tdeLoginComplete"
|
|||||||
private const val USES_KEY_CONNECTOR = "usesKeyConnector"
|
private const val USES_KEY_CONNECTOR = "usesKeyConnector"
|
||||||
private const val ONBOARDING_STATUS_KEY = "onboardingStatus"
|
private const val ONBOARDING_STATUS_KEY = "onboardingStatus"
|
||||||
private const val SHOW_IMPORT_LOGINS_KEY = "showImportLogins"
|
private const val SHOW_IMPORT_LOGINS_KEY = "showImportLogins"
|
||||||
|
private const val NEW_DEVICE_NOTICE_STATE = "newDeviceNoticeState"
|
||||||
private const val LAST_LOCK_TIMESTAMP = "lastLockTimestamp"
|
private const val LAST_LOCK_TIMESTAMP = "lastLockTimestamp"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -486,6 +489,22 @@ class AuthDiskSourceImpl(
|
|||||||
getMutableShowImportLoginsFlow(userId)
|
getMutableShowImportLoginsFlow(userId)
|
||||||
.onSubscription { emit(getShowImportLogins(userId)) }
|
.onSubscription { emit(getShowImportLogins(userId)) }
|
||||||
|
|
||||||
|
override fun getNewDeviceNoticeState(userId: String): NewDeviceNoticeState {
|
||||||
|
return getString(key = NEW_DEVICE_NOTICE_STATE.appendIdentifier(userId))?.let {
|
||||||
|
json.decodeFromStringOrNull(it)
|
||||||
|
} ?: NewDeviceNoticeState(
|
||||||
|
displayStatus = NewDeviceNoticeDisplayStatus.HAS_NOT_SEEN,
|
||||||
|
lastSeenDate = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun storeNewDeviceNoticeState(userId: String, newState: NewDeviceNoticeState?) {
|
||||||
|
putString(
|
||||||
|
key = NEW_DEVICE_NOTICE_STATE.appendIdentifier(userId),
|
||||||
|
value = newState?.let { json.encodeToString(it) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getLastLockTimestamp(userId: String): Instant? {
|
override fun getLastLockTimestamp(userId: String): Instant? {
|
||||||
return getLong(key = LAST_LOCK_TIMESTAMP.appendIdentifier(userId))?.let {
|
return getLong(key = LAST_LOCK_TIMESTAMP.appendIdentifier(userId))?.let {
|
||||||
Instant.ofEpochMilli(it)
|
Instant.ofEpochMilli(it)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.x8bit.bitwarden.data.auth.datasource.disk.di
|
package com.x8bit.bitwarden.data.auth.datasource.disk.di
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import com.bitwarden.data.datasource.disk.di.EncryptedPreferences
|
|
||||||
import com.bitwarden.data.datasource.disk.di.UnencryptedPreferences
|
|
||||||
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
||||||
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSourceImpl
|
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSourceImpl
|
||||||
|
import com.x8bit.bitwarden.data.platform.datasource.di.EncryptedPreferences
|
||||||
|
import com.x8bit.bitwarden.data.platform.datasource.di.UnencryptedPreferences
|
||||||
import com.x8bit.bitwarden.data.platform.datasource.disk.legacy.LegacySecureStorageMigrator
|
import com.x8bit.bitwarden.data.platform.datasource.disk.legacy.LegacySecureStorageMigrator
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.x8bit.bitwarden.data.auth.datasource.disk.model
|
package com.x8bit.bitwarden.data.auth.datasource.disk.model
|
||||||
|
|
||||||
import com.bitwarden.network.model.KdfTypeJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.KdfTypeJson
|
||||||
import com.bitwarden.network.model.UserDecryptionOptionsJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.UserDecryptionOptionsJson
|
||||||
import kotlinx.serialization.Contextual
|
import kotlinx.serialization.Contextual
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package com.x8bit.bitwarden.data.auth.datasource.disk.model
|
||||||
|
|
||||||
|
import kotlinx.serialization.Contextual
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import java.time.ZonedDateTime
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the current display status of the new device notice screen.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
enum class NewDeviceNoticeDisplayStatus {
|
||||||
|
/**
|
||||||
|
* The user has seen the screen and indicated they can access their email.
|
||||||
|
*/
|
||||||
|
@SerialName("canAccessEmail")
|
||||||
|
CAN_ACCESS_EMAIL,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user has indicated they can access their email
|
||||||
|
* as specified by the Permanent mode of the notice.
|
||||||
|
*/
|
||||||
|
@SerialName("canAccessEmailPermanent")
|
||||||
|
CAN_ACCESS_EMAIL_PERMANENT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user has not seen the screen.
|
||||||
|
*/
|
||||||
|
@SerialName("hasNotSeen")
|
||||||
|
HAS_NOT_SEEN,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user has seen the screen and selected "remind me later".
|
||||||
|
*/
|
||||||
|
@SerialName("hasSeen")
|
||||||
|
HAS_SEEN,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The state of the new device notice screen.
|
||||||
|
*/
|
||||||
|
@Suppress("MagicNumber")
|
||||||
|
@Serializable
|
||||||
|
data class NewDeviceNoticeState(
|
||||||
|
@SerialName("displayStatus")
|
||||||
|
val displayStatus: NewDeviceNoticeDisplayStatus,
|
||||||
|
|
||||||
|
@SerialName("lastSeenDate")
|
||||||
|
@Contextual
|
||||||
|
val lastSeenDate: ZonedDateTime?,
|
||||||
|
) {
|
||||||
|
/**
|
||||||
|
* Whether the [lastSeenDate] is at least 7 days old.
|
||||||
|
*/
|
||||||
|
val shouldDisplayNoticeIfSeen = lastSeenDate
|
||||||
|
?.isBefore(
|
||||||
|
ZonedDateTime.now().minusDays(7),
|
||||||
|
)
|
||||||
|
?: false
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package com.bitwarden.network.api
|
package com.x8bit.bitwarden.data.auth.datasource.network.api
|
||||||
|
|
||||||
import com.bitwarden.network.model.CreateAccountKeysRequest
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.CreateAccountKeysRequest
|
||||||
import com.bitwarden.network.model.DeleteAccountRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.DeleteAccountRequestJson
|
||||||
import com.bitwarden.network.model.NetworkResult
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.ResetPasswordRequestJson
|
||||||
import com.bitwarden.network.model.ResetPasswordRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.SetPasswordRequestJson
|
||||||
import com.bitwarden.network.model.SetPasswordRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.VerifyOtpRequestJson
|
||||||
import com.bitwarden.network.model.VerifyOtpRequestJson
|
import com.x8bit.bitwarden.data.platform.datasource.network.model.NetworkResult
|
||||||
import retrofit2.http.Body
|
import retrofit2.http.Body
|
||||||
import retrofit2.http.HTTP
|
import retrofit2.http.HTTP
|
||||||
import retrofit2.http.POST
|
import retrofit2.http.POST
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package com.bitwarden.network.api
|
package com.x8bit.bitwarden.data.auth.datasource.network.api
|
||||||
|
|
||||||
import com.bitwarden.network.model.AuthRequestRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.AuthRequestRequestJson
|
||||||
import com.bitwarden.network.model.AuthRequestUpdateRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.AuthRequestUpdateRequestJson
|
||||||
import com.bitwarden.network.model.AuthRequestsResponseJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.AuthRequestsResponseJson
|
||||||
import com.bitwarden.network.model.NetworkResult
|
import com.x8bit.bitwarden.data.platform.datasource.network.model.NetworkResult
|
||||||
import retrofit2.http.Body
|
import retrofit2.http.Body
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.Header
|
import retrofit2.http.Header
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package com.bitwarden.network.api
|
package com.x8bit.bitwarden.data.auth.datasource.network.api
|
||||||
|
|
||||||
import androidx.annotation.Keep
|
import androidx.annotation.Keep
|
||||||
import com.bitwarden.network.model.NetworkResult
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.TrustedDeviceKeysRequestJson
|
||||||
import com.bitwarden.network.model.TrustedDeviceKeysRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.TrustedDeviceKeysResponseJson
|
||||||
import com.bitwarden.network.model.TrustedDeviceKeysResponseJson
|
import com.x8bit.bitwarden.data.platform.datasource.network.model.NetworkResult
|
||||||
import retrofit2.http.Body
|
import retrofit2.http.Body
|
||||||
import retrofit2.http.PUT
|
import retrofit2.http.PUT
|
||||||
import retrofit2.http.Path
|
import retrofit2.http.Path
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.bitwarden.network.api
|
package com.x8bit.bitwarden.data.auth.datasource.network.api
|
||||||
|
|
||||||
import androidx.annotation.Keep
|
import androidx.annotation.Keep
|
||||||
import com.bitwarden.network.model.KeyConnectorMasterKeyRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorMasterKeyRequestJson
|
||||||
import com.bitwarden.network.model.NetworkResult
|
import com.x8bit.bitwarden.data.platform.datasource.network.model.NetworkResult
|
||||||
import retrofit2.http.Body
|
import retrofit2.http.Body
|
||||||
import retrofit2.http.POST
|
import retrofit2.http.POST
|
||||||
import retrofit2.http.Url
|
import retrofit2.http.Url
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package com.bitwarden.network.api
|
package com.x8bit.bitwarden.data.auth.datasource.network.api
|
||||||
|
|
||||||
import com.bitwarden.network.model.NetworkResult
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.OrganizationAutoEnrollStatusResponseJson
|
||||||
import com.bitwarden.network.model.OrganizationAutoEnrollStatusResponseJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.OrganizationKeysResponseJson
|
||||||
import com.bitwarden.network.model.OrganizationKeysResponseJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.OrganizationResetPasswordEnrollRequestJson
|
||||||
import com.bitwarden.network.model.OrganizationResetPasswordEnrollRequestJson
|
import com.x8bit.bitwarden.data.platform.datasource.network.model.NetworkResult
|
||||||
import retrofit2.http.Body
|
import retrofit2.http.Body
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.PUT
|
import retrofit2.http.PUT
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.bitwarden.network.api
|
package com.x8bit.bitwarden.data.auth.datasource.network.api
|
||||||
|
|
||||||
import com.bitwarden.network.model.NetworkResult
|
import com.x8bit.bitwarden.data.platform.datasource.network.model.NetworkResult
|
||||||
import okhttp3.ResponseBody
|
import okhttp3.ResponseBody
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.Path
|
import retrofit2.http.Path
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package com.bitwarden.network.api
|
package com.x8bit.bitwarden.data.auth.datasource.network.api
|
||||||
|
|
||||||
import com.bitwarden.network.model.KeyConnectorKeyRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorKeyRequestJson
|
||||||
import com.bitwarden.network.model.NetworkResult
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.PasswordHintRequestJson
|
||||||
import com.bitwarden.network.model.PasswordHintRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.ResendEmailRequestJson
|
||||||
import com.bitwarden.network.model.ResendEmailRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.ResendNewDeviceOtpRequestJson
|
||||||
import com.bitwarden.network.model.ResendNewDeviceOtpRequestJson
|
import com.x8bit.bitwarden.data.platform.datasource.network.model.NetworkResult
|
||||||
import com.bitwarden.network.util.HEADER_KEY_AUTHORIZATION
|
import com.x8bit.bitwarden.data.platform.datasource.network.util.HEADER_KEY_AUTHORIZATION
|
||||||
import retrofit2.http.Body
|
import retrofit2.http.Body
|
||||||
import retrofit2.http.Header
|
import retrofit2.http.Header
|
||||||
import retrofit2.http.POST
|
import retrofit2.http.POST
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.bitwarden.network.api
|
package com.x8bit.bitwarden.data.auth.datasource.network.api
|
||||||
|
|
||||||
import com.bitwarden.network.model.AuthRequestRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.AuthRequestRequestJson
|
||||||
import com.bitwarden.network.model.AuthRequestsResponseJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.AuthRequestsResponseJson
|
||||||
import com.bitwarden.network.model.NetworkResult
|
import com.x8bit.bitwarden.data.platform.datasource.network.model.NetworkResult
|
||||||
import retrofit2.http.Body
|
import retrofit2.http.Body
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.Header
|
import retrofit2.http.Header
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.bitwarden.network.api
|
package com.x8bit.bitwarden.data.auth.datasource.network.api
|
||||||
|
|
||||||
import com.bitwarden.network.model.NetworkResult
|
import com.x8bit.bitwarden.data.platform.datasource.network.model.NetworkResult
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.Header
|
import retrofit2.http.Header
|
||||||
|
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
package com.bitwarden.network.api
|
package com.x8bit.bitwarden.data.auth.datasource.network.api
|
||||||
|
|
||||||
import com.bitwarden.network.model.GetTokenResponseJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.GetTokenResponseJson
|
||||||
import com.bitwarden.network.model.NetworkResult
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.PreLoginRequestJson
|
||||||
import com.bitwarden.network.model.PreLoginRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.PreLoginResponseJson
|
||||||
import com.bitwarden.network.model.PreLoginResponseJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.PrevalidateSsoResponseJson
|
||||||
import com.bitwarden.network.model.PrevalidateSsoResponseJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.RefreshTokenResponseJson
|
||||||
import com.bitwarden.network.model.RefreshTokenResponseJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterFinishRequestJson
|
||||||
import com.bitwarden.network.model.RegisterFinishRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterRequestJson
|
||||||
import com.bitwarden.network.model.RegisterRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterResponseJson
|
||||||
import com.bitwarden.network.model.RegisterResponseJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.SendVerificationEmailRequestJson
|
||||||
import com.bitwarden.network.model.SendVerificationEmailRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.VerifyEmailTokenRequestJson
|
||||||
import com.bitwarden.network.model.VerifyEmailTokenRequestJson
|
import com.x8bit.bitwarden.data.platform.datasource.network.model.NetworkResult
|
||||||
import kotlinx.serialization.json.JsonPrimitive
|
import kotlinx.serialization.json.JsonPrimitive
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.http.Body
|
import retrofit2.http.Body
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.bitwarden.network.api
|
package com.x8bit.bitwarden.data.auth.datasource.network.api
|
||||||
|
|
||||||
import androidx.annotation.Keep
|
import androidx.annotation.Keep
|
||||||
import com.bitwarden.network.model.KeyConnectorMasterKeyRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorMasterKeyRequestJson
|
||||||
import com.bitwarden.network.model.KeyConnectorMasterKeyResponseJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorMasterKeyResponseJson
|
||||||
import com.bitwarden.network.model.NetworkResult
|
import com.x8bit.bitwarden.data.platform.datasource.network.model.NetworkResult
|
||||||
import com.bitwarden.network.util.HEADER_KEY_AUTHORIZATION
|
import com.x8bit.bitwarden.data.platform.datasource.network.util.HEADER_KEY_AUTHORIZATION
|
||||||
import retrofit2.http.Body
|
import retrofit2.http.Body
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.Header
|
import retrofit2.http.Header
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.bitwarden.network.api
|
package com.x8bit.bitwarden.data.auth.datasource.network.api
|
||||||
|
|
||||||
import com.bitwarden.network.model.NetworkResult
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.OrganizationDomainSsoDetailsRequestJson
|
||||||
import com.bitwarden.network.model.OrganizationDomainSsoDetailsRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.OrganizationDomainSsoDetailsResponseJson
|
||||||
import com.bitwarden.network.model.OrganizationDomainSsoDetailsResponseJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.VerifiedOrganizationDomainSsoDetailsRequest
|
||||||
import com.bitwarden.network.model.VerifiedOrganizationDomainSsoDetailsRequest
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.VerifiedOrganizationDomainSsoDetailsResponse
|
||||||
import com.bitwarden.network.model.VerifiedOrganizationDomainSsoDetailsResponse
|
import com.x8bit.bitwarden.data.platform.datasource.network.model.NetworkResult
|
||||||
import retrofit2.http.Body
|
import retrofit2.http.Body
|
||||||
import retrofit2.http.POST
|
import retrofit2.http.POST
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ interface UnauthenticatedOrganizationApi {
|
|||||||
): NetworkResult<OrganizationDomainSsoDetailsResponseJson>
|
): NetworkResult<OrganizationDomainSsoDetailsResponseJson>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for the verified organization domains of an email for SSO purposes.
|
* Checks for the verfied organization domains of an email for SSO purposes.
|
||||||
*/
|
*/
|
||||||
@POST("/organizations/domain/sso/verified")
|
@POST("/organizations/domain/sso/verified")
|
||||||
suspend fun getVerifiedOrganizationDomainsByEmail(
|
suspend fun getVerifiedOrganizationDomainsByEmail(
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
package com.x8bit.bitwarden.data.auth.datasource.network.di
|
package com.x8bit.bitwarden.data.auth.datasource.network.di
|
||||||
|
|
||||||
import com.bitwarden.network.service.AccountsService
|
import com.x8bit.bitwarden.data.auth.datasource.network.service.AccountsService
|
||||||
import com.bitwarden.network.service.AccountsServiceImpl
|
import com.x8bit.bitwarden.data.auth.datasource.network.service.AccountsServiceImpl
|
||||||
import com.bitwarden.network.service.AuthRequestsService
|
import com.x8bit.bitwarden.data.auth.datasource.network.service.AuthRequestsService
|
||||||
import com.bitwarden.network.service.AuthRequestsServiceImpl
|
import com.x8bit.bitwarden.data.auth.datasource.network.service.AuthRequestsServiceImpl
|
||||||
import com.bitwarden.network.service.DevicesService
|
import com.x8bit.bitwarden.data.auth.datasource.network.service.DevicesService
|
||||||
import com.bitwarden.network.service.DevicesServiceImpl
|
import com.x8bit.bitwarden.data.auth.datasource.network.service.DevicesServiceImpl
|
||||||
import com.bitwarden.network.service.HaveIBeenPwnedService
|
import com.x8bit.bitwarden.data.auth.datasource.network.service.HaveIBeenPwnedService
|
||||||
import com.bitwarden.network.service.HaveIBeenPwnedServiceImpl
|
import com.x8bit.bitwarden.data.auth.datasource.network.service.HaveIBeenPwnedServiceImpl
|
||||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.IdentityService
|
import com.x8bit.bitwarden.data.auth.datasource.network.service.IdentityService
|
||||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.IdentityServiceImpl
|
import com.x8bit.bitwarden.data.auth.datasource.network.service.IdentityServiceImpl
|
||||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.NewAuthRequestService
|
import com.x8bit.bitwarden.data.auth.datasource.network.service.NewAuthRequestService
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import androidx.annotation.Keep
|
import androidx.annotation.Keep
|
||||||
import com.bitwarden.core.data.serializer.BaseEnumeratedIntSerializer
|
import com.x8bit.bitwarden.data.platform.datasource.network.serializer.BaseEnumeratedIntSerializer
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.Contextual
|
import kotlinx.serialization.Contextual
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -23,15 +23,6 @@ sealed class DeleteAccountResponseJson {
|
|||||||
@Serializable
|
@Serializable
|
||||||
data class Invalid(
|
data class Invalid(
|
||||||
@SerialName("validationErrors")
|
@SerialName("validationErrors")
|
||||||
private val validationErrors: Map<String, List<String?>>?,
|
val validationErrors: Map<String, List<String?>>?,
|
||||||
) : DeleteAccountResponseJson() {
|
) : DeleteAccountResponseJson()
|
||||||
/**
|
|
||||||
* A human readable error message.
|
|
||||||
*/
|
|
||||||
val message: String?
|
|
||||||
get() = validationErrors
|
|
||||||
?.values
|
|
||||||
?.firstOrNull()
|
|
||||||
?.firstOrNull()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import androidx.annotation.Keep
|
import androidx.annotation.Keep
|
||||||
import com.bitwarden.core.data.serializer.BaseEnumeratedIntSerializer
|
import com.x8bit.bitwarden.data.platform.datasource.network.serializer.BaseEnumeratedIntSerializer
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.Contextual
|
import kotlinx.serialization.Contextual
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import com.bitwarden.network.serializer.BaseSurrogateSerializer
|
import com.x8bit.bitwarden.data.platform.datasource.network.serializer.BaseSurrogateSerializer
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterFinishRequestJson.Keys
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterRequestJson.Keys
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.JsonNames
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The response body for sending a verification email.
|
* The response body for sending a verification email.
|
||||||
@@ -28,24 +26,20 @@ sealed class SendVerificationEmailResponseJson {
|
|||||||
* The values in the array should be used for display to the user, since the keys tend to come
|
* The values in the array should be used for display to the user, since the keys tend to come
|
||||||
* back as nonsense. (eg: empty string key)
|
* back as nonsense. (eg: empty string key)
|
||||||
*/
|
*/
|
||||||
@OptIn(ExperimentalSerializationApi::class)
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Invalid(
|
data class Invalid(
|
||||||
@JsonNames("message")
|
@SerialName("message")
|
||||||
|
private val invalidMessage: String? = null,
|
||||||
|
|
||||||
@SerialName("Message")
|
@SerialName("Message")
|
||||||
private val errorMessage: String? = null,
|
private val errorMessage: String? = null,
|
||||||
|
|
||||||
@SerialName("validationErrors")
|
@SerialName("validationErrors")
|
||||||
private val validationErrors: Map<String, List<String>>?,
|
val validationErrors: Map<String, List<String>>?,
|
||||||
) : SendVerificationEmailResponseJson() {
|
) : SendVerificationEmailResponseJson() {
|
||||||
/**
|
/**
|
||||||
* A generic error message.
|
* A generic error message.
|
||||||
*/
|
*/
|
||||||
val message: String?
|
val message: String? get() = invalidMessage ?: errorMessage
|
||||||
get() = validationErrors
|
|
||||||
?.values
|
|
||||||
?.firstOrNull()
|
|
||||||
?.firstOrNull()
|
|
||||||
?: errorMessage
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import com.bitwarden.network.model.RegisterRequestJson.Keys
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterRequestJson.Keys
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.Contextual
|
import kotlinx.serialization.Contextual
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import androidx.annotation.Keep
|
import androidx.annotation.Keep
|
||||||
import com.bitwarden.core.data.serializer.BaseEnumeratedIntSerializer
|
import com.x8bit.bitwarden.data.platform.datasource.network.serializer.BaseEnumeratedIntSerializer
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.bitwarden.network.model
|
package com.x8bit.bitwarden.data.auth.datasource.network.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
package com.bitwarden.network.service
|
package com.x8bit.bitwarden.data.auth.datasource.network.service
|
||||||
|
|
||||||
import com.bitwarden.network.model.DeleteAccountResponseJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.DeleteAccountResponseJson
|
||||||
import com.bitwarden.network.model.KeyConnectorKeyRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorKeyRequestJson
|
||||||
import com.bitwarden.network.model.KeyConnectorMasterKeyResponseJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorMasterKeyResponseJson
|
||||||
import com.bitwarden.network.model.PasswordHintResponseJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.PasswordHintResponseJson
|
||||||
import com.bitwarden.network.model.ResendEmailRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.ResendEmailRequestJson
|
||||||
import com.bitwarden.network.model.ResendNewDeviceOtpRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.ResendNewDeviceOtpRequestJson
|
||||||
import com.bitwarden.network.model.ResetPasswordRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.ResetPasswordRequestJson
|
||||||
import com.bitwarden.network.model.SetPasswordRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.SetPasswordRequestJson
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides an API for querying accounts endpoints.
|
* Provides an API for querying accounts endpoints.
|
||||||
@@ -1,27 +1,27 @@
|
|||||||
package com.bitwarden.network.service
|
package com.x8bit.bitwarden.data.auth.datasource.network.service
|
||||||
|
|
||||||
import com.bitwarden.network.api.AuthenticatedAccountsApi
|
import com.x8bit.bitwarden.data.auth.datasource.network.api.AuthenticatedAccountsApi
|
||||||
import com.bitwarden.network.api.AuthenticatedKeyConnectorApi
|
import com.x8bit.bitwarden.data.auth.datasource.network.api.AuthenticatedKeyConnectorApi
|
||||||
import com.bitwarden.network.api.UnauthenticatedAccountsApi
|
import com.x8bit.bitwarden.data.auth.datasource.network.api.UnauthenticatedAccountsApi
|
||||||
import com.bitwarden.network.api.UnauthenticatedKeyConnectorApi
|
import com.x8bit.bitwarden.data.auth.datasource.network.api.UnauthenticatedKeyConnectorApi
|
||||||
import com.bitwarden.network.model.CreateAccountKeysRequest
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.CreateAccountKeysRequest
|
||||||
import com.bitwarden.network.model.DeleteAccountRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.DeleteAccountRequestJson
|
||||||
import com.bitwarden.network.model.DeleteAccountResponseJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.DeleteAccountResponseJson
|
||||||
import com.bitwarden.network.model.KeyConnectorKeyRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorKeyRequestJson
|
||||||
import com.bitwarden.network.model.KeyConnectorMasterKeyRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorMasterKeyRequestJson
|
||||||
import com.bitwarden.network.model.KeyConnectorMasterKeyResponseJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorMasterKeyResponseJson
|
||||||
import com.bitwarden.network.model.PasswordHintRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.PasswordHintRequestJson
|
||||||
import com.bitwarden.network.model.PasswordHintResponseJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.PasswordHintResponseJson
|
||||||
import com.bitwarden.network.model.ResendEmailRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.ResendEmailRequestJson
|
||||||
import com.bitwarden.network.model.ResendNewDeviceOtpRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.ResendNewDeviceOtpRequestJson
|
||||||
import com.bitwarden.network.model.ResetPasswordRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.ResetPasswordRequestJson
|
||||||
import com.bitwarden.network.model.SetPasswordRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.SetPasswordRequestJson
|
||||||
import com.bitwarden.network.model.VerifyOtpRequestJson
|
import com.x8bit.bitwarden.data.auth.datasource.network.model.VerifyOtpRequestJson
|
||||||
import com.bitwarden.network.model.toBitwardenError
|
import com.x8bit.bitwarden.data.platform.datasource.network.model.toBitwardenError
|
||||||
import com.bitwarden.network.util.HEADER_VALUE_BEARER_PREFIX
|
import com.x8bit.bitwarden.data.platform.datasource.network.util.HEADER_VALUE_BEARER_PREFIX
|
||||||
import com.bitwarden.network.util.NetworkErrorCode
|
import com.x8bit.bitwarden.data.platform.datasource.network.util.NetworkErrorCode
|
||||||
import com.bitwarden.network.util.parseErrorBodyOrNull
|
import com.x8bit.bitwarden.data.platform.datasource.network.util.parseErrorBodyOrNull
|
||||||
import com.bitwarden.network.util.toResult
|
import com.x8bit.bitwarden.data.platform.datasource.network.util.toResult
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user