• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gitify-app / gitify / 13089077170

01 Feb 2025 01:26PM UTC coverage: 87.364% (-0.3%) from 87.618%
13089077170

push

github

web-flow
feat: encrypt tokens using safe storage api (#1800)

* feat: encrypt token on disk using safe storage api

Signed-off-by: Adam Setch <adam.setch@outlook.com>

* feat: encrypt token on disk using safe storage api

Signed-off-by: Adam Setch <adam.setch@outlook.com>

* feat: encrypt token on disk using safe storage api

Signed-off-by: Adam Setch <adam.setch@outlook.com>

* feat: encrypt token on disk using safe storage api

Signed-off-by: Adam Setch <adam.setch@outlook.com>

---------

Signed-off-by: Adam Setch <adam.setch@outlook.com>

639 of 716 branches covered (89.25%)

Branch coverage included in aggregate %.

12 of 22 new or added lines in 5 files covered. (54.55%)

1 existing line in 1 file now uncovered.

1698 of 1959 relevant lines covered (86.68%)

25.09 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.04
/src/renderer/utils/api/request.ts
1
import axios, {
76✔
2
  type AxiosResponse,
3
  type AxiosPromise,
4
  type Method,
5
} from 'axios';
6

7
import { logError, logWarn } from '../../../shared/logger';
76✔
8
import type { Link, Token } from '../../types';
9
import { decryptValue } from '../comms';
76✔
10
import { getNextURLFromLinkHeader } from './utils';
76✔
11

12
/**
13
 * Perform an unauthenticated API request
14
 *
15
 * @param url
16
 * @param method
17
 * @param data
18
 * @returns
19
 */
20
export function apiRequest(
76✔
21
  url: Link,
22
  method: Method,
23
  data = {},
1✔
24
): AxiosPromise | null {
25
  axios.defaults.headers.common.Accept = 'application/json';
4✔
26
  axios.defaults.headers.common['Content-Type'] = 'application/json';
4✔
27
  axios.defaults.headers.common['Cache-Control'] = 'no-cache';
4✔
28
  return axios({ method, url, data });
4✔
29
}
30

31
/**
32
 * Perform an authenticated API request
33
 *
34
 * @param url
35
 * @param method
36
 * @param token
37
 * @param data
38
 * @param fetchAllRecords whether to fetch all records or just the first page
39
 * @returns
40
 */
41
export async function apiRequestAuth(
76✔
42
  url: Link,
43
  method: Method,
44
  token: Token,
45
  data = {},
63✔
46
  fetchAllRecords = false,
86✔
47
): AxiosPromise | null {
48
  let apiToken = token;
190✔
49
  // TODO - Remove this try-catch block in a future release
50
  try {
190✔
51
    apiToken = (await decryptValue(token)) as Token;
190✔
52
  } catch (err) {
NEW
53
    logWarn('apiRequestAuth', 'Token is not yet encrypted');
×
54
  }
55

56
  axios.defaults.headers.common.Accept = 'application/json';
190✔
57
  axios.defaults.headers.common.Authorization = `token ${apiToken}`;
190✔
58
  axios.defaults.headers.common['Content-Type'] = 'application/json';
190✔
59
  axios.defaults.headers.common['Cache-Control'] = shouldRequestWithNoCache(url)
190✔
60
    ? 'no-cache'
61
    : '';
62

63
  if (!fetchAllRecords) {
190✔
64
    return axios({ method, url, data });
174✔
65
  }
66

67
  let response: AxiosResponse | null = null;
16✔
68
  let combinedData = [];
16✔
69

70
  try {
16✔
71
    let nextUrl: string | null = url;
16✔
72

73
    while (nextUrl) {
16✔
74
      response = await axios({ method, url: nextUrl, data });
16✔
75

76
      // If no data is returned, break the loop
77
      if (!response?.data) {
8✔
78
        break;
2✔
79
      }
80

81
      combinedData = combinedData.concat(response.data); // Accumulate data
6✔
82

83
      nextUrl = getNextURLFromLinkHeader(response);
6✔
84
    }
85
  } catch (err) {
86
    logError('apiRequestAuth', 'API request failed:', err);
8✔
87

88
    throw err;
8✔
89
  }
90

91
  return {
8✔
92
    ...response,
93
    data: combinedData,
94
  } as AxiosResponse;
95
}
96

97
/**
98
 * Return true if the request should be made with no-cache
99
 *
100
 * @param url
101
 * @returns boolean
102
 */
103
function shouldRequestWithNoCache(url: string) {
104
  const parsedUrl = new URL(url);
190✔
105

106
  switch (parsedUrl.pathname) {
190✔
107
    case '/notifications':
108
    case '/api/v3/notifications':
109
      return true;
24✔
110
    default:
111
      return false;
166✔
112
  }
113
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc