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

gitify-app / gitify / 13088720956

01 Feb 2025 12:44PM UTC coverage: 87.392% (-0.4%) from 87.75%
13088720956

Pull #1800

github

web-flow
Merge 679f2ef7e into b310a4098
Pull Request #1800: feat: encrypt tokens using safe storage api

639 of 713 branches covered (89.62%)

Branch coverage included in aggregate %.

12 of 26 new or added lines in 5 files covered. (46.15%)

3 existing lines in 2 files now uncovered.

1697 of 1960 relevant lines covered (86.58%)

25.08 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
  try {
190✔
50
    apiToken = (await decryptValue(token)) as Token;
190✔
51
  } catch (err) {
NEW
52
    logWarn('apiRequestAuth', 'Token is not yet encrypted');
×
53
  }
54

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

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

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

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

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

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

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

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

87
    throw err;
8✔
88
  }
89

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

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

105
  switch (parsedUrl.pathname) {
190✔
106
    case '/notifications':
107
    case '/api/v3/notifications':
108
      return true;
24✔
109
    default:
110
      return false;
166✔
111
  }
112
}
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