| 
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -96,7 +96,7 @@ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    <!-- Registration notice --> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    <!-- We won't show any loading indicator because it usually doesn't change anything. We'll just pop the message in only if we discover that they need it. --> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    <div | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      v-if="!loadingLimits && !limits?.nextWeekBeginDateTime" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      v-if="!loadingLimits && !endorserLimits?.nextWeekBeginDateTime" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      class="bg-amber-200 text-amber-900 border-amber-500 border-dashed border text-center rounded-md overflow-hidden px-4 py-3 mb-4" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    > | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      <p class="mb-4"> | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -157,28 +157,39 @@ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      <div> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        {{ limitsMessage }} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      </div> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      <div v-if="!!limits?.nextWeekBeginDateTime"> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        <p class="mb-3 text-sm"> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          You have done <b>{{ limits.doneClaimsThisWeek }}</b> claims out of | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          <b>{{ limits.maxClaimsPerWeek }}</b> for this week. Your claims | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          counter resets at | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      <div v-if="!!endorserLimits?.nextWeekBeginDateTime"> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        <p class="text-sm"> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          You have done | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          <b>{{ endorserLimits.doneClaimsThisWeek }} claims</b> out of | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          <b>{{ endorserLimits.maxClaimsPerWeek }}</b> for this week. Your | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          claims counter resets at | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          <b class="whitespace-nowrap">{{ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            readableTime(limits.nextWeekBeginDateTime) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            readableDate(endorserLimits.nextWeekBeginDateTime) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          }}</b> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        </p> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        <p class="text-sm"> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        <p class="mt-3 text-sm"> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          You have done | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          <b>{{ limits.doneRegistrationsThisMonth }}</b> registrations out of | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          <b>{{ limits.maxRegistrationsPerMonth }}</b> for this month. | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          <b>{{ endorserLimits.doneRegistrationsThisMonth }} registrations</b> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          out of <b>{{ endorserLimits.maxRegistrationsPerMonth }}</b> for this | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          month. | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          <i | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            >(You can register nobody on your first day, and after that only one | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            a day in your first month.)</i | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          > | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          Your registration counter resets at | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          <b class="whitespace-nowrap"> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            {{ readableTime(limits.nextMonthBeginDateTime) }} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            {{ readableDate(endorserLimits.nextMonthBeginDateTime) }} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          </b> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        </p> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        <p class="mt-3 text-sm" v-if="!!imageLimits"> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          You have uploaded | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          <b>{{ imageLimits?.doneImagesThisWeek }} images</b> out of | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          <b>{{ imageLimits?.maxImagesPerWeek }}</b> for this week. Your image | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          counter resets at | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          <b class="whitespace-nowrap">{{ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            readableDate(imageLimits?.nextWeekBeginDateTime) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          }}</b> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        </p> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      </div> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      <button | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        class="block float-right w-fit text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mt-2" | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -509,6 +520,7 @@ import QuickNav from "@/components/QuickNav.vue"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import TopMessage from "@/components/TopMessage.vue"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  AppString, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  DEFAULT_IMAGE_API_SERVER, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  DEFAULT_PUSH_SERVER, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  NotificationIface, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} from "@/constants/app"; | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -516,7 +528,11 @@ import { db, accountsDB } from "@/db/index"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { accessToken } from "@/libs/crypto"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { IIdentifier } from "@veramo/core"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { ErrorResponse, RateLimits } from "@/libs/endorserServer"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  ErrorResponse, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  EndorserRateLimits, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  ImageRateLimits, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} from "@/libs/endorserServer"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// eslint-disable-next-line @typescript-eslint/no-var-requires | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					const Buffer = require("buffer/").Buffer; | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -542,7 +558,9 @@ export default class AccountViewView extends Vue { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  apiServerInput = ""; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  derivationPath = ""; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  downloadUrl = ""; // because DuckDuckGo doesn't download on automated call to "click" on the anchor | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  endorserLimits: EndorserRateLimits | null = null; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  givenName = ""; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  imageLimits: ImageRateLimits | null = null; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  isRegistered = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  isSubscribed = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  notificationMaybeChanged = false; | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -550,7 +568,6 @@ export default class AccountViewView extends Vue { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  publicBase64 = ""; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  webPushServer = ""; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  webPushServerInput = ""; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  limits: RateLimits | null = null; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  limitsMessage = ""; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  loadingLimits = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  showContactGives = false; | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -697,7 +714,7 @@ export default class AccountViewView extends Vue { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    this.updateShowShortcutBvc(this.showShortcutBvc); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  readableTime(timeStr: string) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  readableDate(timeStr: string) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    return timeStr.substring(0, timeStr.indexOf("T")); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -1038,11 +1055,11 @@ export default class AccountViewView extends Vue { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    this.limitsMessage = ""; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    try { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      const resp = await this.fetchRateLimits(identity); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      const resp = await this.fetchEndorserRateLimits(identity); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      if (resp.status === 200) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        this.limits = resp.data; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        this.endorserLimits = resp.data; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        if (!this.isRegistered) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          // the user is not known to be registered, but they are so let's record it | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          // the user was not known to be registered, but now they are (because we got no error) so let's record it | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          try { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            await db.open(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            db.settings.update(MASTER_SETTINGS_KEY, { | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -1062,6 +1079,10 @@ export default class AccountViewView extends Vue { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        const imageResp = await this.fetchImageRateLimits(identity); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        if (imageResp.status === 200) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          this.imageLimits = imageResp.data; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } catch (error) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      this.handleRateLimitsError(error); | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -1082,17 +1103,29 @@ export default class AccountViewView extends Vue { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  /** | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					   * Fetches rate limits from the server. | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					   * Fetches rate limits from the Endorser server. | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					   * | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					   * @param {IIdentifier} identity - The identity object to check rate limits for. | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					   * @returns {Promise<AxiosResponse>} The Axios response object. | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					   */ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  private async fetchRateLimits(identity: IIdentifier) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  private async fetchEndorserRateLimits(identity: IIdentifier) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const url = `${this.apiServer}/api/report/rateLimits`; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const headers = await this.getHeaders(identity); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    return await this.axios.get(url, { headers } as AxiosRequestConfig); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  /** | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					   * Fetches rate limits from the image server. | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					   * | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					   * @param {IIdentifier} identity - The identity object to check rate limits for. | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					   * @returns {Promise<AxiosResponse>} The Axios response object. | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					   */ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  private async fetchImageRateLimits(identity: IIdentifier) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const url = DEFAULT_IMAGE_API_SERVER + "/image-limits"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const headers = await this.getHeaders(identity); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    return await this.axios.get(url, { headers } as AxiosRequestConfig); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  /** | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					   * Handles errors that occur while fetching rate limits. | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					   * | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
				 | 
				
					
  |